Hello, I wrote a simple DES in ECB mode implementation in Perl based on W.Stallings book... When I tried to compare it with online calc. I didnt get exactly the same outputs(lets focus on encryption as the process is idenctical) what do I mean is, we know DES works on blocks of 8 bytes and both my script and online calcs. give the same result for the first 2 blocks only! so I came to the conclusion that I am not reading the input file as 8 byte chunks correctly or as them.... Please help me understand why(again assumption is the read from file func is somehow wrong)?? remarks: -I am a Perl beginner -For those who are interested this is a self project intended to be shown to my class mates if my teacher would allow me i.e. this not an assignment or work related...just for my own fun after reading the book ch. -code may not be optimal or good :( In advance tnxxx all helpers and advises !
#!/usr/bin/perl #--------------------------------------------------------------------- +------------------------ # @Script CLI args@ # 1) action: "e" or "d", as one char string # 2) password: "myDesPass", as a string # 3) input file: "filePath1", as a string, should contain the message + to encrypt # 4) output file: "filePath2", as a string, where the encrypted messag +e will be saved #--------------------------------------------------------------------- +------------------------ #--------------------------------------------------------------------- +------------------------ # Ctyptography and Network Security 4th edition by Willian Stallings # # DES online calculator: # https://www.emvlab.org/descalc # # Perl tutorial: # https://www.tutorialspoint.com/perl/ # http://www.perlmonks.org/ # # unpack/pack: # https://www.tutorialspoint.com/perl/perl_unpack.htm # # perl references: # https://perlmaven.com/array-references-in-perl # # Programmatic Conversions: # http://perltips.wikidot.com/convert-hex-dec-oct-bin # https://stackoverflow.com/questions/288900/how-can-i-convert-a-strin +g-to-a-number-in-perl # # Online Conversions: # http://www.rapidtables.com/convert/number/hex-to-ascii.htm # http://www.asciitohex.com/ # #--------------------------------------------------------------------- +------------------------ #--------------------------------------------------------------------- +------------------------ # DES Internal Conversion Tables #--------------------------------------------------------------------- +------------------------ @SBOXES = ( #S1 [ [14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7], [0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8], [4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0], [15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13] ], #S2 [ [15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10], [3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5], [0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15], [13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9] ], #S3 [ [10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8], [13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1], [13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7], [1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12] ], #S4 [ [7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15], [13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9], [10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4], [3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14] ], #S5 [ [2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9], [14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6], [4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14], [11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3] ], #S6 [ [12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11], [10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8], [9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6], [4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13] ], #S7 [ [4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1], [13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6], [1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2], [6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12] ], #S8 [ [13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7], [1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2], [7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8], [2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11] ] ); my @IP = ( 58,50,42,34,26,18,10,2, 60,52,44,36,28,20,12,4, 62,54,46,38,30,22,14,6, 64,56,48,40,32,24,16,8, 57,49,41,33,25,17, 9,1, 59,51,43,35,27,19,11,3, 61,53,45,37,29,21,13,5, 63,55,47,39,31,23,15,7 ); my @IP_INVERSE = ( 40,8,48,16,56,24,64,32, 39,7,47,15,55,23,63,31, 38,6,46,14,54,22,62,30, 37,5,45,13,53,21,61,29, 36,,4,44,12,52,20,60,28, 35,3,43,11,51,19,59,27, 34,2,42,10,50,18,58,26, 33,1,41,9,49,17,57,25 ); my @E = ( 32,1,2,3,4,5, 4,5,6,7,8,9, 8,9,10,11,12,13, 12,13,14,15,16,17, 16,17,18,19,20,21, 20,21,22,23,24,25, 24,25,26,27,28,29, 28,29,30,31,32,1 ); my @P = ( 16,7,20,21,29,12,28,17, 1,15,23,26,5,18,31,10, 2,8,24,14,32,27,3,9, 19,13,30,6,22,11,4,25 ); my @PC_1 = ( 57,49,41,33,25,17,9, ,1,58,50,42,34,26,18, 10,2,59,51,43,35,27, 19,11,3,60,52,44,36, 63,55,47,39,31,23,15, 7,62,54,46,38,30,22, 14,6,61,53,45,37,29, 21,13,5,28,20,12,4 ); my @PC_2 = ( 14,17,11,24,1,5,3,28, 15,6,21,10,23,19,12,4, 26,8,16,7,27,20,13,2, 41,52,31,37,47,55,30,40, 51,45,33,48,44,49,39,56, 34,53,46,42,50,36,29,32 ); my @ScheduleOfLeftShifts = (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, +2, 1); #--------------------------------------------------------------------- +------------------------ #--------------------------------------------------------------------- +------------------------ # Globals and CLI args #--------------------------------------------------------------------- +------------------------ my $action = checkAction($ARGV[0]); my $subKeysRef = createRoundKeys($ARGV[1]); my $InputFileName = $ARGV[2]; my $OutputFileName = $ARGV[3]; # this is an array where each element is a ref to a bits-array of the +index/round sub-key # @$: dereference a refrence to an array my @SubKeys = @$subKeysRef; # holds data to read/write from/to file my @FileArray = (); #--------------------------------------------------------------------- +------------------------ #--------------------------------------------------------------------- +------------------------ # #--------------------------------------------------------------------- +------------------------ sub checkAction { my $action = $_[0]; if( ($action eq "e") or ($action eq "d") ) { return $action; } else { die "#ERROR: action parameter is wrong (\"e\"=encryption, \"d\ +"=decryption)#\n"; } } #--------------------------------------------------------------------- +------------------------ #--------------------------------------------------------------------- +------------------------ # #--------------------------------------------------------------------- +------------------------ sub createRoundKeys { my $key = $_[0]; if(length $key != 8) { die "#ERROR: DES key is not 64 bit#\n";} my $i, $j; # to hold references to sub-keys for each round according to array + index. # the function returns a reference of this array to be farther use +d. my @subKeys = (); # unpack returns the key string as a corresponding bit string # 64 bit where B indicates highest first my @tempArr = unpack("B64", $key); # split bit string to corresponding bits array my @keyBitsArr = split("", $tempArr[0]); #convert to numeric bits for ($j=0; $j<=$#keyBitsArr; $j++) { $keyBitsArr[$j]+=0; } #------------------------------------------------------------ # permuted choice one(@PC_1) # each index in the keyBitsArr56_PC1 gets some bit from the 64-bit + original key according to some mapping, PC-1 my @keyBitsArr56_PC1 = (); for ($i=0; $i<=$#PC_1; $i++) { $keyBitsArr56_PC1[$i] = $keyBitsArr[$PC_1[$i]-1]; } # split permuted choice 1 outcome @keyBitsArr56_PC1 to two 28 bit +arrays, left and right my @leftBitsArr = (); my @rightBitsArr = (); for($i=0; $i<28; $i++) { $leftBitsArr[$i] = $keyBitsArr56_PC1[$i]; } for(; $i<56; $i++) { $rightBitsArr[$i-28] = $keyBitsArr56_PC1[$i]; } #------------------------------------------------------------ #------------------------------------------------------------ # create sub-keys for each round @tempArr = (); for($i=0; $i<16; $i++) { # shift each part individually for($j=0; $j<$ScheduleOfLeftShifts[$i]; $j++) { # shift left part according to round push(@leftBitsArr, shift(@leftBitsArr)); # shift right part according to round push(@rightBitsArr, shift(@rightBitsArr)); } # PC_2, get 48 bit round sub key # unite to one 56 bits arr for($j=0; $j<28; $j++) { $tempArr[$j] = $leftBitsArr[$j]; $tempArr[$j+28] = $rightBitsArr[$j]; } # permuted choice two for ($j=0; $j<=$#PC_2; $j++) { # save round key ${$subKeys[$i]}[$j] = $tempArr[$PC_2[$j]-1]; } } #------------------------------------------------------------ return \@subKeys; } #--------------------------------------------------------------------- +------------------------ #--------------------------------------------------------------------- +------------------------ # #--------------------------------------------------------------------- +------------------------ sub des { my $i, $j, $k, $tempVar, @tempArr; # iterate over input file in chunks of 64 bit, DES ECB-mode of ope +ration for($i=0; $i<=$#FileArray; $i++) { # convert block read from file to its binary rep $tempVar = unpack("B64", $FileArray[$i]); #---------------------------------------- # DEBUG/PoC print("$FileArray[$i]\n"); $hex = sprintf('%X', oct("0b$tempVar")); print("$hex\n"); #---------------------------------------- # an array of bits as numeric values, the block rep as numeric + binary numbers my @bitsArray = split("", $tempVar); #convert to numeric bits for ($j=0; $j<=$#bitsArray; $j++) { $bitsArray[$j]+=0; } # initial permutation (IP) for each block/64 bit chunk before +the 16 rounds my @bitsArray_ip = (); for ($j=0; $j<=$#IP; $j++) { $bitsArray_ip[$j] = $bitsArray[$IP[$j]-1]; } # split to: left and right my @leftBitsArr = (); my @rightBitsArr = (); for ($j=0; $j<32; $j++) { $leftBitsArr[$j] = $bitsArray_ip[$j]; $rightBitsArr[$j] = $bitsArray_ip[$j+32]; } # 16 DES rounds per 64 bit chunk treated as two 32 bit chunks for($j=0; $j<16; $j++) { my @nextLeftBitsArr = @rightBitsArr; # curr right bits chunk expansion/permutation (E) my @bitsArray_E = (); for($k=0; $k<=$#E; $k++) { $bitsArray_E[$k] = $rightBitsArr[$E[$k]-1]; } @rightBitsArr = @bitsArray_E;# copy back # XOR with round sub-key: check function bool param for en +cryption/decryption action my $ref; if($action eq "e") { $ref = $SubKeys[$j];# j - index of curr round } elsif($action eq "d") { $ref = $SubKeys[15-$j];# j - index of curr round reve +rsed } my @roundSubKey = @$ref;# de-ref to bits-array for($k=0; $k<48; $k++) { $rightBitsArr[$k]^=$roundSubKey[$k]; } # S-box my $sBoxResStr = ""; for($k=0; $k<8; $k++) { @tempArr = unpack("N", pack("B32", ("0"x30).join("",($ +rightBitsArr[$k*6], $rightBitsArr[$k*6+5])))); my $sBoxRow = $tempArr[0]; @tempArr = unpack("N", pack("B32", ("0"x28).join("",($ +rightBitsArr[$k*6+1], $rightBitsArr[$k*6+2], $rightBitsArr[$k*6+3], $ +rightBitsArr[$k*6+4])))); my $sBoxCol = $tempArr[0]; my $sBoxOutput = $SBOXES[$k][$sBoxRow][$sBoxCol]; @tempArr = unpack("B32", pack("N", $sBoxOutput)); $sBoxResStr.=substr($tempArr[0], -4); } @rightBitsArr = split("", $sBoxResStr);# now 32 bits, $sBo +xResStr was loop concat. #convert to numeric bits for ($k=0; $k<=$#rightBitsArr; $k++) { $rightBitsArr[$k]+=0; } # permutation(P) my @bitsArray_p = (); for ($k=0; $k<=$#P; $k++) { $bitsArray_p[$k] = $rightBitsArr[$P[$k]-1]; } @rightBitsArr = @bitsArray_p;# now 32 bits # XOR result on curr right bits chunk with curr left bits +chunk, put res to next right chunk for($k=0; $k<32; $k++) { $rightBitsArr[$k] ^= $leftBitsArr[$k]; } # assign next values @leftBitsArr = @nextLeftBitsArr; } # swap two sides @temp = @leftBitsArr; @leftBitsArr = @rightBitsArr; @rightBitsArr = @temp; # merge and inverse initial permutation --> output 64 bit chun +k cipher-text for($k=0; $k<32; $k++) { $bitsArray[$k] = $leftBitsArr[$k]; $bitsArray[$k+32] = $rightBitsArr[$k]; } my @bitsArray_ip_inverse = (); for ($k=0; $k<=$#IP_INVERSE; $k++) { $bitsArray_ip_inverse[$k] = $bitsArray[$IP_INVERSE[$k]-1]; } #save manipulated chunk to same index in @FileArray $tempVar = join("", @bitsArray_ip_inverse); $FileArray[$i] = pack("B64", $tempVar); } } #--------------------------------------------------------------------- +------------------------ #--------------------------------------------------------------------- +------------------------ # I/O functions #--------------------------------------------------------------------- +------------------------ sub readInputToArray { open(FILEHANDLER, "<".$InputFileName) or die "#ERROR: can't open i +nput file#\n"; my $i = 0; while(1) { # read a block of data, block size is 8 bytes/64 bits $bytes = read (FILEHANDLER, $chunk, 8); if($bytes == 0) { last; } else { $FileArray[$i] = $chunk; $i++; } } close(FILEHANDLER) or die "#ERROR: couldn't close input file prope +rly#\n"; if($action eq "e"){ # padding at the end to fit 8 byte/64 bit chunks for DES block +s my $lastBlockSize = length $FileArray[$#FileArray]; my $diff = 0; if( $lastBlockSize < 8) { $diff = 8 - $lastBlockSize; # create the padding string my $padding = "0" x $diff; # concat last block to pedding string $FileArray[$#FileArray].=$padding; } open(FILEHANDLER, ">.DES_PROPERTIES.txt") or die "#ERROR: can' +t open .DES_PROPERTIES.txt file#\n"; print FILEHANDLER "des_padding_diff\n$diff\n"; close(FILEHANDLER) or die "#ERROR: couldn't close .DES_PROPERT +IES.txt file properly#\n"; } } sub writeOutputToFile { if($action eq "d"){ open(FILEHANDLER, "<.DES_PROPERTIES.txt") or die "#ERROR: can' +t open DES_PROPERTIES.txt file#\n"; @lines = <FILEHANDLER>; $diff = $lines[1]; close(FILEHANDLER) or die "#ERROR: couldn't close DES_PROPERTI +ES.txt file properly#\n"; } open(FILEHANDLER, ">".$OutputFileName) or die "#ERROR: can't open +output file#\n"; for(my $i=0; $i<=$#FileArray; $i++) { if($i == $#FileArray) { $FileArray[$i] = substr($FileArray[$i], 0, length($FileArr +ay[$i])-$diff); } print FILEHANDLER $FileArray[$i]; } close(FILEHANDLER) or die "#ERROR: couldn't close output file prop +erly#\n"; } #--------------------------------------------------------------------- +----------- #--------------------------------------------------------------------- +----------- # Execute #--------------------------------------------------------------------- +----------- readInputToArray(); des(); writeOutputToFile(); #--------------------------------------------------------------------- +-----------

In reply to DES in Perl by TomY

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.