September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -0,0 +1,123 @@
(defpackage #:md5
(:use #:cl))
(in-package #:md5)
(require :babel)
(deftype word () '(unsigned-byte 32))
(deftype octet () '(unsigned-byte 8))
(deftype octets () '(vector octet))
(defparameter *s*
(make-array 16 :element-type 'word
:initial-contents '(7 12 17 22
5 9 14 20
4 11 16 23
6 10 15 21)))
(defun s (i)
(declare ((integer 0 63) i))
(aref *s* (+ (ash (ash i -4) 2)
(ldb (byte 2 0) i))))
(defparameter *k*
(loop with result = (make-array 64 :element-type 'word)
for i from 0 below 64
do (setf (aref result i) (floor (* (ash 1 32) (abs (sin (1+ (float i 1d0)))))))
finally (return result)))
(defun wrap (bits integer)
(declare (fixnum bits) (integer integer))
(ldb (byte bits 0) integer))
(defun integer->8octets (integer)
(declare (integer integer))
(loop for n = (wrap 64 integer) then (ash n -8)
repeat 8
collect (wrap 8 n)))
(defun pad-octets (octets)
(declare (octets octets))
(let* ((octets-length (length octets))
(zero-pad-length (- 64 (mod (+ octets-length 9) 64)))
(zero-pads (loop repeat zero-pad-length collect 0)))
(concatenate 'octets octets '(#x80) zero-pads (integer->8octets (* 8 octets-length)))))
(defun octets->words (octets)
(declare (octets octets))
(loop with result = (make-array (/ (length octets) 4) :element-type 'word)
for n from 0 below (length octets) by 4
for i from 0
do (setf (aref result i)
(dpb (aref octets (+ n 3)) (byte 8 24)
(dpb (aref octets (+ n 2)) (byte 8 16)
(dpb (aref octets (1+ n)) (byte 8 8)
(dpb (aref octets n) (byte 8 0) 0)))))
finally (return result)))
(defun words->octets (&rest words)
(loop for word of-type word in words
collect (ldb (byte 8 0) word)
collect (ldb (byte 8 8) word)
collect (ldb (byte 8 16) word)
collect (ldb (byte 8 24) word)))
(defun left-rotate (x c)
(declare (integer x) (fixnum c))
(let ((x (wrap 32 x)))
(wrap 32 (logior (ash x c)
(ash x (- c 32))))))
(defun md5 (string)
(declare (string string))
(loop with m = (octets->words (pad-octets (babel:string-to-octets string)))
with a0 of-type word = #x67452301
with b0 of-type word = #xefcdab89
with c0 of-type word = #x98badcfe
with d0 of-type word = #x10325476
for j from 0 below (length m) by 16
do (loop for a of-type word = a0 then d
and b of-type word = b0 then new-b
and c of-type word = c0 then b
and d of-type word = d0 then c
for i from 0 below 64
for new-b = (multiple-value-bind (f g)
(ecase (ash i -4)
(0 (values (wrap 32 (logior (logand b c)
(logand (lognot b) d)))
i))
(1 (values (wrap 32 (logior (logand d b)
(logand (lognot d) c)))
(wrap 4 (1+ (* 5 i)))))
(2 (values (wrap 32 (logxor b c d))
(wrap 4 (+ (* 3 i) 5))))
(3 (values (wrap 32 (logxor c
(logior b (lognot d))))
(wrap 4 (* 7 i)))))
(declare (word f g))
(wrap 32 (+ b (left-rotate (+ a f (aref *k* i) (aref m (+ j g)))
(s i)))))
finally (setf a0 (wrap 32 (+ a0 a))
b0 (wrap 32 (+ b0 b))
c0 (wrap 32 (+ c0 c))
d0 (wrap 32 (+ d0 d))))
finally (return (with-output-to-string (s)
(dolist (o (words->octets a0 b0 c0 d0))
(format s "~(~2,'0X~)" o))))))
(defun test-cases ()
(assert (string= "d41d8cd98f00b204e9800998ecf8427e"
(md5 "")))
(assert (string= "0cc175b9c0f1b6a831c399e269772661"
(md5 "a")))
(assert (string= "900150983cd24fb0d6963f7d28e17f72"
(md5 "abc")))
(assert (string= "f96b697d7cb7938d525a2f31aaf161d0"
(md5 "message digest")))
(assert (string= "c3fcd3d76192e4007dfb496cca67e13b"
(md5 "abcdefghijklmnopqrstuvwxyz")))
(assert (string= "d174ab98d277d9f5a5611c2c9f419d9f"
(md5 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")))
(assert (string= "57edf4a22be3c955ac49da2e2107b67a"
(md5 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"))))

View file

@ -1,50 +0,0 @@
module md5asm ;
import std.string ;
import std.conv ;
import std.math ;
version(D_InlineAsm_X86) {} else { static assert(0,"For X86 machine only") ; }
// ctfe construction of transform expressions
uint S(uint n) {
return [7u,12,17,22,5,9,14,20,4,11,16,23,6,10,15,21][(n/16)*4 + (n % 4)] ;
}
uint K(uint n) {
return ((n<=15)? n : (n <=31) ? 5*n+1 : (n<=47) ? (3*n+5) : (7*n)) % 16 ;
}
uint T(uint n) { return cast(uint) (abs(sin(n+1.0L))*(2UL^^32)) ; }
enum abcd = ["EAX", "EBX", "ECX", "EDX"] ;
string[] ABCD(int n) { return abcd[(64 - n)%4..4] ~ abcd[0..(64 - n)%4] ; }
string SUB(int n, string s) {
return s.replace("ax", ABCD(n)[0]).replace("bx", ABCD(n)[1]).
replace("cx", ABCD(n)[2]).replace("dx", ABCD(n)[3]) ;
}
// FF, GG, HH & II expressions part 1 (F,G,H,I)
string fghi1(int n) {
switch(n / 16) {
case 0: return // (bb & cc)|(~bb & dd)
q{mov ESI,bx;mov EDI,bx;not ESI;and EDI,cx;and ESI,dx;or EDI,ESI;add ax,EDI;} ;
case 1: return // (dd & bb)|(~dd & cc)
q{mov ESI,dx;mov EDI,dx;not ESI;and EDI,bx;and ESI,cx;or EDI,ESI;add ax,EDI;} ;
case 2: return // (bb ^ cc ^ dd)
q{mov EDI,bx;xor EDI,cx;xor EDI,dx;add ax,EDI;} ;
case 3: return // (cc ^ (bb | ~dd))
q{mov EDI,dx;not EDI;or EDI,bx;xor EDI,cx;add ax,EDI;} ;
}
}
// FF, GG, HH & II expressions part 2
string fghi2(int n) { return q{add ax,[EBP + 4*KK];add ax,TT;} ~ fghi1(n) ; }
// FF, GG, HH & II expressions prepended with previous parts & subsitute ABCD
string FGHI(int n) {
return SUB(n, fghi2(n) ~ q{rol ax,SS;add ax,bx;}) ;
// aa = ((aa << SS)|( aa >>> (32 - SS))) + bb = ROL(aa, SS) + bb
}
string EXPR(uint n) {
return FGHI(n).replace("SS", to!string(S(n))).
replace("KK", to!string(K(n))).
replace("TT", "0x"~to!string(T(n),16)) ;
}
string TRANSFORM(int n) { return (n < 63) ? EXPR(n) ~ TRANSFORM(n+1) : EXPR(n) ; }
// main steps of transform , to be mixing
const string Transform = TRANSFORM(0) ;

View file

@ -1,44 +0,0 @@
module zmd5 ;
private import md5asm ;
/*
duplicated codes from standard module
*/
private void transform(ubyte* block) {
uint[16] x;
Decode (x.ptr, block, 64);
auto pState = state.ptr ;
auto pBuffer = x.ptr ;
asm{
mov ESI, pState[EBP] ;
mov EDX,[ESI + 3*4] ;
mov ECX,[ESI + 2*4] ;
mov EBX,[ESI + 1*4] ;
mov EAX,[ESI + 0*4] ;
push EBP ;
push ESI ;
mov EBP, pBuffer[EBP] ;
}
mixin("asm { "~md5asm.Transform~"}") ;
asm{
pop ESI ;
pop EBP ;
add [ESI + 0*4],EAX ;
add [ESI + 1*4],EBX ;
add [ESI + 2*4],ECX ;
add [ESI + 3*4],EDX ;
}
x[] = 0 ;
}
/*
duplicated codes from standard module
*/

View file

@ -1,23 +0,0 @@
import std.stdio ;
import std.perf ;
private import std.md5 ;
private import zmd5 ;
private import md5asm ;
void main() {
writefln("digest(\"\") = %s", std.md5.getDigestString("")) ;
writefln("digest(\"\") = %s", zmd5.getDigestString("")) ;
const MBytes = 512 ;
float[] MSG = new float[](MBytes * 0x40000 + 13) ;
auto pf = new PerformanceCounter ;
writefln("\nTest performance / message size %dMBytes", MBytes) ;
pf.start() ; writefln("digest(MSG) = %s", std.md5.getDigestString(MSG)) ;
pf.stop() ; auto time = pf.milliseconds/1000.0 ;
writefln("std.md5 : %8.2f M/sec ( %8.2fsecs)", MBytes/time, time) ;
pf.start() ; writefln("digest(MSG) = %s", zmd5.getDigestString(MSG)) ;
pf.stop() ; time = pf.milliseconds/1000.0 ;
writefln("zmd5 : %8.2f M/sec ( %8.2fsecs)", MBytes/time, time) ;
}

View file

@ -0,0 +1,130 @@
// version 1.1.3
object MD5 {
private val INIT_A = 0x67452301
private val INIT_B = 0xEFCDAB89L.toInt()
private val INIT_C = 0x98BADCFEL.toInt()
private val INIT_D = 0x10325476
private val SHIFT_AMTS = intArrayOf(
7, 12, 17, 22,
5, 9, 14, 20,
4, 11, 16, 23,
6, 10, 15, 21
)
private val TABLE_T = IntArray(64) {
((1L shl 32) * Math.abs(Math.sin(it + 1.0))).toLong().toInt()
}
fun compute(message: ByteArray): ByteArray {
val messageLenBytes = message.size
val numBlocks = ((messageLenBytes + 8) ushr 6) + 1
val totalLen = numBlocks shl 6
val paddingBytes = ByteArray(totalLen - messageLenBytes)
paddingBytes[0] = 0x80.toByte()
var messageLenBits = (messageLenBytes shl 3).toLong()
for (i in 0..7) {
paddingBytes[paddingBytes.size - 8 + i] = messageLenBits.toByte()
messageLenBits = messageLenBits ushr 8
}
var a = INIT_A
var b = INIT_B
var c = INIT_C
var d = INIT_D
val buffer = IntArray(16)
for (i in 0 until numBlocks) {
var index = i shl 6
for (j in 0..63) {
val temp = if (index < messageLenBytes) message[index] else
paddingBytes[index - messageLenBytes]
buffer[j ushr 2] = (temp.toInt() shl 24) or (buffer[j ushr 2] ushr 8)
index++
}
val originalA = a
val originalB = b
val originalC = c
val originalD = d
for (j in 0..63) {
val div16 = j ushr 4
var f = 0
var bufferIndex = j
when (div16) {
0 -> {
f = (b and c) or (b.inv() and d)
}
1 -> {
f = (b and d) or (c and d.inv())
bufferIndex = (bufferIndex * 5 + 1) and 0x0F
}
2 -> {
f = b xor c xor d;
bufferIndex = (bufferIndex * 3 + 5) and 0x0F
}
3 -> {
f = c xor (b or d.inv());
bufferIndex = (bufferIndex * 7) and 0x0F
}
}
val temp = b + Integer.rotateLeft(a + f + buffer[bufferIndex] +
TABLE_T[j], SHIFT_AMTS[(div16 shl 2) or (j and 3)])
a = d
d = c
c = b
b = temp
}
a += originalA
b += originalB
c += originalC
d += originalD
}
val md5 = ByteArray(16)
var count = 0
for (i in 0..3) {
var n = if (i == 0) a else (if (i == 1) b else (if (i == 2) c else d))
for (j in 0..3) {
md5[count++] = n.toByte()
n = n ushr 8
}
}
return md5
}
}
fun ByteArray.toHexString(): String {
val sb = StringBuilder()
for (b in this) sb.append(String.format("%02x", b.toInt() and 0xFF))
return sb.toString()
}
fun main(args: Array<String>) {
val testStrings = arrayOf(
"",
"a",
"abc",
"message digest",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
)
println("${"hash code".padStart(34)} <== string")
for (s in testStrings) {
println("0x${MD5.compute(s.toByteArray()).toHexString()} <== \"$s\"")
}
}

View file

@ -0,0 +1,181 @@
import sequtils
const
ChunkSize = 512 div 8
SumSize = 128 div 8
proc extractChunk(msg : seq[uint8], chunk: var openarray[uint32], offset: int) =
var
srcIndex = offset
for dstIndex in 0 .. < 16:
chunk[dstIndex] = 0
for ii in 0 .. < 4:
chunk[dstIndex] = chunk[dstIndex] shr 8
chunk[dstIndex] = chunk[dstIndex] or (msg[srcIndex].uint32 shl 24)
srcIndex.inc
proc leftRotate(val: uint32, shift: int) : uint32 =
result = (val shl shift) or (val shr (32 - shift))
proc md5Sum(msg : seq[uint8]) : array[SumSize, uint8] =
const
s : array[ChunkSize, int] =
[ 7, 12, 17, 22, 7, 12, 17, 22,
7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20,
5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23,
4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21,
6, 10, 15, 21, 6, 10, 15, 21 ]
K : array[ChunkSize, uint32] =
[ 0xd76aa478'u32, 0xe8c7b756'u32, 0x242070db'u32, 0xc1bdceee'u32,
0xf57c0faf'u32, 0x4787c62a'u32, 0xa8304613'u32, 0xfd469501'u32,
0x698098d8'u32, 0x8b44f7af'u32, 0xffff5bb1'u32, 0x895cd7be'u32,
0x6b901122'u32, 0xfd987193'u32, 0xa679438e'u32, 0x49b40821'u32,
0xf61e2562'u32, 0xc040b340'u32, 0x265e5a51'u32, 0xe9b6c7aa'u32,
0xd62f105d'u32, 0x02441453'u32, 0xd8a1e681'u32, 0xe7d3fbc8'u32,
0x21e1cde6'u32, 0xc33707d6'u32, 0xf4d50d87'u32, 0x455a14ed'u32,
0xa9e3e905'u32, 0xfcefa3f8'u32, 0x676f02d9'u32, 0x8d2a4c8a'u32,
0xfffa3942'u32, 0x8771f681'u32, 0x6d9d6122'u32, 0xfde5380c'u32,
0xa4beea44'u32, 0x4bdecfa9'u32, 0xf6bb4b60'u32, 0xbebfbc70'u32,
0x289b7ec6'u32, 0xeaa127fa'u32, 0xd4ef3085'u32, 0x04881d05'u32,
0xd9d4d039'u32, 0xe6db99e5'u32, 0x1fa27cf8'u32, 0xc4ac5665'u32,
0xf4292244'u32, 0x432aff97'u32, 0xab9423a7'u32, 0xfc93a039'u32,
0x655b59c3'u32, 0x8f0ccc92'u32, 0xffeff47d'u32, 0x85845dd1'u32,
0x6fa87e4f'u32, 0xfe2ce6e0'u32, 0xa3014314'u32, 0x4e0811a1'u32,
0xf7537e82'u32, 0xbd3af235'u32, 0x2ad7d2bb'u32, 0xeb86d391'u32 ]
# Pad with 1-bit, and fill with 0's up to 448 bits mod 512
var paddedMsgSize = msg.len + 1
var remain = (msg.len + 1) mod ChunkSize
if remain > (448 div 8):
paddedMsgSize += ChunkSize - remain + (448 div 8)
else:
paddedMsgSize += (448 div 8) - remain
var paddingSize = paddedMsgSize - msg.len
var padding = newSeq[uint8](paddingSize)
padding[0] = 0x80
# Pad with number of *bits* in original message, little-endian
var sizePadding = newSeq[uint8](8)
var size = msg.len * 8
for ii in 0 .. < 4:
sizePadding[ii] = uint8(size and 0xff)
size = size shr 8
var paddedMsg = concat(msg, padding, sizePadding)
var accum = [ 0x67452301'u32, 0xefcdab89'u32, 0x98badcfe'u32, 0x10325476'u32 ]
for offset in countup(0, paddedMsg.len - 1, ChunkSize):
var A = accum[0]
var B = accum[1]
var C = accum[2]
var D = accum[3]
var F : uint32
var g : int
var M : array[16, uint32]
var dTemp : uint32
extractChunk(paddedMsg, M, offset)
# This is pretty much the same as Wikipedia's MD5 entry
for ii in 0 .. 63:
if ii <= 15:
F = (B and C) or ((not B) and D)
g = ii
elif ii <= 31:
F = (D and B) or ((not D) and C)
g = (5 * ii + 1) mod 16
elif ii <= 47:
F = B xor C xor D
g = (3 * ii + 5) mod 16
else:
F = C xor (B or (not D))
g = (7 * ii) mod 16
dTemp = D
D = C
C = B
B = B + leftRotate((A + F + K[ii] + M[g]), s[ii])
A = dTemp
accum[0] += A
accum[1] += B
accum[2] += C
accum[3] += D
# Convert four 32-bit accumulators to 16 byte array, little-endian
var dstIdx : int
for acc in accum:
var tmp = acc
for ii in 0 .. < 4:
result[dstIdx] = uint8(tmp and 0xff)
tmp = tmp shr 8
dstIdx.inc
# Only needed to convert from string to uint8 sequence
iterator items * (str : string) : uint8 =
for ii in 0 .. < len(str):
yield str[ii].uint8
proc main =
var msg = ""
var sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0xD4'u8, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E ] )
msg = "The quick brown fox jumps over the lazy dog"
sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0x9E'u8, 0x10, 0x7D, 0x9D, 0x37, 0x2B, 0xB6, 0x82,
0x6B, 0xD8, 0x1D, 0x35, 0x42, 0xA4, 0x19, 0xD6 ] )
msg = "The quick brown fox jumps over the lazy dog."
sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0xE4'u8, 0xD9, 0x09, 0xC2, 0x90, 0xD0, 0xFB, 0x1C,
0xA0, 0x68, 0xFF, 0xAD, 0xDF, 0x22, 0xCB, 0xD0 ])
# Message size around magic 512 bits
msg = "01234567890123456789012345678901234567890123456789012345678901234"
sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0xBE'u8, 0xB9, 0xF4, 0x8B, 0xC8, 0x02, 0xCA, 0x5C,
0xA0, 0x43, 0xBC, 0xC1, 0x5E, 0x21, 0x9A, 0x5A ])
msg = "0123456789012345678901234567890123456789012345678901234567890123"
sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0x7F'u8, 0x7B, 0xFD, 0x34, 0x87, 0x09, 0xDE, 0xEA,
0xAC, 0xE1, 0x9E, 0x3F, 0x53, 0x5F, 0x8C, 0x54 ])
msg = "012345678901234567890123456789012345678901234567890123456789012"
sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0xC5'u8, 0xE2, 0x56, 0x43, 0x7E, 0x75, 0x80, 0x92,
0xDB, 0xFE, 0x06, 0x28, 0x3E, 0x48, 0x90, 0x19 ])
# Message size around magic 448 bits
msg = "01234567890123456789012345678901234567890123456789012345"
sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0x8A'u8, 0xF2, 0x70, 0xB2, 0x84, 0x76, 0x10, 0xE7,
0x42, 0xB0, 0x79, 0x1B, 0x53, 0x64, 0x8C, 0x09 ])
msg = "0123456789012345678901234567890123456789012345678901234"
sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0x6E'u8, 0x7A, 0x4F, 0xC9, 0x2E, 0xB1, 0xC3, 0xF6,
0xE6, 0x52, 0x42, 0x5B, 0xCC, 0x8D, 0x44, 0xB5 ])
msg = "012345678901234567890123456789012345678901234567890123"
sum = md5Sum(toSeq(msg.items()))
assert(sum == [ 0x3D'u8, 0xFF, 0x83, 0xC8, 0xFA, 0xDD, 0x26, 0x37,
0x0D, 0x5B, 0x09, 0x84, 0x09, 0x64, 0x44, 0x57 ])
main()

View file

@ -0,0 +1,231 @@
#!/usr/bin/rexx
/* Expected results:
0xd41d8cd98f00b204e9800998ecf8427e <== ""
0x0cc175b9c0f1b6a831c399e269772661 <== "a"
0x900150983cd24fb0d6963f7d28e17f72 <== "abc"
0xf96b697d7cb7938d525a2f31aaf161d0 <== "message digest"
0xc3fcd3d76192e4007dfb496cca67e13b <== "abcdefghijklmnopqrstuvwxyz"
0xd174ab98d277d9f5a5611c2c9f419d9f <== "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
0x57edf4a22be3c955ac49da2e2107b67a <== "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
*/
md5 = .md5~new; md5~update(""); say md5~digest
md5 = .md5~new; md5~update("a"); say md5~digest
md5 = .md5~new; md5~update("abc"); say md5~digest
md5 = .md5~new; md5~update("message digest"); say md5~digest
md5 = .md5~new("abcdefghijklmnopqrstuvwxyz"); say md5~digest
md5 = .md5~new("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); md5~update("abcdefghijklmnopqrstuvwxyz0123456789"); say md5~digest
md5 = .md5~new; md5~update("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); say md5~digest
-- requires OORexx 4.2.0 or later
-- standard numeric digits of 9 is not enough in this case
::options digits 20
-- Implementation mainly based on pseudocode in https://en.wikipedia.org/wiki/MD5
::class md5 public
::method init
expose a0 b0 c0 d0 count buffer index K. s -- instance variables
use strict arg chunk=""
-- Initialize message digest
a0 = .int32~new('67452301'x,"C") -- A
b0 = .int32~new('efcdab89'x,"C") -- B
c0 = .int32~new('98badcfe'x,"C") -- C
d0 = .int32~new('10325476'x,"C") -- D
-- The 512 bit chunk buffer
buffer = .mutablebuffer~new('00'x~copies(64),64)
-- The position in the buffer to insert new input
index = 1
-- message bytecount
count = 0
-- initialize leftrotate amounts
nrs = .array~of(7,12,17,22)
s = nrs~union(nrs)~union(nrs)~union(nrs)
nrs = .array~of(5,9,14,20)
s = s~union(nrs)~union(nrs)~union(nrs)~union(nrs)
nrs = .array~of(4,11,16,23)
s = s~union(nrs)~union(nrs)~union(nrs)~union(nrs)
nrs = .array~of(6,10,15,21)
s = s~union(nrs)~union(nrs)~union(nrs)~union(nrs)
-- initialize sinus derived constants.
-- sin function from RXMath Library shipped with OORexx
-- see ::routine directive at the end of the code
do i=0 to 63
K.i = .int32~new(((2**32)*(sin(i+1,16,R)~abs))~floor)
end
-- process initial string if any
self~update(chunk)
exit
::method update
expose a0 b0 c0 d0 count buffer index K. s -- instance variables
use strict arg chunk
count += chunk~length
if chunk~length<65-index then do
buffer~overlay(chunk,index)
index += chunk~length
end
else do
split = 65-index+1
parse var chunk part =(split) chunk
buffer~overlay(part,index)
index = 65
end
-- Only proces completely filled buffer
do while index=65
A = a0
B = b0
C = c0
D = d0
do i=0 to 63
select
when i<16 then do
F = D~xor(B~and(C~xor(D)))
g = i
end
when i<32 then do
F = C~xor(D~and(B~xor(C)))
g = (5*i+1)//16
end
when i<48 then do
F = B~xor(C)~xor(D)
g = (3*i+5)//16
end
otherwise do
F = C~xor(B~or(D~xor(.int32~new('ffffffff'x,"C"))))
g = (7*i)//16
end
end
M = .int32~new(buffer~substr(g*4+1,4)~reverse,"C") -- 32bit word in little-endian
dTemp = D
D = C
C = B
B = (B + (A+F+K.i+M)~bitrotate(s[i+1]))
A = dTemp
end
a0 = a0+A
b0 = b0+B
c0 = c0+C
d0 = d0+D
parse var chunk part 65 chunk
index = part~length+1
buffer~overlay(part,1,part~length)
end
exit
::method digest
expose a0 b0 c0 d0 count buffer index K s -- instance variables
padlen = 64
if index<57 then padlen = 57-index
if index>57 then padlen = 121-index
padding = '00'x~copies(padlen)~bitor('80'x)
bitcount = count*8//2**64
lowword = bitcount//2**32
hiword = bitcount%2**32
lowcount = lowword~d2c(4)~reverse -- make it little-endian
hicount = hiword~d2c(4)~reverse -- make it little-endian
self~update(padding || lowcount || hicount)
return a0~string || b0~string || c0~string || d0~string
-- A convenience class to encapsulate operations on non OORexx-like
-- things as little-endian 32-bit words
::class int32 public
::attribute arch class
::method init class
self~arch = "little-endian" -- can be adapted for multiple architectures
-- Method to create an int32 like object
-- Input can be a OORexx whole number (type="I") or
-- a character string of 4 bytes (type="C")
-- input truncated or padded to 32-bit word/string
::method init
expose char4 int32
use strict arg input, type="Integer"
-- type must be one of "I"nteger or "C"haracter
t = type~subchar(1)~upper
select
when t=='I' then do
char4 = input~d2c(4)
int32 = char4~c2d
end
when t=='C' then do
char4 = input~right(4,'00'x)
int32 = char4~c2d
end
otherwise do
raise syntax 93.915 array("IC",type)
end
end
exit
::method xor -- wrapper for OORexx bitxor method
expose char4
use strict arg other
return .int32~new(char4~bitxor(other~char),"C")
::method and -- wrapper for OORexx bitand method
expose char4
use strict arg other
return .int32~new(char4~bitand(other~char),"C")
::method or -- wrapper for OORexx bitor method
expose char4
use strict arg other
return .int32~new(char4~bitor(other~char),"C")
::method bitleft -- OORexx shift (<<) implementation
expose char4
use strict arg bits
bstring = char4~c2x~x2b
bstring = bstring~substr(bits+1)~left(bstring~length,'0')
return .int32~new(bstring~b2x~x2d)
::method bitright -- OORexx shift (>>) implementation
expose char4
use strict arg bits, signed=.false
bstring = char4~c2x~x2b
fill = '0'
if signed then fill = bstring~subchar(1)
bstring = bstring~left(bstring~length-bits)~right(bstring~length,fill)
return .int32~new(bstring~b2x~x2d)
::method bitnot -- OORexx not implementation
expose char4
return .int32~new(char4~bitxor('ffffffff'x)~c2d,"C")
::method bitrotate -- OORexx (left) rotate method
expose char4
use strict arg bits, direction='left'
d = direction~subchar(1)~upper
if d=='L' then do
leftpart = self~bitleft(bits)
rightpart = self~bitright(32-bits)
end
else do
leftpart = self~bitleft(32-bits)
rightpart = self~bitright(bits)
end
return rightpart~or(leftpart)
::method int -- retrieve integer as number
expose int32
return int32
::method char -- retrieve integer as characters
expose char4
return char4
::method '+' -- OORexx method to add 2 .int32 instances
expose int32
use strict arg other
return .int32~new(int32+other~int)
::method string -- retrieve integer as hexadecimal string
expose char4
return char4~reverse~c2x~lower
-- Simplify function names for the necessary 'RxMath' functions
::routine sin EXTERNAL "LIBRARY rxmath RxCalcSin"

View file

@ -1,115 +1,114 @@
/*REXX program tests the MD5 procedure (below) as per a test suite the IETF RFC (1321).*/
msg.1 = /*─────MD5 test suite [from above doc].*/
msg.2 = 'a'
msg.3 = 'abc'
msg.4 = 'message digest'
msg.5 = 'abcdefghijklmnopqrstuvwxyz'
msg.6 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
msg.7 = 12345678901234567890123456789012345678901234567890123456789012345678901234567890
msg.0 = 7 /* [↑] last value doesn't need quotes.*/
do m=1 for msg.0; say /*process each of the seven messages. */
say ' in =' msg.m /*display the in message. */
say 'out =' MD5(msg.m) /* " " out " */
/*REXX program tests the MD5 procedure (below) as per a test suite from IETF RFC (1321).*/
@.1 = /*─────MD5 test suite [from above doc].*/
@.2 = 'a'
@.3 = 'abc'
@.4 = 'message digest'
@.5 = 'abcdefghijklmnopqrstuvwxyz'
@.6 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
@.7 = 12345678901234567890123456789012345678901234567890123456789012345678901234567890
@.0 = 7 /* [↑] last value doesn't need quotes.*/
do m=1 for @.0; say /*process each of the seven messages. */
say ' in =' @.m /*display the in message. */
say 'out =' MD5(@.m) /* " " out " */
end /*m*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
MD5: procedure; parse arg !; numeric digits 20 /*insure there's enough decimal digits.*/
a='67452301'x; b="efcdab89"x; c='98badcfe'x; d="10325476"x; x00='0'x; x80="80"x
a= '67452301'x; b= "efcdab89"x; c= '98badcfe'x; d= "10325476"x
#=length(!) /*length in bytes of the input message.*/
L=#*8//512; if L<448 then plus=448-L /*is the length less than 448 ? */
if L>448 then plus=960-L /* " " " greater " " */
if L=448 then plus=512 /* " " " equal to " */
x00000000='00000000'x /* [↓] a little of this, ··· */
$=! || x80 || copies( x00, plus%8 -1 )reverse(right(d2c(8 * #), 4, x00)) || x00000000
L=# *8 //512; if L<448 then plus=448 - L /*is the length less than 448 ? */
if L>448 then plus=960 - L /* " " " greater " " */
if L=448 then plus=512 /* " " " equal to " */
/* [↓] a little of this, ··· */
$=! || "80"x || copies('0'x,plus%8-1)reverse(right(d2c(8*#), 4, '0'x)) || '00000000'x
/* [↑] ··· and a little of that.*/
do j=0 to length($)%64-1 /*process the message (lots of steps).*/
a_=a; b_=b; c_=c; d_=d /*save the original values for later.*/
chunk=j*64 /*calculate the size of the chunks. */
do k=1 for 16 /*process the message in chunks. */
!.k=reverse( substr($, chunk + 1 + 4*(k-1), 4) ) /*magic stuff.*/
end /*k*/
a = .part1( a, b, c, d, 0, 7, 3614090360) /*■■■■ 1 ■■■■*/
d = .part1( d, a, b, c, 1, 12, 3905402710) /*■■■■ 2 ■■■■*/
c = .part1( c, d, a, b, 2, 17, 606105819) /*■■■■ 3 ■■■■*/
b = .part1( b, c, d, a, 3, 22, 3250441966) /*■■■■ 4 ■■■■*/
a = .part1( a, b, c, d, 4, 7, 4118548399) /*■■■■ 5 ■■■■*/
d = .part1( d, a, b, c, 5, 12, 1200080426) /*■■■■ 6 ■■■■*/
c = .part1( c, d, a, b, 6, 17, 2821735955) /*■■■■ 7 ■■■■*/
b = .part1( b, c, d, a, 7, 22, 4249261313) /*■■■■ 8 ■■■■*/
a = .part1( a, b, c, d, 8, 7, 1770035416) /*■■■■ 9 ■■■■*/
d = .part1( d, a, b, c, 9, 12, 2336552879) /*■■■■ 10 ■■■■*/
c = .part1( c, d, a, b, 10, 17, 4294925233) /*■■■■ 11 ■■■■*/
b = .part1( b, c, d, a, 11, 22, 2304563134) /*■■■■ 12 ■■■■*/
a = .part1( a, b, c, d, 12, 7, 1804603682) /*■■■■ 13 ■■■■*/
d = .part1( d, a, b, c, 13, 12, 4254626195) /*■■■■ 14 ■■■■*/
c = .part1( c, d, a, b, 14, 17, 2792965006) /*■■■■ 15 ■■■■*/
b = .part1( b, c, d, a, 15, 22, 1236535329) /*■■■■ 16 ■■■■*/
a = .part2( a, b, c, d, 1, 5, 4129170786) /*■■■■ 17 ■■■■*/
d = .part2( d, a, b, c, 6, 9, 3225465664) /*■■■■ 18 ■■■■*/
c = .part2( c, d, a, b, 11, 14, 643717713) /*■■■■ 19 ■■■■*/
b = .part2( b, c, d, a, 0, 20, 3921069994) /*■■■■ 20 ■■■■*/
a = .part2( a, b, c, d, 5, 5, 3593408605) /*■■■■ 21 ■■■■*/
d = .part2( d, a, b, c, 10, 9, 38016083) /*■■■■ 22 ■■■■*/
c = .part2( c, d, a, b, 15, 14, 3634488961) /*■■■■ 23 ■■■■*/
b = .part2( b, c, d, a, 4, 20, 3889429448) /*■■■■ 24 ■■■■*/
a = .part2( a, b, c, d, 9, 5, 568446438) /*■■■■ 25 ■■■■*/
d = .part2( d, a, b, c, 14, 9, 3275163606) /*■■■■ 26 ■■■■*/
c = .part2( c, d, a, b, 3, 14, 4107603335) /*■■■■ 27 ■■■■*/
b = .part2( b, c, d, a, 8, 20, 1163531501) /*■■■■ 28 ■■■■*/
a = .part2( a, b, c, d, 13, 5, 2850285829) /*■■■■ 29 ■■■■*/
d = .part2( d, a, b, c, 2, 9, 4243563512) /*■■■■ 30 ■■■■*/
c = .part2( c, d, a, b, 7, 14, 1735328473) /*■■■■ 31 ■■■■*/
b = .part2( b, c, d, a, 12, 20, 2368359562) /*■■■■ 32 ■■■■*/
a = .part3( a, b, c, d, 5, 4, 4294588738) /*■■■■ 33 ■■■■*/
d = .part3( d, a, b, c, 8, 11, 2272392833) /*■■■■ 34 ■■■■*/
c = .part3( c, d, a, b, 11, 16, 1839030562) /*■■■■ 35 ■■■■*/
b = .part3( b, c, d, a, 14, 23, 4259657740) /*■■■■ 36 ■■■■*/
a = .part3( a, b, c, d, 1, 4, 2763975236) /*■■■■ 37 ■■■■*/
d = .part3( d, a, b, c, 4, 11, 1272893353) /*■■■■ 38 ■■■■*/
c = .part3( c, d, a, b, 7, 16, 4139469664) /*■■■■ 39 ■■■■*/
b = .part3( b, c, d, a, 10, 23, 3200236656) /*■■■■ 40 ■■■■*/
a = .part3( a, b, c, d, 13, 4, 681279174) /*■■■■ 41 ■■■■*/
d = .part3( d, a, b, c, 0, 11, 3936430074) /*■■■■ 42 ■■■■*/
c = .part3( c, d, a, b, 3, 16, 3572445317) /*■■■■ 43 ■■■■*/
b = .part3( b, c, d, a, 6, 23, 76029189) /*■■■■ 44 ■■■■*/
a = .part3( a, b, c, d, 9, 4, 3654602809) /*■■■■ 45 ■■■■*/
d = .part3( d, a, b, c, 12, 11, 3873151461) /*■■■■ 46 ■■■■*/
c = .part3( c, d, a, b, 15, 16, 530742520) /*■■■■ 47 ■■■■*/
b = .part3( b, c, d, a, 2, 23, 3299628645) /*■■■■ 48 ■■■■*/
a = .part4( a, b, c, d, 0, 6, 4096336452) /*■■■■ 49 ■■■■*/
d = .part4( d, a, b, c, 7, 10, 1126891415) /*■■■■ 50 ■■■■*/
c = .part4( c, d, a, b, 14, 15, 2878612391) /*■■■■ 51 ■■■■*/
b = .part4( b, c, d, a, 5, 21, 4237533241) /*■■■■ 52 ■■■■*/
a = .part4( a, b, c, d, 12, 6, 1700485571) /*■■■■ 53 ■■■■*/
d = .part4( d, a, b, c, 3, 10, 2399980690) /*■■■■ 54 ■■■■*/
c = .part4( c, d, a, b, 10, 15, 4293915773) /*■■■■ 55 ■■■■*/
b = .part4( b, c, d, a, 1, 21, 2240044497) /*■■■■ 56 ■■■■*/
a = .part4( a, b, c, d, 8, 6, 1873313359) /*■■■■ 57 ■■■■*/
d = .part4( d, a, b, c, 15, 10, 4264355552) /*■■■■ 58 ■■■■*/
c = .part4( c, d, a, b, 6, 15, 2734768916) /*■■■■ 59 ■■■■*/
b = .part4( b, c, d, a, 13, 21, 1309151649) /*■■■■ 60 ■■■■*/
a = .part4( a, b, c, d, 4, 6, 4149444226) /*■■■■ 61 ■■■■*/
d = .part4( d, a, b, c, 11, 10, 3174756917) /*■■■■ 62 ■■■■*/
c = .part4( c, d, a, b, 2, 15, 718787259) /*■■■■ 63 ■■■■*/
b = .part4( b, c, d, a, 9, 21, 3951481745) /*■■■■ 64 ■■■■*/
a = .a(a_,a); b=.a(b_,b); c=.a(c_,c); d=.a(d_,d)
end /*j*/
return c2x( reverse(a) )c2x( reverse(b) )c2x( reverse(c) )c2x( reverse(d) )
do j=0 for length($) % 64 /*process the message (lots of steps).*/
a_=a; b_=b; c_=c; d_=d /*save the original values for later.*/
chunk=j * 64 /*calculate the size of the chunks. */
do k=1 for 16 /*process the message in chunks. */
!.k=reverse( substr($, chunk + 1 + 4*(k-1), 4) ) /*magic stuff.*/
end /*k*/ /*────step────*/
a = .p1( a, b, c, d, 0, 7, 3614090360) /*■■■■ 1 ■■■■*/
d = .p1( d, a, b, c, 1, 12, 3905402710) /*■■■■ 2 ■■■■*/
c = .p1( c, d, a, b, 2, 17, 606105819) /*■■■■ 3 ■■■■*/
b = .p1( b, c, d, a, 3, 22, 3250441966) /*■■■■ 4 ■■■■*/
a = .p1( a, b, c, d, 4, 7, 4118548399) /*■■■■ 5 ■■■■*/
d = .p1( d, a, b, c, 5, 12, 1200080426) /*■■■■ 6 ■■■■*/
c = .p1( c, d, a, b, 6, 17, 2821735955) /*■■■■ 7 ■■■■*/
b = .p1( b, c, d, a, 7, 22, 4249261313) /*■■■■ 8 ■■■■*/
a = .p1( a, b, c, d, 8, 7, 1770035416) /*■■■■ 9 ■■■■*/
d = .p1( d, a, b, c, 9, 12, 2336552879) /*■■■■ 10 ■■■■*/
c = .p1( c, d, a, b, 10, 17, 4294925233) /*■■■■ 11 ■■■■*/
b = .p1( b, c, d, a, 11, 22, 2304563134) /*■■■■ 12 ■■■■*/
a = .p1( a, b, c, d, 12, 7, 1804603682) /*■■■■ 13 ■■■■*/
d = .p1( d, a, b, c, 13, 12, 4254626195) /*■■■■ 14 ■■■■*/
c = .p1( c, d, a, b, 14, 17, 2792965006) /*■■■■ 15 ■■■■*/
b = .p1( b, c, d, a, 15, 22, 1236535329) /*■■■■ 16 ■■■■*/
a = .p2( a, b, c, d, 1, 5, 4129170786) /*■■■■ 17 ■■■■*/
d = .p2( d, a, b, c, 6, 9, 3225465664) /*■■■■ 18 ■■■■*/
c = .p2( c, d, a, b, 11, 14, 643717713) /*■■■■ 19 ■■■■*/
b = .p2( b, c, d, a, 0, 20, 3921069994) /*■■■■ 20 ■■■■*/
a = .p2( a, b, c, d, 5, 5, 3593408605) /*■■■■ 21 ■■■■*/
d = .p2( d, a, b, c, 10, 9, 38016083) /*■■■■ 22 ■■■■*/
c = .p2( c, d, a, b, 15, 14, 3634488961) /*■■■■ 23 ■■■■*/
b = .p2( b, c, d, a, 4, 20, 3889429448) /*■■■■ 24 ■■■■*/
a = .p2( a, b, c, d, 9, 5, 568446438) /*■■■■ 25 ■■■■*/
d = .p2( d, a, b, c, 14, 9, 3275163606) /*■■■■ 26 ■■■■*/
c = .p2( c, d, a, b, 3, 14, 4107603335) /*■■■■ 27 ■■■■*/
b = .p2( b, c, d, a, 8, 20, 1163531501) /*■■■■ 28 ■■■■*/
a = .p2( a, b, c, d, 13, 5, 2850285829) /*■■■■ 29 ■■■■*/
d = .p2( d, a, b, c, 2, 9, 4243563512) /*■■■■ 30 ■■■■*/
c = .p2( c, d, a, b, 7, 14, 1735328473) /*■■■■ 31 ■■■■*/
b = .p2( b, c, d, a, 12, 20, 2368359562) /*■■■■ 32 ■■■■*/
a = .p3( a, b, c, d, 5, 4, 4294588738) /*■■■■ 33 ■■■■*/
d = .p3( d, a, b, c, 8, 11, 2272392833) /*■■■■ 34 ■■■■*/
c = .p3( c, d, a, b, 11, 16, 1839030562) /*■■■■ 35 ■■■■*/
b = .p3( b, c, d, a, 14, 23, 4259657740) /*■■■■ 36 ■■■■*/
a = .p3( a, b, c, d, 1, 4, 2763975236) /*■■■■ 37 ■■■■*/
d = .p3( d, a, b, c, 4, 11, 1272893353) /*■■■■ 38 ■■■■*/
c = .p3( c, d, a, b, 7, 16, 4139469664) /*■■■■ 39 ■■■■*/
b = .p3( b, c, d, a, 10, 23, 3200236656) /*■■■■ 40 ■■■■*/
a = .p3( a, b, c, d, 13, 4, 681279174) /*■■■■ 41 ■■■■*/
d = .p3( d, a, b, c, 0, 11, 3936430074) /*■■■■ 42 ■■■■*/
c = .p3( c, d, a, b, 3, 16, 3572445317) /*■■■■ 43 ■■■■*/
b = .p3( b, c, d, a, 6, 23, 76029189) /*■■■■ 44 ■■■■*/
a = .p3( a, b, c, d, 9, 4, 3654602809) /*■■■■ 45 ■■■■*/
d = .p3( d, a, b, c, 12, 11, 3873151461) /*■■■■ 46 ■■■■*/
c = .p3( c, d, a, b, 15, 16, 530742520) /*■■■■ 47 ■■■■*/
b = .p3( b, c, d, a, 2, 23, 3299628645) /*■■■■ 48 ■■■■*/
a = .p4( a, b, c, d, 0, 6, 4096336452) /*■■■■ 49 ■■■■*/
d = .p4( d, a, b, c, 7, 10, 1126891415) /*■■■■ 50 ■■■■*/
c = .p4( c, d, a, b, 14, 15, 2878612391) /*■■■■ 51 ■■■■*/
b = .p4( b, c, d, a, 5, 21, 4237533241) /*■■■■ 52 ■■■■*/
a = .p4( a, b, c, d, 12, 6, 1700485571) /*■■■■ 53 ■■■■*/
d = .p4( d, a, b, c, 3, 10, 2399980690) /*■■■■ 54 ■■■■*/
c = .p4( c, d, a, b, 10, 15, 4293915773) /*■■■■ 55 ■■■■*/
b = .p4( b, c, d, a, 1, 21, 2240044497) /*■■■■ 56 ■■■■*/
a = .p4( a, b, c, d, 8, 6, 1873313359) /*■■■■ 57 ■■■■*/
d = .p4( d, a, b, c, 15, 10, 4264355552) /*■■■■ 58 ■■■■*/
c = .p4( c, d, a, b, 6, 15, 2734768916) /*■■■■ 59 ■■■■*/
b = .p4( b, c, d, a, 13, 21, 1309151649) /*■■■■ 60 ■■■■*/
a = .p4( a, b, c, d, 4, 6, 4149444226) /*■■■■ 61 ■■■■*/
d = .p4( d, a, b, c, 11, 10, 3174756917) /*■■■■ 62 ■■■■*/
c = .p4( c, d, a, b, 2, 15, 718787259) /*■■■■ 63 ■■■■*/
b = .p4( b, c, d, a, 9, 21, 3951481745) /*■■■■ 64 ■■■■*/
a = .a(a_, a); b=.a(b_, b); c=.a(c_, c); d=.a(d_, d)
end /*j*/
return .rx(a).rx(b).rx(c).rx(d) /*same as: .rx(a) || .rx(b) || ··· */
/*──────────────────────────────────────────────────────────────────────────────────────*/
.a: return right(d2c(c2d(arg(1)) + c2d(arg(2))), 4, '0'x)
.h: return bitxor(bitxor(arg(1), arg(2)), arg(3))
.i: return bitxor(arg(2), bitor(arg(1), bitxor(arg(3), 'ffffffff'x)))
.f: return bitor(bitand(arg(1),arg(2)), bitand(bitxor(arg(1), 'ffffffff'x), arg(3)))
.g: return bitor(bitand(arg(1),arg(3)), bitand(arg(2), bitxor(arg(3), 'ffffffff'x)))
.Lr: procedure; parse arg _,#; if #==0 then return _ /*left rotate.*/
?=x2b(c2x(_)); return x2c(b2x(right(? || left(?, #), length(?))))
.part1: procedure expose !.; parse arg w,x,y,z,n,m,_; n=n+1
return .a(.Lr(right(d2c(_+c2d(w)+c2d(.f(x,y,z))+c2d(!.n)),4,'0'x),m),x)
.part2: procedure expose !.; parse arg w,x,y,z,n,m,_; n=n+1
return .a(.Lr(right(d2c(_+c2d(w)+c2d(.g(x,y,z))+c2d(!.n)),4,'0'x),m),x)
.part3: procedure expose !.; parse arg w,x,y,z,n,m,_; n=n+1
return .a(.Lr(right(d2c(_+c2d(w)+c2d(.h(x,y,z))+c2d(!.n)),4,'0'x),m),x)
.part4: procedure expose !.; parse arg w,x,y,z,n,m,_; n=n+1
return .a(.Lr(right(d2c(c2d(w)+c2d(.i(x,y,z))+c2d(!.n)+_),4,'0'x),m),x)
.a: return right( d2c( c2d( arg(1) ) + c2d( arg(2) ) ), 4, '0'x)
.h: return bitxor( bitxor( arg(1), arg(2) ), arg(3) )
.i: return bitxor( arg(2), bitor(arg(1), bitxor(arg(3), 'ffffffff'x) ) )
.f: return bitor( bitand(arg(1), arg(2)), bitand(bitxor(arg(1), 'ffffffff'x), arg(3) ) )
.g: return bitor( bitand(arg(1), arg(3)), bitand(arg(2), bitxor(arg(3), 'ffffffff'x) ) )
.rx: return c2x( reverse( arg(1) ) )
.Lr: procedure; parse arg _,#; if #==0 then return _ /*left bit rotate.*/
?=x2b(c2x(_)); return x2c( b2x( right(? || left(?, #), length(?) ) ) )
.p1: procedure expose !.; parse arg w,x,y,z,n,m,_; n=n + 1
return .a(.Lr(right(d2c(_+c2d(w) + c2d(.f(x,y,z)) + c2d(!.n)),4,'0'x),m),x)
.p2: procedure expose !.; parse arg w,x,y,z,n,m,_; n=n + 1
return .a(.Lr(right(d2c(_+c2d(w) + c2d(.g(x,y,z)) + c2d(!.n)),4,'0'x),m),x)
.p3: procedure expose !.; parse arg w,x,y,z,n,m,_; n=n + 1
return .a(.Lr(right(d2c(_+c2d(w) + c2d(.h(x,y,z)) + c2d(!.n)),4,'0'x),m),x)
.p4: procedure expose !.; parse arg w,x,y,z,n,m,_; n=n + 1
return .a(.Lr(right(d2c(c2d(w) + c2d(.i(x,y,z)) + c2d(!.n)+_),4,'0'x),m),x)

View file

@ -18,7 +18,7 @@ class MD5(String msg) {
[6, 10, 15, 21] * 4,
].flat
const T = 64.of {|i| floor(abs(sin(i)) * 1<<32) }
const T = 64.of {|i| floor(abs(sin(i+1)) * 1<<32) }
const K = [
^16 -> map {|n| n },
@ -45,7 +45,7 @@ class MD5(String msg) {
var padded = [msg..., 128, [0] * (-(floor(bits / 8) + 1 + 8) % 64)].flat
gather {
padded.each_slice(4, {|a|
padded.each_slice(4, {|*a|
take(radix(256, a))
})
take(little_endian(32, 2, [bits]))
@ -66,7 +66,7 @@ class MD5(String msg) {
), B, C)
}
for k,v in ([A, B, C, D].pairs) {
for k,v in ([A, B, C, D].kv) {
H[k] = block(H[k], v)
}

View file

@ -0,0 +1,267 @@
section .text
org 0x100
mov di, md5_for_display
mov si, test_input_1
mov cx, test_input_1_len
call compute_md5
call display_md5
mov si, test_input_2
mov cx, test_input_2_len
call compute_md5
call display_md5
mov si, test_input_3
mov cx, test_input_3_len
call compute_md5
call display_md5
mov si, test_input_4
mov cx, test_input_4_len
call compute_md5
call display_md5
mov si, test_input_5
mov cx, test_input_5_len
call compute_md5
call display_md5
mov si, test_input_6
mov cx, test_input_6_len
call compute_md5
call display_md5
mov si, test_input_7
mov cx, test_input_7_len
call compute_md5
call display_md5
mov ax, 0x4c00
int 21h
md5_for_display times 16 db 0
HEX_CHARS db '0123456789ABCDEF'
display_md5:
mov ah, 9
mov dx, display_str_1
int 0x21
push cx
push si
mov cx, 16
mov si, di
xor bx, bx
.loop:
lodsb
mov bl, al
and bl, 0x0F
push bx
mov bl, al
shr bx, 4
mov ah, 2
mov dl, [HEX_CHARS + bx]
int 0x21
pop bx
mov dl, [HEX_CHARS + bx]
int 0x21
dec cx
jnz .loop
mov ah, 9
mov dx, display_str_2
int 0x21
pop si
pop cx
test cx, cx
jz do_newline
mov ah, 2
display_string:
lodsb
mov dl, al
int 0x21
dec cx
jnz display_string
do_newline:
mov ah, 9
mov dx, display_str_3
int 0x21
ret;
compute_md5:
; si --> input bytes, cx = input len, di --> 16-byte output buffer
; assumes all in the same segment
cld
pusha
push di
push si
mov [message_len], cx
mov bx, cx
shr bx, 6
mov [ending_bytes_block_num], bx
mov [num_blocks], bx
inc word [num_blocks]
shl bx, 6
add si, bx
and cx, 0x3f
push cx
mov di, ending_bytes
rep movsb
mov al, 0x80
stosb
pop cx
sub cx, 55
neg cx
jge add_padding
add cx, 64
inc word [num_blocks]
add_padding:
mov al, 0
rep stosb
xor eax, eax
mov ax, [message_len]
shl eax, 3
mov cx, 8
store_message_len:
stosb
shr eax, 8
dec cx
jnz store_message_len
pop si
mov [md5_a], dword INIT_A
mov [md5_b], dword INIT_B
mov [md5_c], dword INIT_C
mov [md5_d], dword INIT_D
block_loop:
push cx
cmp cx, [ending_bytes_block_num]
jne backup_abcd
; switch buffers if towards the end where padding needed
mov si, ending_bytes
backup_abcd:
push dword [md5_d]
push dword [md5_c]
push dword [md5_b]
push dword [md5_a]
xor cx, cx
xor eax, eax
main_loop:
push cx
mov ax, cx
shr ax, 4
test al, al
jz pass0
cmp al, 1
je pass1
cmp al, 2
je pass2
; pass3
mov eax, [md5_c]
mov ebx, [md5_d]
not ebx
or ebx, [md5_b]
xor eax, ebx
jmp do_rotate
pass0:
mov eax, [md5_b]
mov ebx, eax
and eax, [md5_c]
not ebx
and ebx, [md5_d]
or eax, ebx
jmp do_rotate
pass1:
mov eax, [md5_d]
mov edx, eax
and eax, [md5_b]
not edx
and edx, [md5_c]
or eax, edx
jmp do_rotate
pass2:
mov eax, [md5_b]
xor eax, [md5_c]
xor eax, [md5_d]
do_rotate:
add eax, [md5_a]
mov bx, cx
shl bx, 1
mov bx, [BUFFER_INDEX_TABLE + bx]
add eax, [si + bx]
mov bx, cx
shl bx, 2
add eax, dword [TABLE_T + bx]
mov bx, cx
ror bx, 2
shr bl, 2
rol bx, 2
mov cl, [SHIFT_AMTS + bx]
rol eax, cl
add eax, [md5_b]
push eax
push dword [md5_b]
push dword [md5_c]
push dword [md5_d]
pop dword [md5_a]
pop dword [md5_d]
pop dword [md5_c]
pop dword [md5_b]
pop cx
inc cx
cmp cx, 64
jb main_loop
; add to original values
pop eax
add [md5_a], eax
pop eax
add [md5_b], eax
pop eax
add [md5_c], eax
pop eax
add [md5_d], eax
; advance pointers
add si, 64
pop cx
inc cx
cmp cx, [num_blocks]
jne block_loop
mov cx, 4
mov si, md5_a
pop di
rep movsd
popa
ret
section .data
INIT_A equ 0x67452301
INIT_B equ 0xEFCDAB89
INIT_C equ 0x98BADCFE
INIT_D equ 0x10325476
SHIFT_AMTS db 7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21
TABLE_T dd 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501, 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821, 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8, 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A, 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70, 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665, 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1, 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391
BUFFER_INDEX_TABLE dw 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 4, 24, 44, 0, 20, 40, 60, 16, 36, 56, 12, 32, 52, 8, 28, 48, 20, 32, 44, 56, 4, 16, 28, 40, 52, 0, 12, 24, 36, 48, 60, 8, 0, 28, 56, 20, 48, 12, 40, 4, 32, 60, 24, 52, 16, 44, 8, 36
ending_bytes_block_num dw 0
ending_bytes times 128 db 0
message_len dw 0
num_blocks dw 0
md5_a dd 0
md5_b dd 0
md5_c dd 0
md5_d dd 0
display_str_1 db '0x$'
display_str_2 db ' <== "$'
display_str_3 db '"', 13, 10, '$'
test_input_1:
test_input_1_len equ $ - test_input_1
test_input_2 db 'a'
test_input_2_len equ $ - test_input_2
test_input_3 db 'abc'
test_input_3_len equ $ - test_input_3
test_input_4 db 'message digest'
test_input_4_len equ $ - test_input_4
test_input_5 db 'abcdefghijklmnopqrstuvwxyz'
test_input_5_len equ $ - test_input_5
test_input_6 db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
test_input_6_len equ $ - test_input_6
test_input_7 db '12345678901234567890123456789012345678901234567890123456789012345678901234567890'
test_input_7_len equ $ - test_input_7