|
NAMEMath::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'
REQUIRESperl5.005, Exporter, Math::BigInt, Math::String::Charset EXPORTSExports nothing on default, but can export as_number(), string(), first(), digits(), "from_number", bzero() and last(). DESCRIPTIONThis 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 DETAILSUses 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
LIMITSFor 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:
EXAMPLESFun 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";
PERFORMANCEFor 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. BENCHMARKSSee http://bloodgate.com/perl/benchmarks.html BUGS
SUPPORTYou can find documentation for this module with the perldoc command. perldoc Math::String You can also look for information at:
LICENSEThis program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. AUTHORSIf 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-
|