Skip to content

Instantly share code, notes, and snippets.

@lyda
Last active November 24, 2020 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lyda/239cfad690beb364c55df440c3e9ec39 to your computer and use it in GitHub Desktop.
Save lyda/239cfad690beb364c55df440c3e9ec39 to your computer and use it in GitHub Desktop.
COBOL implementation of the MD5 algorithm.
*> Copyright (C) 2006 Micro Focus (IP) Limited.
*> All rights reserved.
*>
*> Michael Wojcik, Micro Focus International Ltd
*> April 2006
$set ans85 mf sourceformat"free" align"8" notrickle opt"4"
$set noalter comp nocheck nocheckdiv noqualproc noseg notrunc
$set scheduler
*> cobmd5: An implementation of the MD5 message digest algorithm
*> in COBOL. See the "mainline" paragraph for an example of using
*> it. This program actually calculates the MD5 digest of a file
*> specified on the command line.
*> NOTE: This implementation is inspired by free-for-use C source code
*> contained in IETF RFC (Request For Comments) document 1321, which is
*> adapted from RSA Data Security Incorporated's RSAREF library.
*>
*> The license for the RSADSI-owned materials is as follows:
*>
*> [Begin RSADSI license.]
*>
*> Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
*> rights reserved.
*>
*> License to copy and use this software is granted provided that it
*> is identified as the "RSA Data Security, Inc. MD5 Message-Digest
*> Algorithm" in all material mentioning or referencing this software
*> or this function.
*>
*> License is also granted to make and use derivative works provided
*> that such works are identified as "derived from the RSA Data
*> Security, Inc. MD5 Message-Digest Algorithm" in all material
*> mentioning or referencing the derived work.
*>
*> RSA Data Security, Inc. makes no representations concerning either
*> the merchantability of this software or the suitability of this
*> software for any particular purpose. It is provided "as is"
*> without express or implied warranty of any kind.
*>
*> These notices must be retained in any copies of any part of this
*> documentation and/or software.
*>
*> [End RSADSI license.]
*> In general, to compute the digest of arbitrary data:
*> 1. Perform MD5-Init to initialize the context.
*> 2. Perform MD5-Update on blocks of input until it's all been processed.
*> Note that MD5-Update here uses a fixed-size input buffer, but really
*> could take a linkage item of arbitrary size.
*> 3. Perform MD5-Final to finish.
*> 4. Extract the digest from MD5-Digest. See Print-Digest for an example.
identification division.
program-id. cobmd5.
author. Michael Wojcik, Micro Focus International Ltd.
data division.
working-storage section.
01 Program-Vars.
03 Input-Filename pic x(256).
03 Input-Handle pic x(4).
03 Input-Record pic x(4096).
03 Input-Access pic x comp-x sync.
03 Input-Deny pic x comp-x sync.
03 Input-Device pic x comp-x sync.
03 Input-Flags pic x comp-x sync.
03 Input-Offset pic x(8) comp-x sync.
03 Input-Size pic x(8) comp-x sync.
03 Input-Count pic x(4) comp-x sync.
03 File-Stat pic xx comp-x sync.
03 redefines File-Stat.
05 FS-Byte-1 pic x.
05 FS-Byte-2 pic x comp-x.
03 FS-Display-2 pic 9(3) display.
78 Open-Read value 1.
78 Deny-None value 3.
78 Device-None value 0.
78 Flags-None value 0.
78 Flags-FSize value 128.
01 Parameters.
*> x, y, and z are the parameters to the basic MD5 functions
03 MD5-X pic x(4) comp-5 sync.
03 MD5-Y pic x(4) comp-5 sync.
03 MD5-Z pic x(4) comp-5 sync.
*> MD5-Basic is the result of a basic function
03 MD5-Basic pic x(4) comp-5 sync.
*> r and n are the parameters to the MD5 rotate-left function
03 MD5-R pic x(4) comp-5 sync.
03 MD5-N pic x(4) comp-5 sync.
*> rl is the result of the MD5 rotate-left function
03 MD5-RL pic x(4) comp-5 sync.
*> a-d, v, s, and ac are the parameters to the MD5 transforms
*> (RFC 1321 calls v "x", but we've already used x)
*> a-d are state; v is input data; s and ac are constants
03 MD5-A pic x(4) comp-5 sync.
03 MD5-B pic x(4) comp-5 sync.
03 MD5-C pic x(4) comp-5 sync.
03 MD5-D pic x(4) comp-5 sync.
03 MD5-V pic x(4) comp-5 sync.
03 MD5-S pic x(4) comp-5 sync.
03 MD5-AC pic x(4) comp-5 sync.
*> invals is the table of 32-bit little-endian integers created from
*> the input buffer
03 MD5-InVals pic x(4) comp-5 sync
occurs 16.
*> buf and val are used by Encode and Decode, which convert between
*> byte buffers and 32-bit integers (Decode is not actually used in
*> the current implementation)
03 MD5-Buf pic x(4).
03 MD5-Val pic x(4) comp-5 sync.
*> Parameters to the Update function, which actually processes the
*> input data. In a real implementation these would be in linkage,
*> and MD5-Input would just be a pic x that we'd treat as an array
*> of undefined length using reference modification.
03 MD5-Input pic x(4096).
03 MD5-InLen pic x(4) comp-5 sync.
*> Final result - the digest
03 MD5-Digest pic x(16).
01 Temporaries.
03 ROL-NthPowerOf2 pic x(4) comp-5 sync.
03 ROL-CmpPowerOf2 pic x(4) comp-5 sync.
03 ROL-Quotient pic x(4) comp-5 sync.
03 ROL-Remainder pic x(4) comp-5 sync.
03 ROL-PowersOf2-vals comp-5 sync.
05 filler pic x(4) comp-5 sync value 2.
05 filler pic x(4) comp-5 sync value 4.
05 filler pic x(4) comp-5 sync value 8.
05 filler pic x(4) comp-5 sync value 16.
05 filler pic x(4) comp-5 sync value 32.
05 filler pic x(4) comp-5 sync value 64.
05 filler pic x(4) comp-5 sync value 128.
05 filler pic x(4) comp-5 sync value 256.
05 filler pic x(4) comp-5 sync value 512.
05 filler pic x(4) comp-5 sync value 1024.
05 filler pic x(4) comp-5 sync value 2048.
05 filler pic x(4) comp-5 sync value 4096.
05 filler pic x(4) comp-5 sync value 8192.
05 filler pic x(4) comp-5 sync value 16384.
05 filler pic x(4) comp-5 sync value 32768.
05 filler pic x(4) comp-5 sync value 65536.
05 filler pic x(4) comp-5 sync
value 131072.
05 filler pic x(4) comp-5 sync
value 262144.
05 filler pic x(4) comp-5 sync
value 524288.
05 filler pic x(4) comp-5 sync
value 1048576.
05 filler pic x(4) comp-5 sync
value 2097152.
05 filler pic x(4) comp-5 sync
value 4194304.
05 filler pic x(4) comp-5 sync
value 8388608.
05 filler pic x(4) comp-5 sync
value 16777216.
05 filler pic x(4) comp-5 sync
value 33554432.
05 filler pic x(4) comp-5 sync
value 67108864.
05 filler pic x(4) comp-5 sync
value 134217728.
05 filler pic x(4) comp-5 sync
value 268435456.
05 filler pic x(4) comp-5 sync
value 536870912.
05 filler pic x(4) comp-5 sync
value 1073741824.
05 filler pic x(4) comp-5 sync
value 2147483648.
03 filler redefines ROL-PowersOf2-vals comp-5 sync.
05 ROL-PowersOf2 pic x(4) comp-5 sync
occurs 31.
*> BE-Val and BE-Rep are used by Encode and Decode
03 BE-Val pic x(4) comp-x sync.
03 BE-Rep pic x(4) redefines BE-Val.
03 Byte-Idx pic x(4) comp-5 sync.
03 InVal-Idx pic x(4) comp-5 sync.
03 InVal-Bytes.
05 InVal-Array pic x(4).
05 InVal-Byte pic x comp-5 occurs 4
redefines InVal-Array.
03 InBuf-Used pic x(4) comp-5 sync.
03 Input-Exists pic x(4) comp-5 sync.
03 Input-Extra pic x(4) comp-5 sync.
03 Final-Idx pic x(4) comp-5 sync.
03 Final-Pad pic x(4) comp-5 sync.
03 Final-Count-Hi pic x(4) comp-5 sync.
03 Final-Count-Lo pic x(4) comp-5 sync.
03 Final-Len pic x(8).
03 Digest-Byte pic x comp-5 sync.
03 Digest-ByteVal pic x redefines Digest-Byte.
03 Digest-Hi pic x comp-5 sync.
03 Digest-Lo pic x comp-5 sync.
03 Digest-String pic x(32).
77 B-TARGET pic x(4) comp-5 sync.
01 MD5-Context.
*> State (MD5_ABCD)
03 MD5-State pic x(16).
*> State as 4-byte words
03 MD5-State-Words pic x(4) comp-5
occurs 4
redefines MD5-State.
*> Number of bits mod 2**64. Note this value is
*> incorporated into the hash during finalization.
03 MD5-Count pic x(8) comp-5 sync.
*> Input buffer
03 MD5-Buffer pic x(64).
*> MD5 initialization constants
78 MD5-Init-1 value H"67452301".
78 MD5-Init-2 value H"efcdab89".
78 MD5-Init-3 value H"98badcfe".
78 MD5-Init-4 value H"10325476".
*> MD5 round rotary-shift constants
78 MD5-S11 value 7.
78 MD5-S12 value 12.
78 MD5-S13 value 17.
78 MD5-S14 value 22.
78 MD5-S21 value 5.
78 MD5-S22 value 9.
78 MD5-S23 value 14.
78 MD5-S24 value 20.
78 MD5-S31 value 4.
78 MD5-S32 value 11.
78 MD5-S33 value 16.
78 MD5-S34 value 23.
78 MD5-S41 value 6.
78 MD5-S42 value 10.
78 MD5-S43 value 15.
78 MD5-S44 value 21.
*> MD5 round additive constants
78 MD5-AC01 value H"d76aa478".
78 MD5-AC02 value H"e8c7b756".
78 MD5-AC03 value H"242070db".
78 MD5-AC04 value H"c1bdceee".
78 MD5-AC05 value H"f57c0faf".
78 MD5-AC06 value H"4787c62a".
78 MD5-AC07 value H"a8304613".
78 MD5-AC08 value H"fd469501".
78 MD5-AC09 value H"698098d8".
78 MD5-AC10 value H"8b44f7af".
78 MD5-AC11 value H"ffff5bb1".
78 MD5-AC12 value H"895cd7be".
78 MD5-AC13 value H"6b901122".
78 MD5-AC14 value H"fd987193".
78 MD5-AC15 value H"a679438e".
78 MD5-AC16 value H"49b40821".
78 MD5-AC17 value H"f61e2562".
78 MD5-AC18 value H"c040b340".
78 MD5-AC19 value H"265e5a51".
78 MD5-AC20 value H"e9b6c7aa".
78 MD5-AC21 value H"d62f105d".
78 MD5-AC22 value H"02441453".
78 MD5-AC23 value H"d8a1e681".
78 MD5-AC24 value H"e7d3fbc8".
78 MD5-AC25 value H"21e1cde6".
78 MD5-AC26 value H"c33707d6".
78 MD5-AC27 value H"f4d50d87".
78 MD5-AC28 value H"455a14ed".
78 MD5-AC29 value H"a9e3e905".
78 MD5-AC30 value H"fcefa3f8".
78 MD5-AC31 value H"676f02d9".
78 MD5-AC32 value H"8d2a4c8a".
78 MD5-AC33 value H"fffa3942".
78 MD5-AC34 value H"8771f681".
78 MD5-AC35 value H"6d9d6122".
78 MD5-AC36 value H"fde5380c".
78 MD5-AC37 value H"a4beea44".
78 MD5-AC38 value H"4bdecfa9".
78 MD5-AC39 value H"f6bb4b60".
78 MD5-AC40 value H"bebfbc70".
78 MD5-AC41 value H"289b7ec6".
78 MD5-AC42 value H"eaa127fa".
78 MD5-AC43 value H"d4ef3085".
78 MD5-AC44 value H"04881d05".
78 MD5-AC45 value H"d9d4d039".
78 MD5-AC46 value H"e6db99e5".
78 MD5-AC47 value H"1fa27cf8".
78 MD5-AC48 value H"c4ac5665".
78 MD5-AC49 value H"f4292244".
78 MD5-AC50 value H"432aff97".
78 MD5-AC51 value H"ab9423a7".
78 MD5-AC52 value H"fc93a039".
78 MD5-AC53 value H"655b59c3".
78 MD5-AC54 value H"8f0ccc92".
78 MD5-AC55 value H"ffeff47d".
78 MD5-AC56 value H"85845dd1".
78 MD5-AC57 value H"6fa87e4f".
78 MD5-AC58 value H"fe2ce6e0".
78 MD5-AC59 value H"a3014314".
78 MD5-AC60 value H"4e0811a1".
78 MD5-AC61 value H"f7537e82".
78 MD5-AC62 value H"bd3af235".
78 MD5-AC63 value H"2ad7d2bb".
78 MD5-AC64 value H"eb86d391".
01 MD5-Padding.
03 MD5-Padding-FirstByte pic x comp-5 value H"80".
03 MD5-Padding-Remainder pic x(63) value low-values.
*> For hex display
01 Hex-Chars.
03 Hex-Digits pic x(16)
value "0123456789abcdef".
03 Hex-Char pic x occurs 16
redefines Hex-Digits.
procedure division.
*> Test MD5 routines by generating and displaying digest of the file
*> specified on the command line
mainline.
*> Get input filename
accept Input-Filename from command-line
if Input-Filename = spaces
display "cobmd5: calculate MD5 digest for a file"
display "Copyright (C) 2006 Micro Focus (IP) Limited"
display "syntax: cobmd5 filename"
goback returning 1
end-if
*> Try to open it
move Open-Read to Input-Access
move Deny-None to Input-Deny
move Device-None to Input-Device
call "CBL_OPEN_FILE" using
Input-Filename
Input-Access
Input-Deny
Input-Device
Input-Handle
end-call
if return-code not = 0
move return-code to File-Stat
move FS-Byte-2 to FS-Display-2
display
"unable to open input file: "
FS-Byte-1 "/" FS-Display-2
goback returning 1
end-if
*> Get file size
move 0 to Input-Count Input-Size Input-Offset
move Flags-FSize to Input-Flags
call "CBL_READ_FILE" using
Input-Handle
Input-Size
Input-Count
Input-Flags
Input-Record
end-call
if return-code not = 0
move return-code to File-Stat
move FS-Byte-2 to FS-Display-2
display
"unable to get input file size: "
FS-Byte-1 "/" FS-Display-2
goback returning 1
end-if
*> Start MD5 digest
perform MD5-Init
*> Read from file until EOF, generating digest
move 0 to return-code
move Flags-None to Input-Flags
perform until Input-Size = 0
*> Read up to buffer size or remaining bytes
if Input-Size > length of Input-Record
move length of Input-Record to Input-Count
else
move Input-Size to Input-Count
end-if
call "CBL_READ_FILE" using
Input-Handle
Input-Offset
Input-Count
Input-Flags
Input-Record
end-call
if return-code not = 0
move return-code to File-Stat
move FS-Byte-2 to FS-Display-2
display
"unable to read input file: "
FS-Byte-1 "/" FS-Display-2
goback returning 1
end-if
*> Update offset, remaining size
add Input-Count to Input-Offset
subtract Input-Count from Input-Size
*> Update digest
move Input-Record(1 : Input-Count) to MD5-Input
move Input-Count to MD5-InLen
perform MD5-Update
end-perform
*> Finish MD5 digest
perform MD5-Final
*> Display MD5 digest
perform MD5-Print
exit program
goback returning 0.
*> Optimization note: the docs say that sections are more efficient for
*> performing than paragraphs, so I've made the inner-loop paragraphs into
*> their own sections.
*> F, G, H, and I are the basic MD5 functions.
MD5-F section.
*> compute MD5-Basic =
*> (MD5-X b-and MD5-Y) b-or ((b-not MD5-X) b-and MD5-Z)
move MD5-Y to MD5-Basic
call 'CBL_AND' using MD5-X MD5-Basic BY VALUE 4
move MD5-X to B-TARGET
call 'CBL_NOT' using B-TARGET BY VALUE 4
call 'CBL_AND' using MD5-Z B-TARGET BY VALUE 4
call 'CBL_OR' using B-TARGET MD5-Basic BY VALUE 4
exit section.
MD5-G section.
*> compute MD5-Basic =
*> (MD5-X b-and MD5-Z) b-or (MD5-Y b-and (b-not MD5-Z))
move MD5-Z to MD5-Basic
call 'CBL_AND' using MD5-X MD5-Basic BY VALUE 4
move MD5-Z to B-TARGET
call 'CBL_NOT' using B-TARGET BY VALUE 4
call 'CBL_AND' using MD5-Y B-TARGET BY VALUE 4
call 'CBL_OR' using B-TARGET MD5-Basic BY VALUE 4
exit section.
MD5-H section.
*> compute MD5-Basic =
*> (MD5-X b-xor MD5-Y) b-xor MD5-Z
move MD5-Y to B-TARGET
call 'CBL_XOR' using MD5-Z B-TARGET BY VALUE 4
move MD5-Z to MD5-Basic
call 'CBL_XOR' using B-TARGET MD5-Basic BY VALUE 4
exit section.
MD5-I section.
*> compute MD5-Basic =
*> MD5-Y b-xor (MD5-X b-or (b-not MD5-Z))
move MD5-Z to MD5-Basic
call 'CBL_NOT' using MD5-Basic BY VALUE 4
call 'CBL_OR' using MD5-X MD5-Basic BY VALUE 4
call 'CBL_XOR' using MD5-Y MD5-Basic BY VALUE 4
exit section.
*> ROL rotates a 32-bit integer left by n bits.
*> Example usage:
*> move H"12345678" to MD5-R
*> move 20 to MD5-N
*> display "before: " MD5-R
*> perform MD5-ROL
*> display "after: " MD5-RL
MD5-ROL section.
*> Determine the nth power of 2, which will be the shift multiplier, and
*> the (32-n)th power of 2, which will be the partition between the left
*> and right halves. A table lookup here is TREMENDOUSLY faster than a
*> couple of compute statements - total running time was reduced by a
*> couple of orders of magnitude. Amazing.
move ROL-PowersOf2(MD5-N) to ROL-NthPowerOf2
move ROL-PowersOf2(32 - MD5-N) to ROL-CmpPowerOf2
*> R / ROL-CmpPowerOf2 is the left half, and R mod ROL-CmpPowerOf2 is the
*> right half.
divide MD5-R by ROL-CmpPowerOf2 giving ROL-Quotient remainder ROL-Remainder
*> Swap the left and right halves by multiplying ROL-Remainder by
*> ROL-NthPowerOf2 and adding the two results
multiply ROL-Remainder by ROL-NthPowerOf2 giving MD5-RL
add ROL-Quotient to MD5-RL
exit section.
*> FF, GG, HH, and II are the MD5 transformations.
MD5-FF section.
*> compute F(b,c,d)
move MD5-B to MD5-X
move MD5-C to MD5-Y
move MD5-D to MD5-Z
perform MD5-F
*> Add F(b,c,d), v, and ac to a, modulo 2**32
add MD5-Basic to MD5-A
add MD5-V to MD5-A
add MD5-AC to MD5-A
*> Rotate a by s
move MD5-A to MD5-R
move MD5-S to MD5-N
perform MD5-ROL
*> Add b to result of rotation
add MD5-B to MD5-RL
*> Rotate the four state words: a gets d, d gets c, c gets b, b gets the
*> new value of a from the temp.
move MD5-D to MD5-A
move MD5-C to MD5-D
move MD5-B to MD5-C
move MD5-RL to MD5-B
exit section.
*> GG, HH, and II are identical to FF except with a different basic function
MD5-GG section.
move MD5-B to MD5-X
move MD5-C to MD5-Y
move MD5-D to MD5-Z
perform MD5-G
add MD5-A to MD5-Basic giving MD5-R
add MD5-V to MD5-R
add MD5-AC to MD5-R
move MD5-S to MD5-N
perform MD5-ROL
add MD5-B to MD5-RL
move MD5-D to MD5-A
move MD5-C to MD5-D
move MD5-B to MD5-C
move MD5-RL to MD5-B
exit section.
MD5-HH section.
move MD5-B to MD5-X
move MD5-C to MD5-Y
move MD5-D to MD5-Z
perform MD5-H
add MD5-A to MD5-Basic giving MD5-R
add MD5-V to MD5-R
add MD5-AC to MD5-R
move MD5-S to MD5-N
perform MD5-ROL
add MD5-B to MD5-RL
move MD5-D to MD5-A
move MD5-C to MD5-D
move MD5-B to MD5-C
move MD5-RL to MD5-B
exit section.
MD5-II section.
move MD5-B to MD5-X
move MD5-C to MD5-Y
move MD5-D to MD5-Z
perform MD5-I
add MD5-A to MD5-Basic giving MD5-R
add MD5-V to MD5-R
add MD5-AC to MD5-R
move MD5-S to MD5-N
perform MD5-ROL
add MD5-B to MD5-RL
move MD5-D to MD5-A
move MD5-C to MD5-D
move MD5-B to MD5-C
move MD5-RL to MD5-B
exit section.
*> MD5 transformation function: update the 128 bits of state using 64 bytes
*> of input.
*> This consists of four rounds, each with 16 subrounds. Each round uses
*> a different transformation (FF, GG, etc), and each subround applies it
*> to four bytes of the input, using the appropriate constants for S and
*> AC. (In the first round the input bytes are processed in order; the
*> remaining rounds vary the order using a generator, but they're always
*> in groups of 4.)
*> These rounds update A, B, C, and D.
*> At the end of the four rounds, the 128 bits of state are updated using
*> A, B, C, and D: A is added to the first four bytes (modulo 2**32), and
*> so on.
MD5-Transform section.
*> Set registers A-D from the state
move MD5-State-Words(1) to MD5-A
move MD5-State-Words(2) to MD5-B
move MD5-State-Words(3) to MD5-C
move MD5-State-Words(4) to MD5-D
*> Convert input buffer interpreted as little-endian 32-bit integers
*> to native integers
perform MD5-SetInVals
*> Round 1
move MD5-InVals(1) to MD5-V
move MD5-S11 to MD5-S
move MD5-AC01 to MD5-AC
perform MD5-FF
move MD5-InVals(2) to MD5-V
move MD5-S12 to MD5-S
move MD5-AC02 to MD5-AC
perform MD5-FF
move MD5-InVals(3) to MD5-V
move MD5-S13 to MD5-S
move MD5-AC03 to MD5-AC
perform MD5-FF
move MD5-InVals(4) to MD5-V
move MD5-S14 to MD5-S
move MD5-AC04 to MD5-AC
perform MD5-FF
move MD5-InVals(5) to MD5-V
move MD5-S11 to MD5-S
move MD5-AC05 to MD5-AC
perform MD5-FF
move MD5-InVals(6) to MD5-V
move MD5-S12 to MD5-S
move MD5-AC06 to MD5-AC
perform MD5-FF
move MD5-InVals(7) to MD5-V
move MD5-S13 to MD5-S
move MD5-AC07 to MD5-AC
perform MD5-FF
move MD5-InVals(8) to MD5-V
move MD5-S14 to MD5-S
move MD5-AC08 to MD5-AC
perform MD5-FF
move MD5-InVals(9) to MD5-V
move MD5-S11 to MD5-S
move MD5-AC09 to MD5-AC
perform MD5-FF
move MD5-InVals(10) to MD5-V
move MD5-S12 to MD5-S
move MD5-AC10 to MD5-AC
perform MD5-FF
move MD5-InVals(11) to MD5-V
move MD5-S13 to MD5-S
move MD5-AC11 to MD5-AC
perform MD5-FF
move MD5-InVals(12) to MD5-V
move MD5-S14 to MD5-S
move MD5-AC12 to MD5-AC
perform MD5-FF
move MD5-InVals(13) to MD5-V
move MD5-S11 to MD5-S
move MD5-AC13 to MD5-AC
perform MD5-FF
move MD5-InVals(14) to MD5-V
move MD5-S12 to MD5-S
move MD5-AC14 to MD5-AC
perform MD5-FF
move MD5-InVals(15) to MD5-V
move MD5-S13 to MD5-S
move MD5-AC15 to MD5-AC
perform MD5-FF
move MD5-InVals(16) to MD5-V
move MD5-S14 to MD5-S
move MD5-AC16 to MD5-AC
perform MD5-FF
*> Round 2
move MD5-InVals(2) to MD5-V
move MD5-S21 to MD5-S
move MD5-AC17 to MD5-AC
perform MD5-GG
move MD5-InVals(7) to MD5-V
move MD5-S22 to MD5-S
move MD5-AC18 to MD5-AC
perform MD5-GG
move MD5-InVals(12) to MD5-V
move MD5-S23 to MD5-S
move MD5-AC19 to MD5-AC
perform MD5-GG
move MD5-InVals(1) to MD5-V
move MD5-S24 to MD5-S
move MD5-AC20 to MD5-AC
perform MD5-GG
move MD5-InVals(6) to MD5-V
move MD5-S21 to MD5-S
move MD5-AC21 to MD5-AC
perform MD5-GG
move MD5-InVals(11) to MD5-V
move MD5-S22 to MD5-S
move MD5-AC22 to MD5-AC
perform MD5-GG
move MD5-InVals(16) to MD5-V
move MD5-S23 to MD5-S
move MD5-AC23 to MD5-AC
perform MD5-GG
move MD5-InVals(5) to MD5-V
move MD5-S24 to MD5-S
move MD5-AC24 to MD5-AC
perform MD5-GG
move MD5-InVals(10) to MD5-V
move MD5-S21 to MD5-S
move MD5-AC25 to MD5-AC
perform MD5-GG
move MD5-InVals(15) to MD5-V
move MD5-S22 to MD5-S
move MD5-AC26 to MD5-AC
perform MD5-GG
move MD5-InVals(4) to MD5-V
move MD5-S23 to MD5-S
move MD5-AC27 to MD5-AC
perform MD5-GG
move MD5-InVals(9) to MD5-V
move MD5-S24 to MD5-S
move MD5-AC28 to MD5-AC
perform MD5-GG
move MD5-InVals(14) to MD5-V
move MD5-S21 to MD5-S
move MD5-AC29 to MD5-AC
perform MD5-GG
move MD5-InVals(3) to MD5-V
move MD5-S22 to MD5-S
move MD5-AC30 to MD5-AC
perform MD5-GG
move MD5-InVals(8) to MD5-V
move MD5-S23 to MD5-S
move MD5-AC31 to MD5-AC
perform MD5-GG
move MD5-InVals(13) to MD5-V
move MD5-S24 to MD5-S
move MD5-AC32 to MD5-AC
perform MD5-GG
*> Round 3
move MD5-InVals(6) to MD5-V
move MD5-S31 to MD5-S
move MD5-AC33 to MD5-AC
perform MD5-HH
move MD5-InVals(9) to MD5-V
move MD5-S32 to MD5-S
move MD5-AC34 to MD5-AC
perform MD5-HH
move MD5-InVals(12) to MD5-V
move MD5-S33 to MD5-S
move MD5-AC35 to MD5-AC
perform MD5-HH
move MD5-InVals(15) to MD5-V
move MD5-S34 to MD5-S
move MD5-AC36 to MD5-AC
perform MD5-HH
move MD5-InVals(2) to MD5-V
move MD5-S31 to MD5-S
move MD5-AC37 to MD5-AC
perform MD5-HH
move MD5-InVals(5) to MD5-V
move MD5-S32 to MD5-S
move MD5-AC38 to MD5-AC
perform MD5-HH
move MD5-InVals(8) to MD5-V
move MD5-S33 to MD5-S
move MD5-AC39 to MD5-AC
perform MD5-HH
move MD5-InVals(11) to MD5-V
move MD5-S34 to MD5-S
move MD5-AC40 to MD5-AC
perform MD5-HH
move MD5-InVals(14) to MD5-V
move MD5-S31 to MD5-S
move MD5-AC41 to MD5-AC
perform MD5-HH
move MD5-InVals(1) to MD5-V
move MD5-S32 to MD5-S
move MD5-AC42 to MD5-AC
perform MD5-HH
move MD5-InVals(4) to MD5-V
move MD5-S33 to MD5-S
move MD5-AC43 to MD5-AC
perform MD5-HH
move MD5-InVals(7) to MD5-V
move MD5-S34 to MD5-S
move MD5-AC44 to MD5-AC
perform MD5-HH
move MD5-InVals(10) to MD5-V
move MD5-S31 to MD5-S
move MD5-AC45 to MD5-AC
perform MD5-HH
move MD5-InVals(13) to MD5-V
move MD5-S32 to MD5-S
move MD5-AC46 to MD5-AC
perform MD5-HH
move MD5-InVals(16) to MD5-V
move MD5-S33 to MD5-S
move MD5-AC47 to MD5-AC
perform MD5-HH
move MD5-InVals(3) to MD5-V
move MD5-S34 to MD5-S
move MD5-AC48 to MD5-AC
perform MD5-HH
*> Round 4
move MD5-InVals(1) to MD5-V
move MD5-S41 to MD5-S
move MD5-AC49 to MD5-AC
perform MD5-II
move MD5-InVals(8) to MD5-V
move MD5-S42 to MD5-S
move MD5-AC50 to MD5-AC
perform MD5-II
move MD5-InVals(15) to MD5-V
move MD5-S43 to MD5-S
move MD5-AC51 to MD5-AC
perform MD5-II
move MD5-InVals(6) to MD5-V
move MD5-S44 to MD5-S
move MD5-AC52 to MD5-AC
perform MD5-II
move MD5-InVals(13) to MD5-V
move MD5-S41 to MD5-S
move MD5-AC53 to MD5-AC
perform MD5-II
move MD5-InVals(4) to MD5-V
move MD5-S42 to MD5-S
move MD5-AC54 to MD5-AC
perform MD5-II
move MD5-InVals(11) to MD5-V
move MD5-S43 to MD5-S
move MD5-AC55 to MD5-AC
perform MD5-II
move MD5-InVals(2) to MD5-V
move MD5-S44 to MD5-S
move MD5-AC56 to MD5-AC
perform MD5-II
move MD5-InVals(9) to MD5-V
move MD5-S41 to MD5-S
move MD5-AC57 to MD5-AC
perform MD5-II
move MD5-InVals(16) to MD5-V
move MD5-S42 to MD5-S
move MD5-AC58 to MD5-AC
perform MD5-II
move MD5-InVals(7) to MD5-V
move MD5-S43 to MD5-S
move MD5-AC59 to MD5-AC
perform MD5-II
move MD5-InVals(14) to MD5-V
move MD5-S44 to MD5-S
move MD5-AC60 to MD5-AC
perform MD5-II
move MD5-InVals(5) to MD5-V
move MD5-S41 to MD5-S
move MD5-AC61 to MD5-AC
perform MD5-II
move MD5-InVals(12) to MD5-V
move MD5-S42 to MD5-S
move MD5-AC62 to MD5-AC
perform MD5-II
move MD5-InVals(3) to MD5-V
move MD5-S43 to MD5-S
move MD5-AC63 to MD5-AC
perform MD5-II
move MD5-InVals(10) to MD5-V
move MD5-S44 to MD5-S
move MD5-AC64 to MD5-AC
perform MD5-II
*> Update state by adding the appropriate register to each of the
*> four words of state information, modulo 2**32
add MD5-A to MD5-State-Words(1)
add MD5-B to MD5-State-Words(2)
add MD5-C to MD5-State-Words(3)
add MD5-D to MD5-State-Words(4)
exit section.
*> MD5 integer encode: translate a 32-bit integer in machine format into an
*> array of bytes in little-endian (LSB-first) ordering. What I do here is
*> move it to the big-endian (comp-x) data item BE-Val, so it has a known
*> byte order, then extract the bytes in reverse order using the byte-array
*> redefinition BE-Rep to get the bytes in little-endian order.
MD5-Encode section.
move MD5-Val to BE-Val *> convert to MSB byte ordering
perform varying Byte-Idx from 1 by 1 until Byte-Idx > 4
move BE-Rep(Byte-Idx : 1) to MD5-Buf(5 - Byte-Idx : 1)
end-perform
exit section.
*> MD5 integer decode: set a 32-bit integer in machine format from an array
*> of bytes in little-endian (LSB-first) ordering. The inverse of Encode.
MD5-Decode section.
perform varying Byte-Idx from 1 by 1 until Byte-Idx > 4
move MD5-Buf(Byte-Idx : 1) to BE-Rep(5 - Byte-Idx : 1)
end-perform
move BE-Val to MD5-Val
exit section.
*> MD5 input conversion: MD5 operates on the input as a series of 32-bit
*> unsigned little-endian integers. Here we convert the input byte buffer
*> into native-order integers.
MD5-SetInVals section.
perform varying InVal-Idx from 1 by 1 until InVal-Idx > 16
compute Byte-Idx = (InVal-Idx - 1) * 4 + 1
move MD5-Buffer(Byte-Idx : 4) to InVal-Array
*> b-or doesn't work correctly with byte-size operands, or with
*> exponentiation. Addition should be safe here.
compute MD5-InVals(InVal-Idx) =
(InVal-Byte(4) * 16777216) +
(InVal-Byte(3) * 65536) +
(InVal-Byte(2) * 256) +
(InVal-Byte(1) * 1)
end-perform
exit section.
*> MD5 initialization
MD5-Init.
move low-values to MD5-Context
move MD5-Init-1 to MD5-State-Words(1)
move MD5-Init-2 to MD5-State-Words(2)
move MD5-Init-3 to MD5-State-Words(3)
move MD5-Init-4 to MD5-State-Words(4)
exit.
*> MD5 update
*> This is the function that takes an input buffer and updates the hash with
*> it. The buffer can contain any number of bytes of data, up to the size
*> that can be represented by the length data-item. A hash is generated by
*> calling MD5-Init, then MD5-Update one or more times, then MD5-Finalize
*> when all the data has been passed to Update.
MD5-Update.
*> Compute number of bytes remaining in MD5 buffer from last chunk mod 64;
*> this is the index into the buffer where the new data starts.
compute Input-Exists = function rem( (MD5-Count / 8) 64 )
*> Update number of bits: add input length * 8 to count field, which
*> is a 64-bit unsigned integer. (MD5 incorporates the input length in
*> bits mod 2**64 into the hash during finalization.)
compute MD5-Count = MD5-Count + (MD5-InLen * 8)
*> If we have enough data to complete the partial block in the buffer,
*> do so and process it.
if Input-Exists > 0 and Input-Exists + MD5-InLen >= 64
subtract Input-Exists from 64 giving InBuf-Used
move MD5-Input(1 : InBuf-Used) to
MD5-Buffer(Input-Exists + 1 : InBuf-Used)
perform MD5-Transform
move 0 to Input-Exists *> used up old input data
else
move 0 to InBuf-Used
end-if
*> Process any remaining full blocks of new input data
perform until MD5-InLen - InBuf-Used < 64
move MD5-Input(InBuf-Used + 1 : 64) to MD5-Buffer(1 : 64)
add 64 to InBuf-Used
perform MD5-Transform
end-perform
*> If any input remains, buffer it for the next Update call or for
*> Finalize
subtract InBuf-Used from MD5-InLen giving Input-Extra
if Input-Extra > 0
move MD5-Input(InBuf-Used + 1 : Input-Extra) to
MD5-Buffer(Input-Exists + 1 : Input-Extra)
end-if
exit.
*> MD5 finalization
*> All of the input data has been processed, except for any final remaining
*> partial block. Encode the input length as a 64-bit little-endian integer.
*> Append MD5 padding to the remaining partial input (if any) so that we'll
*> have a complete block when we append the 8 bytes of the length, then
*> append the length (making a final full input block) and run the last
*> iteration of the transform.
MD5-Final.
*> Convert the length of input to a little-endian integer
divide MD5-Count by 4294967296
giving Final-Count-Hi remainder Final-Count-Lo
move Final-Count-Lo to MD5-Val
perform MD5-Encode
move MD5-Buf to Final-Len(1:4)
move Final-Count-Hi to MD5-Val
perform MD5-Encode
move MD5-Buf to Final-Len(5:4)
*> Figure out how much padding we need. We have 8 bytes of length to
*> store, and blocks are 64 bytes, and the MD5 spec requires that there's
*> always some padding, even if that means we have a whole block of
*> padding. So compute the length (in bytes - note the context stores
*> it in bits) mod 64, then subtract that from 120 (= 56 mod 64), and
*> reduce that mod 64. The result, added to the current length, will be
*> congruent to 56 modulo 64.
compute Final-Idx = function rem( (MD5-Count / 8) 64 )
compute Final-Pad = function rem( (120 - Final-Idx) 64 )
*> Pad
move MD5-Padding to MD5-Input
move Final-Pad to MD5-InLen
perform MD5-Update
*> Append length and perform final transformation
move Final-Len to MD5-Input
move 8 to MD5-InLen
perform MD5-Update
*> Extract the digest from the state: the digest is the 128-bit little-
*> endian number that represents the final value of the state
move MD5-State-Words(1) to MD5-Val
perform MD5-Encode
move MD5-Buf(1:4) to MD5-Digest(1:4)
move MD5-State-Words(2) to MD5-Val
perform MD5-Encode
move MD5-Buf(1:4) to MD5-Digest(5:4)
move MD5-State-Words(3) to MD5-Val
perform MD5-Encode
move MD5-Buf(1:4) to MD5-Digest(9:4)
move MD5-State-Words(4) to MD5-Val
perform MD5-Encode
move MD5-Buf(1:4) to MD5-Digest(13:4)
exit.
*> Print a digest
MD5-Print.
perform varying Byte-Idx from 1 by 1 until Byte-Idx > 16
move MD5-Digest(Byte-Idx : 1) to Digest-ByteVal
compute Digest-Hi = function rem( (Digest-Byte / 16) 16 ) + 1
compute Digest-Lo = function rem( Digest-Byte 16 ) + 1
move Hex-Char(Digest-Hi) to Digest-String(Byte-Idx * 2 - 1 : 1)
move Hex-Char(Digest-Lo) to Digest-String(Byte-Idx * 2 : 1)
end-perform
display Digest-String
exit.
@michaelwojcik-mf
Copy link

Someone alerted me to this - I'm the original author - and I downloaded and compiled it to check the code. It appears to be broken; the digests it outputs don't match what I get from a canonical MD5 implementation. I don't know if there's an error in one of your changes (I didn't see one in a quick skim through the code, but it was very cursory) or if the version of the source you used was wrong.

I have an updated version but it still gives the wrong value if the input size is a multiple of 56, and I haven't had an opportunity to track that down, so I haven't published it.

For now, though, unless you want to debug the issue, I'd suggest removing this, since it's giving the wrong output.

(Please note: I'm not taking any position on whether this code should be made available on Github. It was originally published on a public Micro Focus site, and you've retained the copyright message, so I don't see any problem with it, and I don't see why anyone else would. But I don't officially have the authority to license publication.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment