TBS digest, sign.
La firma de autenticación (según se entiende en la Directiva Europea) se propone de
esta forma rudimentaria. Fue presentado al congreso de Criptología y Seguridad en la
Información de Oviedo 5-7 Sept. 2002 (RECSI7). No contiene (aún) verificación ni IDs.
#!/usr/bin/perl
package TBS; #
use integer; # Perl compilado con 64bit int para compatibilidad
use strict;
my $VERSION = '0.91';
my $DEBUG =0; # NO DEBUG
my @skeys =(0x0002, 0x0003, 0x0005, 0x0007, 0x0011, 0x0013, 0x0017, 0x0019,
0x1002, 0x1003, 0x1005, 0x1007, 0x1011, 0x1013, 0x1017, 0x1019,
0x1400, 0x1405, 0x1500, 0x1070, 0x1097, 0x1099, 0x1990, 0x3333,
0xaaa6, 0x9876, 0x9631, 0x9110, 0x8755, 0x8888, 0x8242, 0x7411,
0xbaba, 0xaf01, 0xaf77, 0xad48, 0xad43, 0xac57, 0xac42, 0xab69,
0xbbbb, 0xbbb1, 0xbb92, 0xbb38, 0xbb36, 0xbb17, 0xbb00, 0xb000,
0xcb01, 0xcb03, 0xcb05, 0xcb07, 0xcb11, 0xcb13, 0xcb17, 0xcb19,
0xff02, 0xff03, 0xff05, 0xff07, 0xff11, 0xff13, 0xff17, 0xff19);
my $num = scalar (@ARGV);
my (@data,@x,@atad); # declaration of matrixes (lists). data and x are temporal
if ($num <=0) {
while ( < STDIN > ){
push @data,$_;
last unless $_;
}
}else{
open (IN,"<".$ARGV[0]) || die "Cannot open $ARGV[0]";
@data = < IN >;
close (IN);
}
unless (@data){ die "Cannot read anything from stdin"; }
if ($DEBUG){ print "ok data\n"; }
our $unused="";
my $SIGNATURE = &sign_time() . &sign_path_program(); # 7 + 10
if ($DEBUG) { print $SIGNATURE,"\n"; }
my ($m,$n,$i,$j,$k)=(0,0,0,0,0);
for $i (@data){
$m++; # line
if ($m>77){ $m=1; }
@x = split "",$i;
for $j (@x){
$n++; # column
if ($n>77){ $n=1; }
$atad[$n][$m] += ord($j); # transpose and acumulate ascii number ()
}
}
# @data = (); @x = (); # cleanning
$unused .= (ord($j)%100).$m.$n; # get something from size
for $i (1..77){
for $j (1..77){
unless (defined $atad[$i][$j]){ # padding
if (defined $atad[$j][$i]){ # by the transposed
$atad[$i][$j]=$atad[$j][$i]+$i+$j; # sign one-way
}else{ # message short
$atad[$i][$j] = hex($skeys[($i*77+$j)%64])+$i+$j;
}
}
}
}
$SIGNATURE .= &sign_studied(@atad); # 17 + 10
if ($DEBUG) { print $SIGNATURE,"\n"; }
$SIGNATURE .= &sign_unuseds($unused); # 27 + 10
if ($DEBUG) { print $SIGNATURE,"\n"; }
my ($value,$ok,$final,@sol,$z)=(0,0,"",(),0); # declarations. @sol is a small matrix
$value=$m+$n;
# MD5 2^128=340282366920938463463374607431768211456
# 77^40=2881568890859166525765145719746023659877064263035691961526335443765425482401
for $i (100..140){ # less than 101 for 'warming'
$ok=0;
while(1) {
$value += $i+hex($skeys[$value%64]); # iteration, key,
$j=1+$value%77;
$k=1+int($value/77)%77;
$value += $atad[$j][$k]; # it and its neighbours
if (defined $atad[$j-1][$k-1]){ $value += $atad[$j-1][$k-1]; }
if (defined $atad[$j+1][$k-1]){ $value += $atad[$j+1][$k-1]; }
if (defined $atad[$j-1][$k+1]){ $value += $atad[$j-1][$k+1]; }
if (defined $atad[$j+1][$k+1]){ $value += $atad[$j+1][$k+1]; }
if ($value<0){ $value= 0; } # if gones overflow...
$ok++;
last if ($ok==15); # 5*20*40 still < 77*77 matrix (!)
}
$sol[$i-100]=1+$value%77;
}
for $i (1..40){ # sol[0] is not used
if ($sol[$i]>77 || $sol[$i]<=0){ die "Valor ilegal $sol[$i]\n"; }
$z = 45+$sol[$i];
if ($z==96) { $z=45; } # the mouse exception (absent in first bytes)
$final .= chr($z);
}
$SIGNATURE .= $final; # that's all
print $SIGNATURE,"\n";
# main END
sub sign_time {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$unused .= $mday + $mon + $wday + $isdst;
# unused by the moment...
my $seconds = $hour*60*60+$min*60+$sec;
# seconds goes from 0 to 24*60*60, that is, 86400
# this leads to inefficiency since 77^2 = 5929 and 77^3 = 456533
# so it's a non-sense non using this obvious code:
my $byte1 = $hour;
my $byte2 = $min;
my $byte3 = $sec;
$seconds = chr(45+$byte1).chr(45+$byte2).chr(45+$byte3);
my $dayoftheyear = $yday;
my $byte4 = int ($dayoftheyear/77);
my $byte5 = $dayoftheyear % 77;
# so dayoftheyear = byte4*77+byte5
$dayoftheyear = chr(45+$byte4).chr(45+$byte5);
my $yearsince1900 = $year;
my $byte6 = int ($yearsince1900/77);
my $byte7 = $yearsince1900 % 77;
# so year = byte6*77 +byte7 +1900
$yearsince1900 = chr(45+$byte6).chr(45+$byte7);
# putting all together... 7 char, only remains 70...
return ($seconds . $dayoftheyear . $yearsince1900);
}
sub sign_path_program {
# PATH is a environment variable, POSIX standard
my $path = $ENV{PATH};
# argv[0] contains the program name which signs
my $name = $0;
my $basestring = ucfirst(lc($path)).uc($name); # lowercase and uppercase
# . : ; _ - / and \ are inside base77, but spaces aren't
$basestring =~ s/ //g;
# uuencoded chars only - don't works, it includes evils \n
# $basestring = pack("u",$basestring);
# ok this base-string must be no null but could have a lot of chars
while (length($basestring)<10){
$basestring .= reverse($basestring);
}
# so let's truncate to a maximun of 10 chars simply from the left on sequence
if (length($basestring)>10){
$unused .= substr($basestring,0,length($basestring)-10,"");
}
return $basestring; # and remains 60...
}
sub sign_studied {
my @d = @_; # all data from @atad
my ($i, $j, $foo, $search, $num); # man sum, cksum, md5sum...
for $i (1..77){
for $j (1..77){
# $foo .= $d[$j][$i]; better using XOR as int. op.!!!
$num += $d[$i][$j] ^ ($j*$i+$i); # man sum (Sys V 512, BSD 1K)
}
}
### $checksum = do { local $/; unpack("%32C*",<>) % 65535; }; # rep. Sys V
## $foo =~ s/ //g;
# $search = study $foo;
# $unused .= $search;
# for $i ('0'..'z'){
# $num .= abs(rindex $foo,$i)%10;
# }
$num = reverse ($num);
if (length($num)<10) { $num = 9999999999-$num; }
return substr($num,0,10); # only last 50...
}
sub sign_unuseds {
my $s = shift; # reading the variable $unuseds or alike
my @s = split "", $s;
my $count ="";
for (@s){
if (/\d/){
s/(\d)//;
$count .= 9-$1;
}elsif (/\w/){
s/(\w)//;
$count .= ord($1)%100;
}else{
s/ //g;
$count .= int(length($count)**(4*atan2(1,1))); # powered by PI
}
}
$count =~ s/\D//g; # only digits
$count = reverse($count);
while (length($count)<10){
$count .= reverse($count);
}
return substr($count,0,10); # yet remains 40
}
1;
__END__