244 lines
6.9 KiB
Plaintext
244 lines
6.9 KiB
Plaintext
**FREE
|
|
Ctl-opt MAIN(Main);
|
|
Ctl-opt DFTACTGRP(*NO) ACTGRP(*NEW);
|
|
|
|
dcl-pr QDCXLATE EXTPGM('QDCXLATE');
|
|
dataLen packed(5 : 0) CONST;
|
|
data char(32767) options(*VARSIZE);
|
|
conversionTable char(10) CONST;
|
|
end-pr;
|
|
|
|
dcl-c MASK32 CONST(4294967295);
|
|
dcl-s SHIFT_AMTS int(3) dim(16) CTDATA PERRCD(16);
|
|
dcl-s MD5_TABLE_T int(20) dim(64) CTDATA PERRCD(4);
|
|
|
|
dcl-proc Main;
|
|
dcl-s inputData char(45);
|
|
dcl-s inputDataLen int(10) INZ(0);
|
|
dcl-s outputHash char(16);
|
|
dcl-s outputHashHex char(32);
|
|
|
|
DSPLY 'Input: ' '' inputData;
|
|
inputData = %trim(inputData);
|
|
inputDataLen = %len(%trim(inputData));
|
|
DSPLY ('Input=' + inputData);
|
|
DSPLY ('InputLen=' + %char(inputDataLen));
|
|
|
|
// Convert from EBCDIC to ASCII
|
|
if inputDataLen > 0;
|
|
QDCXLATE(inputDataLen : inputData : 'QTCPASC');
|
|
endif;
|
|
CalculateMD5(inputData : inputDataLen : outputHash);
|
|
// Convert to hex
|
|
ConvertToHex(outputHash : 16 : outputHashHex);
|
|
DSPLY ('MD5: ' + outputHashHex);
|
|
return;
|
|
end-proc;
|
|
|
|
dcl-proc CalculateMD5;
|
|
dcl-pi *N;
|
|
message char(65535) options(*VARSIZE) CONST;
|
|
messageLen int(10) value;
|
|
outputHash char(16);
|
|
end-pi;
|
|
dcl-s numBlocks int(10);
|
|
dcl-s padding char(72);
|
|
dcl-s a int(20) INZ(1732584193);
|
|
dcl-s b int(20) INZ(4023233417);
|
|
dcl-s c int(20) INZ(2562383102);
|
|
dcl-s d int(20) INZ(271733878);
|
|
dcl-s buffer int(20) dim(16) INZ(0);
|
|
dcl-s i int(10);
|
|
dcl-s j int(10);
|
|
dcl-s k int(10);
|
|
dcl-s multiplier int(20);
|
|
dcl-s index int(10);
|
|
dcl-s originalA int(20);
|
|
dcl-s originalB int(20);
|
|
dcl-s originalC int(20);
|
|
dcl-s originalD int(20);
|
|
dcl-s div16 int(10);
|
|
dcl-s f int(20);
|
|
dcl-s tempInt int(20);
|
|
dcl-s bufferIndex int(10);
|
|
dcl-ds byteToInt QUALIFIED;
|
|
n int(5) INZ(0);
|
|
c char(1) OVERLAY(n : 2);
|
|
end-ds;
|
|
|
|
numBlocks = (messageLen + 8) / 64 + 1;
|
|
MD5_FillPadding(messageLen : numBlocks : padding);
|
|
for i = 0 to numBlocks - 1;
|
|
index = i * 64;
|
|
|
|
// Read message as little-endian 32-bit words
|
|
for j = 1 to 16;
|
|
multiplier = 1;
|
|
for k = 1 to 4;
|
|
index += 1;
|
|
if index <= messageLen;
|
|
byteToInt.c = %subst(message : index : 1);
|
|
else;
|
|
byteToInt.c = %subst(padding : index - messageLen : 1);
|
|
endif;
|
|
buffer(j) += multiplier * byteToInt.n;
|
|
multiplier *= 256;
|
|
endfor;
|
|
endfor;
|
|
|
|
originalA = a;
|
|
originalB = b;
|
|
originalC = c;
|
|
originalD = d;
|
|
|
|
for j = 0 to 63;
|
|
div16 = j / 16;
|
|
select;
|
|
when div16 = 0;
|
|
f = %bitor(%bitand(b : c) : %bitand(%bitnot(b) : d));
|
|
bufferIndex = j;
|
|
|
|
when div16 = 1;
|
|
f = %bitor(%bitand(b : d) : %bitand(c : %bitnot(d)));
|
|
bufferIndex = %bitand(j * 5 + 1 : 15);
|
|
|
|
when div16 = 2;
|
|
f = %bitxor(b : %bitxor(c : d));
|
|
bufferIndex = %bitand(j * 3 + 5 : 15);
|
|
|
|
when div16 = 3;
|
|
f = %bitxor(c : %bitor(b : Mask32Bit(%bitnot(d))));
|
|
bufferIndex = %bitand(j * 7 : 15);
|
|
endsl;
|
|
tempInt = Mask32Bit(b + RotateLeft32Bit(a + f + buffer(bufferIndex + 1) + MD5_TABLE_T(j + 1) :
|
|
SHIFT_AMTS(div16 * 4 + %bitand(j : 3) + 1)));
|
|
a = d;
|
|
d = c;
|
|
c = b;
|
|
b = tempInt;
|
|
endfor;
|
|
a = Mask32Bit(a + originalA);
|
|
b = Mask32Bit(b + originalB);
|
|
c = Mask32Bit(c + originalC);
|
|
d = Mask32Bit(d + originalD);
|
|
endfor;
|
|
|
|
for i = 0 to 3;
|
|
if i = 0;
|
|
tempInt = a;
|
|
elseif i = 1;
|
|
tempInt = b;
|
|
elseif i = 2;
|
|
tempInt = c;
|
|
else;
|
|
tempInt = d;
|
|
endif;
|
|
|
|
for j = 0 to 3;
|
|
byteToInt.n = %bitand(tempInt : 255);
|
|
%subst(outputHash : i * 4 + j + 1 : 1) = byteToInt.c;
|
|
tempInt /= 256;
|
|
endfor;
|
|
endfor;
|
|
return;
|
|
end-proc;
|
|
|
|
dcl-proc MD5_FillPadding;
|
|
dcl-pi *N;
|
|
messageLen int(10);
|
|
numBlocks int(10);
|
|
padding char(72);
|
|
end-pi;
|
|
dcl-s totalLen int(10);
|
|
dcl-s paddingSize int(10);
|
|
dcl-ds *N;
|
|
messageLenBits int(20);
|
|
mlb_bytes char(8) OVERLAY(messageLenBits);
|
|
end-ds;
|
|
dcl-s i int(10);
|
|
|
|
%subst(padding : 1 : 1) = X'80';
|
|
totalLen = numBlocks * 64;
|
|
paddingSize = totalLen - messageLen; // 9 to 72
|
|
messageLenBits = messageLen;
|
|
messageLenBits *= 8;
|
|
for i = 1 to 8;
|
|
%subst(padding : paddingSize - i + 1 : 1) = %subst(mlb_bytes : i : 1);
|
|
endfor;
|
|
for i = 2 to paddingSize - 8;
|
|
%subst(padding : i : 1) = X'00';
|
|
endfor;
|
|
return;
|
|
end-proc;
|
|
|
|
dcl-proc RotateLeft32Bit;
|
|
dcl-pi *N int(20);
|
|
n int(20) value;
|
|
amount int(3) value;
|
|
end-pi;
|
|
dcl-s i int(3);
|
|
|
|
n = Mask32Bit(n);
|
|
for i = 1 to amount;
|
|
n *= 2;
|
|
if n >= 4294967296;
|
|
n -= MASK32;
|
|
endif;
|
|
endfor;
|
|
return n;
|
|
end-proc;
|
|
|
|
dcl-proc Mask32Bit;
|
|
dcl-pi *N int(20);
|
|
n int(20) value;
|
|
end-pi;
|
|
return %bitand(n : MASK32);
|
|
end-proc;
|
|
|
|
dcl-proc ConvertToHex;
|
|
dcl-pi *N;
|
|
inputData char(32767) options(*VARSIZE) CONST;
|
|
inputDataLen int(10) value;
|
|
outputData char(65534) options(*VARSIZE);
|
|
end-pi;
|
|
dcl-c HEX_CHARS CONST('0123456789ABCDEF');
|
|
dcl-s i int(10);
|
|
dcl-s outputOffset int(10) INZ(1);
|
|
dcl-ds dataStruct QUALIFIED;
|
|
numField int(5) INZ(0);
|
|
// IBM i is big-endian
|
|
charField char(1) OVERLAY(numField : 2);
|
|
end-ds;
|
|
|
|
for i = 1 to inputDataLen;
|
|
dataStruct.charField = %BitAnd(%subst(inputData : i : 1) : X'F0');
|
|
dataStruct.numField /= 16;
|
|
%subst(outputData : outputOffset : 1) = %subst(HEX_CHARS : dataStruct.numField + 1 : 1);
|
|
outputOffset += 1;
|
|
dataStruct.charField = %BitAnd(%subst(inputData : i : 1) : X'0F');
|
|
%subst(outputData : outputOffset : 1) = %subst(HEX_CHARS : dataStruct.numField + 1 : 1);
|
|
outputOffset += 1;
|
|
endfor;
|
|
return;
|
|
end-proc;
|
|
|
|
**CTDATA SHIFT_AMTS
|
|
7 12 17 22 5 9 14 20 4 11 16 23 6 10 15 21
|
|
**CTDATA MD5_TABLE_T
|
|
3614090360 3905402710 606105819 3250441966
|
|
4118548399 1200080426 2821735955 4249261313
|
|
1770035416 2336552879 4294925233 2304563134
|
|
1804603682 4254626195 2792965006 1236535329
|
|
4129170786 3225465664 643717713 3921069994
|
|
3593408605 38016083 3634488961 3889429448
|
|
568446438 3275163606 4107603335 1163531501
|
|
2850285829 4243563512 1735328473 2368359562
|
|
4294588738 2272392833 1839030562 4259657740
|
|
2763975236 1272893353 4139469664 3200236656
|
|
681279174 3936430074 3572445317 76029189
|
|
3654602809 3873151461 530742520 3299628645
|
|
4096336452 1126891415 2878612391 4237533241
|
|
1700485571 2399980690 4293915773 2240044497
|
|
1873313359 4264355552 2734768916 1309151649
|
|
4149444226 3174756917 718787259 3951481745
|