NAME

Math::String - Arbitrary sized integers having arbitrary charsets to calculate with key rooms

SYNOPSIS

use Math::String;
use Math::String::Charset;

$a = new Math::String 'cafebabe';   # default a-z
$b = new Math::String 'deadbeef';   # a-z
print $a + $b;                      # Math::String ""

$a = new Math::String 'aa';         # default a-z
$b = $a;
$b++;
print "$b > $a" if ($b > $a);       # prove that ++ makes it greater
$b--;
print "$b == $a" if ($b == $a);     # and that ++ and -- are reverse

$d = Math::String->bzero( ['0'...'9'] );    # like Math::Bigint
$d += Math::String->new ( '9999', [ '0'..'9' ] );
                                    # Math::String "9999"

print "$d\n";                       # string       "00000\n"
print $d->as_number(),"\n";         # Math::BigInt "+11111"
print $d->last(5),"\n";             # string       "99999"
print $d->first(3),"\n";            # string       "111"
print $d->length(),"\n";            # faster than length("$d");

$d = Math::String->new ( '', Math::String::Charset->new ( {
  minlen => 2, start => [ 'a'..'z' ], } );

print $d->minlen(),"\n";            # print 2
print ++$d,"\n";                    # print 'aa'

REQUIRES

perl5.005, Exporter, Math::BigInt, Math::String::Charset

EXPORTS

Exports nothing on default, but can export as_number(), string(), first(), digits(), from_number, bzero() and last().

DESCRIPTION

This module lets you calculate with strings (specifically passwords, but not limited to) as if they were big integers. The strings can have arbitrary length and charsets. Please see Math::String::Charset for full documentation on possible character sets.

You can thus quickly determine the number of passwords for brute force attacks, divide key spaces etc.

INTERNAL DETAILS

Uses internally Math::BigInt to do the math, all with overloaded operators. For the character sets, Math::String::Charset is used.

Actually, the 'numbers' created by this module are NOT equal to plain numbers. It works more than a counting sequence. Oh, well, example coming:

Imagine a charset from a-z (26 letters). The number 0 is defined as '', the number one is therefore 'a' and two becomes 'b' and so on. And when you reach 'z' and increment it, you will get 'aa'. 'ab' is next and so on forever.

That works a little bit like the automagic in ++, but more consistent and flexible. The following example 'breaks' (no, >= instead of gt won't help ;)

    $a = 'z'; $b = $a; $a++; print ($a gt $b ? 'greater' : 'lower');

With Math::String, it does work as intended, you just have to use '<' or '>' etc for comparing. That was also the main reason for this module ;o)

incidentily, '--' as well most other mathematical operations work as you expected them to work on big integers.

Compare a Math::String of charset '0-9' sequence to that of a 'normal' number:

   ''   0                       0
   '0'  1                       1
   '1'  2                       2
   '2'  3                       3
   '3'  4                       4
   '4'  5                       5
   '5'  6                       6
   '6'  7                       7
   '7'  8                       8
   '8'  9                       9
   '9'  10                     10
  '00'  11                1*10+ 1
  '01'  12                1*10+ 2
      ...
  '98'  109               9*10+ 9
  '99'  110               9*10+10
 '000'  111         1*100+1*10+ 1
 '001'  112         1*100+1*10+ 2
      ...
'0000'  1111  1*1000+1*100+1*10+1
      ...
'1234'  2345  2*1000+3*100+4*10+5

And so on. Here is another example that shows how it works with a number having 4 digits in each place (named "a","b","c", and "d"):

  a    1           1
  b    2           2
  c    3           3
  d    4           4
 aa    5       1*4+1
 ab    6       1*4+2
 ac    7       1*4+3
 ad    8       1*4+4
 ba    9       2*4+1
 bb   10       2*4+2
 bc   11       2*4+3
 bd   12       2*4+4
 ca   13       3*4+1
 cb   14       3*4+2
 cc   15       3*4+3
 cd   16       3*4+4
 da   17       4*4+1
 db   18       4*4+2
 dc   19       4*4+3
 dd   20       4*4+4
aaa   21  1*16+1*4+1

Here is one with a charset containing 'characters' longer than one, namely the words 'foo', 'bar' and 'fud':

       foo           1
       bar           2
       fud           3
    foofoo           4
    foobar           5
    foofud           6
    barfoo           7
    barbar           8
    barfud           9
    fudfoo          10
    fudbar          11
    fudfud          12
 foofoofoo          13 etc

The number sequences are symmetrical to 0, e.g. 'a' is both 1 and -1. Internally the sign is stored and honoured, only on conversation to string it is lost.

The caveat is that you can NOT use Math::String to work, let's say with hexadecimal numbers. If you do calculate with Math::String like you would with 'normal' hexadecimal numbers (any base would or rather, would not do), the result may not mean anything and can not nesseccarily compared to plain hexadecimal math.

The charset given upon creation need not be a 'simple' set consisting of all the letters. You can, actually, give a set consisting of bi-, tri- or higher grams.

See Math::String::Charset for examples of higher order charsets and charsets with more than one character per, well, character.

USEFUL METHODS

LIMITS

For the actual math, the same limits as in Math::BigInt apply. Negative Math::Strings are possible, but produce no different output than positive. You can use as_number() or sign() to get the sign, or do math with them, of course.

Also, the limits detailed in Math::String::Charset apply, like:

EXAMPLES

Fun with Math::String:

    use Math::String;

    $ibm = new Math::String ('ibm');
    $vms = new Math::String ('vms');
    $ibm -= 'aaa';
    $vms += 'aaa';
    print "ibm is now $ibm\n";
    print "vms is now $vms\n";

Some more serious examples:

    use Math::String;
    use Math::BigFloat;

    $a = new Math::String 'henry';                  # default a-z
    $b = new Math::String 'foobar';                 # a-z

    # Get's you the amount of passwords between 'henry' and 'foobar'.
    print "a  : ",$a->as_numbert(),"\n";
    print "b  : ",$b->as_bigint(),"\n";
    $c = $b - $a; print $c->as_bigint(),"\n";

    # You want to know what is the first or last password of a certain
    # length (without multiple charsets this looks a bit silly):
    print $a->first(5),"\n";                        # aaaaa
    print Math::String::first(5,['a'..'z']),"\n";   # aaaaa
    print $a->last(5),"\n";                         # zzzzz
    print Math::String::last(5,['A'..'Z']),"\n";    # ZZZZZ

    # Lets assume you had a password of length 4, which contained a
    # Capital, some lowercase letters, somewhere either a number, or
    # one of '.,:;', but you forgot it. How many passwords do you need
    # to brute force in the worst case, testing every combination?
    $a = new Math::String '', ['a'..'z','A'..'Z','0'..'9','.',',',':',';'];
    # produce last possibility ';;;;;' and first 'aaaaa'
    $b = $a->last(4);   # last possibility of length 4
    $c = $a->first(4);  # whats the first password of length 4

    $c->bsub($b);
    print $c->as_bigint(),"\n";             # all of length 4
    print $b->as_bigint(),"\n";             # testing length 1..3 too

    # Let's say your computer can test 100.000 passwords per second, how
    # long would it take?
    $d = $c->bdiv(100000);
    print $d->as_bigint()," seconds\n";     #

    # or:
    $d = new Math::BigFloat($c->as_bigint()) / '100000';
    print "$d seconds\n";                   #

    # You want your computer to run for one hour and see if the password
    # is to be found. What would be the last password to be tested?
    $c = $b + (Math::BigInt->new('100000') * 3600);
    print "Last tested would be: $c\n";

    # You want to know what the 10.000th try would be
    $c = Math::String->from_number(10000,
     ['a'..'z','A'..'Z','0'..'9','.',',',':',';']);
    print "Try #10000 would be: $c\n";

PERFORMANCE

For simple things, like generating all passwords from 'a' to 'zzz', this is expensive and slow. A custom, table-driven generator or the build-in automagic of ++ (if it would work correctly for all cases, that is ;) would beat it anytime. But if you want to do more than just counting, then this code is what you want to use.

BENCHMARKS

See http://bloodgate.com/perl/benchmarks.html

BUGS

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Math::String

You can also look for information at:

LICENSE

This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself.

AUTHORS

If you use this module in one of your projects, then please email me. I want to hear about how my code helps you ;)

Tels http://bloodgate.com 2000 - 2005.

Maintained by Peter John Acklam, pjacklam@gmail.com 2017-