CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
DES in Perl

 



TomY
New User

Nov 14, 2017, 1:14 AM

Post #1 of 3 (985 views)
DES in Perl Can't Post

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.
-code may not be optimal or good :(

In advance tnxxx all helpers and advises !




Code
#!/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 message 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-string-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 used.
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 operation
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 encryption/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 reversed
}

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, $sBoxResStr 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 chunk 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 input 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 properly#\n";

if($action eq "e"){
# padding at the end to fit 8 byte/64 bit chunks for DES blocks
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_PROPERTIES.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_PROPERTIES.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($FileArray[$i])-$diff);
}
print FILEHANDLER $FileArray[$i];
}
close(FILEHANDLER) or die "#ERROR: couldn't close output file properly#\n";
}
#--------------------------------------------------------------------------------

#--------------------------------------------------------------------------------
# Execute
#--------------------------------------------------------------------------------
readInputToArray();
des();
writeOutputToFile();
#--------------------------------------------------------------------------------



BillKSmith
Veteran

Nov 14, 2017, 7:59 AM

Post #2 of 3 (971 views)
Re: [TomY] DES in Perl [In reply to] Can't Post

There are two things you must do before we can offer much help.

Add the pragmas strict and warnings. Fix all the errors that they report. (There are over 100 messages, but not nearly that many errors). You just might fix the problem yourself.

Prepare a short sample of input which we can run and demonstrate the error. Post the actual output and the expected output.

You have provided excellent documentation. Smile Convention suggests that this type of documentation should be provided as POD rather than as comments. For documentation on POD, type:

Code
perldoc perlpod

Good Luck,
Bill


Laurent_R
Veteran / Moderator

Nov 14, 2017, 11:19 PM

Post #3 of 3 (962 views)
Re: [TomY] DES in Perl [In reply to] Can't Post

Cross posted on Perl monks:

Code
http://www.perlmonks.org/?node_id=1203344

Please consider informing people of cross-posts to avoid duplication of work on various locations of the Internet.

Otherwise, you might want to take a look at the pure Perl implementation of DES in the Crypt::DES_PP module (http://search.cpan.org/perldoc?Crypt%3A%3ADES_PP).

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives