some more touchups
svn: r2916
This commit is contained in:
parent
fd96a129f3
commit
283cb0dffd
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
(provide md5)
|
(provide md5)
|
||||||
|
|
||||||
|
;;; Copyright (c) 2006, PLT Scheme Inc.
|
||||||
;;; Copyright (c) 2002, Jens Axel Soegaard
|
;;; Copyright (c) 2002, Jens Axel Soegaard
|
||||||
;;;
|
;;;
|
||||||
;;; Permission to copy this software, in whole or in part, to use this
|
;;; Permission to copy this software, in whole or in part, to use this
|
||||||
|
@ -17,13 +18,6 @@
|
||||||
;; The algorithm was invented by Ron Rivest, RSA Security, INC.
|
;; The algorithm was invented by Ron Rivest, RSA Security, INC.
|
||||||
;; Reference: RFC 1321, <http://www.faqs.org/rfcs/rfc1321.html>
|
;; Reference: RFC 1321, <http://www.faqs.org/rfcs/rfc1321.html>
|
||||||
|
|
||||||
;;; Technicalities
|
|
||||||
;; The algorithm is designed to be efficiently implemented
|
|
||||||
;; using 32 bit arithmetic. If your implementation supports
|
|
||||||
;; 32 bit arithmetic directly, you should substitute the
|
|
||||||
;; portable 32 operations with primitives of your implementation.
|
|
||||||
;; See the PLT version below for an example.
|
|
||||||
|
|
||||||
;;; History
|
;;; History
|
||||||
; 14-10-2002 /jas
|
; 14-10-2002 /jas
|
||||||
; - Bored. Initial attempt. Done. Well, except for faulty output.
|
; - Bored. Initial attempt. Done. Well, except for faulty output.
|
||||||
|
@ -79,6 +73,7 @@
|
||||||
|
|
||||||
; 11-5-2006 / Eli
|
; 11-5-2006 / Eli
|
||||||
; - Cleaned up a lot, removed Larceny-isms
|
; - Cleaned up a lot, removed Larceny-isms
|
||||||
|
; - Heavy optimization: not consing anything throughout the loop
|
||||||
|
|
||||||
|
|
||||||
;;; Word aritmetic (32 bit)
|
;;; Word aritmetic (32 bit)
|
||||||
|
@ -102,9 +97,8 @@
|
||||||
(if (<= 0 n 4294967296)
|
(if (<= 0 n 4294967296)
|
||||||
(cons (quotient n 65536) (remainder n 65536))
|
(cons (quotient n 65536) (remainder n 65536))
|
||||||
(error 'word "out of range: ~e" n)))]
|
(error 'word "out of range: ~e" n)))]
|
||||||
;; to use when the number is known to be in range
|
;; use when the number is known to be in range
|
||||||
[(word #:safe #:new c) #'(word #:new #:safe c)]
|
[(word #:new+safe c)
|
||||||
[(word #:new #:safe c)
|
|
||||||
#'(let ([n c]) (cons (quotient n 65536) (remainder n 65536)))]
|
#'(let ([n c]) (cons (quotient n 65536) (remainder n 65536)))]
|
||||||
;; default form: compute at compile-time if possible
|
;; default form: compute at compile-time if possible
|
||||||
[(word c)
|
[(word c)
|
||||||
|
@ -131,38 +125,30 @@
|
||||||
(define (word+=! a b)
|
(define (word+=! a b)
|
||||||
(let ([t1 (+ (car a) (car b))]
|
(let ([t1 (+ (car a) (car b))]
|
||||||
[t2 (+ (cdr a) (cdr b))])
|
[t2 (+ (cdr a) (cdr b))])
|
||||||
(set-car! a (bitwise-and (+ t1 (arithmetic-shift t2 -16)) 65535))
|
(cons! a
|
||||||
(set-cdr! a (bitwise-and t2 65535))
|
(bitwise-and (+ t1 (arithmetic-shift t2 -16)) 65535)
|
||||||
a))
|
(bitwise-and t2 65535))))
|
||||||
|
|
||||||
(define word<<<!
|
(define word<<<!
|
||||||
(let* ([masks '#(#x0 #x1 #x3 #x7 #xF #x1F #x3F #x7F #xFF #x1FF #x3FF #x7FF
|
(let* ([masks '#(#x0 #x1 #x3 #x7 #xF #x1F #x3F #x7F #xFF #x1FF #x3FF #x7FF
|
||||||
#xFFF #x1FFF #x3FFF #x7FFF #xFFFF)])
|
#xFFF #x1FFF #x3FFF #x7FFF #xFFFF)])
|
||||||
(lambda (a s)
|
(lambda (a s)
|
||||||
(let ([rot (lambda (hi lo s)
|
(let-values ([(hi lo s)
|
||||||
|
(cond [(< 0 s 16) (values (car a) (cdr a) s)]
|
||||||
|
[(< s 32) (values (cdr a) (car a) (- s 16))]
|
||||||
|
[else (error 'word<<< "shift out of range: ~e"
|
||||||
|
s)])])
|
||||||
(cons! a
|
(cons! a
|
||||||
(bitwise-ior
|
(bitwise-ior
|
||||||
(arithmetic-shift
|
(arithmetic-shift (bitwise-and hi (vector-ref masks (- 16 s)))
|
||||||
(bitwise-and hi (vector-ref masks (- 16 s)))
|
|
||||||
s)
|
s)
|
||||||
(bitwise-and (arithmetic-shift lo (- s 16))
|
(bitwise-and (arithmetic-shift lo (- s 16))
|
||||||
(vector-ref masks s)))
|
(vector-ref masks s)))
|
||||||
(bitwise-ior
|
(bitwise-ior
|
||||||
(arithmetic-shift
|
(arithmetic-shift (bitwise-and lo (vector-ref masks (- 16 s)))
|
||||||
(bitwise-and lo (vector-ref masks (- 16 s)))
|
|
||||||
s)
|
s)
|
||||||
(bitwise-and (arithmetic-shift hi (- s 16))
|
(bitwise-and (arithmetic-shift hi (- s 16))
|
||||||
(vector-ref masks s)))))])
|
(vector-ref masks s))))))))
|
||||||
(cond [(< 0 s 16) (rot (car a) (cdr a) s)]
|
|
||||||
[(< s 32) (rot (cdr a) (car a) (- s 16))]
|
|
||||||
[else (error 'word<<< "shift out of range: ~e" s)])))))
|
|
||||||
|
|
||||||
;; word->bytesl : word -> (list byte byte byte byte), little endian!
|
|
||||||
(define (word->bytesl w)
|
|
||||||
(list (bitwise-and (cdr w) 255)
|
|
||||||
(bitwise-and (arithmetic-shift (cdr w) -8) 255)
|
|
||||||
(bitwise-and (car w) 255)
|
|
||||||
(bitwise-and (arithmetic-shift (car w) -8) 255)))
|
|
||||||
|
|
||||||
;; Bytes and words
|
;; Bytes and words
|
||||||
;; The least significant byte of a word is the first
|
;; The least significant byte of a word is the first
|
||||||
|
@ -171,15 +157,16 @@
|
||||||
;; bytes->word-vector! : vector byte-string -> void
|
;; bytes->word-vector! : vector byte-string -> void
|
||||||
(define (bytes->word-vector! result l-raw)
|
(define (bytes->word-vector! result l-raw)
|
||||||
;; assumption: always getting a byte-string with 64 places
|
;; assumption: always getting a byte-string with 64 places
|
||||||
(unless (= 64 (bytes-length l-raw))
|
;; (unless (= 64 (bytes-length l-raw))
|
||||||
(error 'bytes->word-vector! "something bad happened"))
|
;; (error 'bytes->word-vector! "something bad happened"))
|
||||||
(let loop ([n 15])
|
(let loop ([n 15])
|
||||||
(when (<= 0 n)
|
(when (<= 0 n)
|
||||||
(let ([w (vector-ref result n)] [n (* 4 n)])
|
(let ([m (* 4 n)])
|
||||||
(set-car! w (+ (bytes-ref l-raw (+ 2 n))
|
(cons! (vector-ref result n)
|
||||||
(* 256 (bytes-ref l-raw (+ 3 n)))))
|
(+ (bytes-ref l-raw (+ 2 m))
|
||||||
(set-cdr! w (+ (bytes-ref l-raw n)
|
(* 256 (bytes-ref l-raw (+ 3 m))))
|
||||||
(* 256 (bytes-ref l-raw (+ 1 n))))))
|
(+ (bytes-ref l-raw m)
|
||||||
|
(* 256 (bytes-ref l-raw (+ 1 m))))))
|
||||||
(loop (sub1 n)))))
|
(loop (sub1 n)))))
|
||||||
|
|
||||||
(define empty-port (open-input-bytes #""))
|
(define empty-port (open-input-bytes #""))
|
||||||
|
@ -190,8 +177,9 @@
|
||||||
;; 32-bit words when the port is exhausted it returns #f for the port and the
|
;; 32-bit words when the port is exhausted it returns #f for the port and the
|
||||||
;; last few bytes padded
|
;; last few bytes padded
|
||||||
(define (read-block! a-port done result)
|
(define (read-block! a-port done result)
|
||||||
(define (write-words! done buf)
|
(define-syntax write-words!
|
||||||
(bytes->word-vector! result (step2 (* 8 done) buf)))
|
(syntax-rules ()
|
||||||
|
[(_ done buf) (bytes->word-vector! result (step2 (* 8 done) buf))]))
|
||||||
(let ([l-raw (read-bytes 512/8 a-port)])
|
(let ([l-raw (read-bytes 512/8 a-port)])
|
||||||
(cond
|
(cond
|
||||||
;; File size was a multiple of 512 bits, or we're doing one more round
|
;; File size was a multiple of 512 bits, or we're doing one more round
|
||||||
|
@ -237,8 +225,7 @@
|
||||||
(let ([a-port
|
(let ([a-port
|
||||||
(cond [(bytes? a-thing) (open-input-bytes a-thing)]
|
(cond [(bytes? a-thing) (open-input-bytes a-thing)]
|
||||||
[(input-port? a-thing) a-thing]
|
[(input-port? a-thing) a-thing]
|
||||||
[else (raise-type-error
|
[else (raise-type-error 'md5 "input-port or bytes" a-thing)])])
|
||||||
'md5 "input-port or bytes" a-thing)])])
|
|
||||||
(step5 (step4 a-port))))
|
(step5 (step4 a-port))))
|
||||||
|
|
||||||
;; Step 1 - Append Padding Bits
|
;; Step 1 - Append Padding Bits
|
||||||
|
@ -248,11 +235,11 @@
|
||||||
;; step1 : bytes -> bytes
|
;; step1 : bytes -> bytes
|
||||||
|
|
||||||
(define (step1 message)
|
(define (step1 message)
|
||||||
(let* ([z-b-t-a (modulo (- 448 (* 8 (bytes-length message))) 512)]
|
(let* ([nbytes (modulo (- 448/8 (bytes-length message)) 512/8)]
|
||||||
[zero-bits-to-append (if (zero? z-b-t-a) 512 z-b-t-a)])
|
[nbytes (if (zero? nbytes) 512/8 nbytes)])
|
||||||
(bytes-append message
|
(bytes-append message
|
||||||
#"\x80" ; the 1 bit byte => one less 0 bytes to append
|
#"\x80" ; the 1 bit byte => one less 0 bytes to append
|
||||||
(make-bytes (quotient (- zero-bits-to-append 1) 8) 0))))
|
(make-bytes (sub1 nbytes) 0))))
|
||||||
|
|
||||||
;; Step 2 - Append Length
|
;; Step 2 - Append Length
|
||||||
;; A 64 bit representation of the bit length b of the message before
|
;; A 64 bit representation of the bit length b of the message before
|
||||||
|
@ -274,7 +261,7 @@
|
||||||
|
|
||||||
;; Step 4 - Process Message in 16-Word Blocks
|
;; Step 4 - Process Message in 16-Word Blocks
|
||||||
;; For each 16 word block, go through a round one to four.
|
;; For each 16 word block, go through a round one to four.
|
||||||
;; step4 : (list word) -> "(list word word word word)"
|
;; step4 : input-port -> (list word word word word)
|
||||||
|
|
||||||
;; Step 3 :-) (magic constants)
|
;; Step 3 :-) (magic constants)
|
||||||
(define (step4 a-port)
|
(define (step4 a-port)
|
||||||
|
@ -283,10 +270,10 @@
|
||||||
(vector (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0)
|
(vector (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0)
|
||||||
(cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0)
|
(cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0)
|
||||||
(cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0)))
|
(cons 0 0) (cons 0 0) (cons 0 0) (cons 0 0)))
|
||||||
(define A (word #:new #:safe #x67452301))
|
(define A (word #:new+safe #x67452301))
|
||||||
(define B (word #:new #:safe #xefcdab89))
|
(define B (word #:new+safe #xefcdab89))
|
||||||
(define C (word #:new #:safe #x98badcfe))
|
(define C (word #:new+safe #x98badcfe))
|
||||||
(define D (word #:new #:safe #x10325476))
|
(define D (word #:new+safe #x10325476))
|
||||||
(define AA (cons 0 0))
|
(define AA (cons 0 0))
|
||||||
(define BB (cons 0 0))
|
(define BB (cons 0 0))
|
||||||
(define CC (cons 0 0))
|
(define CC (cons 0 0))
|
||||||
|
@ -434,17 +421,19 @@
|
||||||
;; Step 5 - Output
|
;; Step 5 - Output
|
||||||
;; To finish up, we convert the word to hexadecimal string
|
;; To finish up, we convert the word to hexadecimal string
|
||||||
;; - and make sure they end up in order.
|
;; - and make sure they end up in order.
|
||||||
;; step5 : "(list word word word word)" -> string
|
;; step5 : (list word word word word) -> string
|
||||||
|
|
||||||
(define (step5 l)
|
(define (step5 l)
|
||||||
|
|
||||||
(define hex #(48 49 50 51 52 53 54 55 56 57 97 98 99 100 101 102))
|
(define hex #(48 49 50 51 52 53 54 55 56 57 97 98 99 100 101 102))
|
||||||
|
;; word->bytesl : word -> (list byte),
|
||||||
(define (number->hex n)
|
;; returns a little endian result, but each byte is hi half and then lo half
|
||||||
(bytes (vector-ref hex (quotient n 16))
|
(define (word->bytesl w)
|
||||||
(vector-ref hex (modulo n 16))))
|
(let ([byte (lambda (n b) (bitwise-and (arithmetic-shift n (- b)) 15))]
|
||||||
|
[lo (cdr w)] [hi (car w)])
|
||||||
(apply bytes-append (map number->hex (apply append (map word->bytesl l)))))
|
(list (byte lo 4) (byte lo 0) (byte lo 12) (byte lo 8)
|
||||||
|
(byte hi 4) (byte hi 0) (byte hi 12) (byte hi 8))))
|
||||||
|
(apply bytes (map (lambda (n) (vector-ref hex n))
|
||||||
|
(apply append (map word->bytesl l)))))
|
||||||
|
|
||||||
;(define (md5-test)
|
;(define (md5-test)
|
||||||
; (if (and (equal? (md5 "")
|
; (if (and (equal? (md5 "")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user