Do What I Mean
June 11th, 2021
I wanted to replicate the following function from Javascript md5 module in Emacs lips:
function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
The nested functions are:
str2rstr_utf8
encodes a string as utf-8, assuming it is utf-16rster_md5
calculates the md5 of a raw stringrstr2b64
converts a raw string to a base-64 stringOutputs:
str2rstr_utf8("test"); // "test"
rstr_md5("test"); // "\tkÍF!ÓsÊÞN&'´ö"
rstr2b64("test"); // "dGVzdA"
rstr2b64(rstr_md5("test")) // "CY9rzUYh03PK3k6DJie09g"
I could quite easily find some elisp functions that may be equivalent:
Javascript md5 | Elisp |
---|---|
str2rstr_utf8 | encode-coding-string |
rster_md5 | secure-hash |
str2b64 | base64-encode-string |
On closer inspection I figured I would not need encode-coding-string
because Emacs already uses UTF8 encoding internally, while Javascript uses UTF-16.
It turns out that the other two elisp functions are close matches to their JS counterparts:
(base64-encode-string "test") ; "dGVzdA", same as rstr2b64
(secure-hash 'md5 "test") ; "098f6bcd4621d373cade4e832627b4f6"
; which is HEX for " kÍF!ÓsÊÞN&'´ö"
So, I need a function to decode a HEX string:
(defun decode-hex-string (hex-string)
(let ((res nil))
(dotimes (i (/ (length hex-string) 2) (apply #'concat (reverse res)))
(let ((hex-byte (substring hex-string (* 2 i) (* 2 (+ i 1)))))
(push (format "%c" (string-to-number hex-byte 16)) res)))))
(decode-hex-string (secure-hash 'md5 "test")) ; " kÍF!ÓsÊÞN&'´ö" same as rster_md5
(base64-encode-string
(decode-hex-string (secure-hash 'md5 "test"))) ; "CY9rzUYh03PK3k6DJie09g"
Et voilá!