MD5/Implementation: Difference between revisions
Content added Content deleted
(Added RPG implementation) |
|||
Line 3,403: | Line 3,403: | ||
out = 57EDF4A22BE3C955AC49DA2E2107B67A |
out = 57EDF4A22BE3C955AC49DA2E2107B67A |
||
</pre> |
</pre> |
||
=={{header|RPG}}== |
|||
Based on my Java implementation. Uses free-form RPG and a CTDATA section to hold lookup tables. Converts input from EBCDIC to ASCII before hashing. |
|||
<lang RPG>**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</lang> |
|||
Sample output: |
|||
<pre> DSPLY Input: |
|||
abcdefghijklmnopqrstuvwxyz |
|||
DSPLY Input=abcdefghijklmnopqrstuvwxyz |
|||
DSPLY InputLen=26 |
|||
DSPLY MD5: C3FCD3D76192E4007DFB496CCA67E13B</pre> |
|||
=={{header|Seed7}}== |
=={{header|Seed7}}== |