diff --git a/pkgs/racket-pkgs/racket-doc/file/scribblings/md5.scrbl b/pkgs/racket-pkgs/racket-doc/file/scribblings/md5.scrbl index c4e470ca82..3d79ef6f62 100644 --- a/pkgs/racket-pkgs/racket-doc/file/scribblings/md5.scrbl +++ b/pkgs/racket-pkgs/racket-doc/file/scribblings/md5.scrbl @@ -8,6 +8,9 @@ @defmodule[file/md5] +See @racketmodname[openssl/md5] for a faster implementation with a +slightly different interface. + @defproc[(md5 [in (or/c input-port? bytes? string?)] [hex-encode? boolean? #t]) bytes?]{ diff --git a/pkgs/racket-pkgs/racket-doc/openssl/openssl.scrbl b/pkgs/racket-pkgs/racket-doc/openssl/openssl.scrbl index a897040814..6ea456741b 100644 --- a/pkgs/racket-pkgs/racket-doc/openssl/openssl.scrbl +++ b/pkgs/racket-pkgs/racket-doc/openssl/openssl.scrbl @@ -2,7 +2,8 @@ @(require scribble/manual (for-label openssl racket - openssl/sha1)) + openssl/sha1 + openssl/md5)) @title{OpenSSL: Secure Communication} @@ -649,3 +650,34 @@ until an end-of-file.} Converts the given byte string to a string representation, where each byte in @racket[bstr] is converted to its two-digit hexadecimal representation in the resulting string.} + +@defproc[(hex-string->bytes [str string?]) bytes?]{ + +The inverse of @racket[bytes->hex-string].} + +@; ---------------------------------------------------------------------- + +@section{MD5 Hashing} + +@defmodule[openssl/md5]{The @racketmodname[openssl/md5] library +provides a Racket wrapper for the OpenSSL library's MD5 hashing +functions. If the OpenSSL library cannot be opened, this library logs +a warning and falls back to the implementation in +@racketmodname[file/md5].} + +@history[#:added "6.0.0.3"] + +@defproc[(md5 [in input-port?]) string?]{ + +Returns a 32-character string that represents the MD5 hash (in +hexadecimal notation) of the content from @racket[in], consuming all +of the input from @racket[in] until an end-of-file. + +The @racket[md5] function composes @racket[bytes->hex-string] with +@racket[md5-bytes].} + +@defproc[(md5-bytes [in input-port?]) bytes?]{ + +Returns a 16-byte byte string that represents the MD5 hash of the +content from @racket[in], consuming all of the input from @racket[in] +until an end-of-file.} diff --git a/racket/collects/openssl/md5.rkt b/racket/collects/openssl/md5.rkt new file mode 100644 index 0000000000..14e91feb90 --- /dev/null +++ b/racket/collects/openssl/md5.rkt @@ -0,0 +1,57 @@ +#lang racket/base +(require ffi/unsafe + racket/runtime-path + (for-syntax racket/base) + (prefix-in r: file/md5) + "libcrypto.rkt") + +(provide md5 + md5-bytes) + +(define _SHA_CTX-pointer _pointer) + +(define MD5_Init + (and libcrypto + (get-ffi-obj 'MD5_Init libcrypto (_fun _SHA_CTX-pointer -> _int) (lambda () #f)))) +(define MD5_Update + (and libcrypto + (get-ffi-obj 'MD5_Update libcrypto (_fun _SHA_CTX-pointer _pointer _long -> _int) (lambda () #f)))) +(define MD5_Final + (and libcrypto + (get-ffi-obj 'MD5_Final libcrypto (_fun _pointer _SHA_CTX-pointer -> _int) (lambda () #f)))) + +(define (md5-bytes in) + (unless (input-port? in) (raise-argument-error 'md5-bytes "input-port?" in)) + (if MD5_Init + (let ([ctx (malloc 256)] + [tmp (make-bytes 4096)] + [result (make-bytes 16)]) + (MD5_Init ctx) + (let loop () + (let ([n (read-bytes-avail! tmp in)]) + (unless (eof-object? n) + (MD5_Update ctx tmp n) + (loop)))) + (MD5_Final result ctx) + result) + (r:md5 in #f))) + +(define (md5 in) + (unless (input-port? in) (raise-argument-error 'md5 "input-port?" in)) + (bytes->hex-string (md5-bytes in))) + +;; copied from `file/sha1` --- should be in a separate module, +;; instead +(define (bytes->hex-string bstr) + (let* ([len (bytes-length bstr)] + [bstr2 (make-bytes (* len 2))] + [digit + (lambda (v) + (if (v . < . 10) + (+ v (char->integer #\0)) + (+ v (- (char->integer #\a) 10))))]) + (for ([i (in-range len)]) + (let ([c (bytes-ref bstr i)]) + (bytes-set! bstr2 (* 2 i) (digit (arithmetic-shift c -4))) + (bytes-set! bstr2 (+ (* 2 i) 1) (digit (bitwise-and c #xF))))) + (bytes->string/latin-1 bstr2))) diff --git a/racket/collects/openssl/sha1.rkt b/racket/collects/openssl/sha1.rkt index 4f36d3a0ea..546e5c126c 100644 --- a/racket/collects/openssl/sha1.rkt +++ b/racket/collects/openssl/sha1.rkt @@ -23,6 +23,7 @@ (get-ffi-obj 'SHA1_Final libcrypto (_fun _pointer _SHA_CTX-pointer -> _int) (lambda () #f)))) (define (sha1-bytes in) + (unless (input-port? in) (raise-argument-error 'sha1-bytes "input-port?" in)) (if SHA1_Init (let ([ctx (malloc 256)] [tmp (make-bytes 4096)] @@ -38,4 +39,5 @@ (r:sha1-bytes in))) (define (sha1 in) + (unless (input-port? in) (raise-argument-error 'sha1 "input-port?" in)) (r:bytes->hex-string (sha1-bytes in)))