Everytime I need to use the Crypto module, a great wave of anxiety sweeps over me. For most common programmers the case is usually that you need to MD5 or SHA256 som some data to send over HTTP to some REST API or something like that, or compare something to a hash stored in a database or something like that.
I had to make HMAC-SHA256 hash yesterday and it took me like 1,5 hours to figure that stuff out:
String.string2hex(Crypto.HMAC(Crypto.SHA256)(secret)(data));
Not the most intuitive stuff if you ask me.
That led me to the question: Why aren't there any helper methods directly in Crypto, for the more common use cases? So I've been fiddling around with it some and though that maybe something like below could be nice to have. This is just a mockup so feel free to point out if there are better ways to write the code, and if this is something that would fit at all.
//! Typedef for a generic hashing function that takes a string as argument //! and returnes a hashed and @[String.string2hex]'ed string. typedef function(string(8bit):string(8bit)) hash_func_t;
//! Typedef for a generic HMAC hash function that takes data and a secret as //! arguments and returns a hashed and @[String.string2hex]'ed string typedef function(string(8bit),string(8bit):string(8bit)) hash_hmac_func_t;
protected hash_func_t make_hash_func(Crypto.Hash hash, void|bool raw) { return lambda (string in) { string s = hash->hash(in); return raw ? s : String.string2hex(s); }; }
protected hash_hmac_func_t make_hash_hmac_func(Crypto.Hash hash, void|bool raw) { return lambda (string data, string secret) { string s = Crypto.HMAC(hash)(secret)(data); return raw ? s : String.string2hex(s); }; }
//! Create a HMAC hash of @[data] and @[secret] using the Crypto module @[hash]. //! //! @param hash //! @param data //! @param secret string hash_hmac(Crypto.Hash hash, string data, string secret) { return make_hash_hmac_func(hash)(data, secret); }
//! Creates a HMAC hashing function using the Crypto module @[hash]. This can //! later be called with the data and secret to make a hash of. //! //! @returns //! @tt{function(string, string : string)@} variant hash_hmac_func_t hash_hmac(Crypto.Hash hash) { return make_hash_hmac_func(hash); }
//! Creates a hash of @[data] using the hashing algorithm in @[hash]. //! If @[raw] is given the hash will not pass through @[String.string2hex]. string hash(Crypto.Hash hash, string data, void|bool raw) { return make_hash_func(hash, raw)(data); }
//! Creates a hashing function using the Crypto module @[hash]. This can later //! be called with the data to make a hash of. //! If @[raw] is given the hash will not pass through @[String.string2hex]. //! //! @returns //! @tt{function(string : string)@} variant hash_func_t hash(Crypto.Hash hash, void|bool raw) { return make_hash_func(hash, raw); }
hash_hmac_func_t hmac_sha256 = hash_hmac(Crypto.SHA256); hash_hmac_func_t hmac_md5 = hash_hmac(Crypto.MD5); hash_func_t md5 = hash(Crypto.MD5); hash_func_t sha256 = hash(Crypto.SHA256);
int main(int argc, array(string) argv) { string data = "my data"; string secret = "abc123";
write("%-20s %s\n", "hash_hmac(MD5):", hash_hmac(Crypto.MD5, data, secret)); write("%-20s %s\n", "hash_hmac_md5:", hmac_md5(data, secret)); write("%-20s %s\n", "hash_hmac_sha256:", hmac_sha256(data, secret)); write("%-20s %s\n", "hash(md5):", hash(Crypto.MD5, data)); write("%-20s %s\n", "hash(md5:raw):", hash(Crypto.MD5, data, true)); write("%-20s %s\n", "md5:", md5(data)); write("%-20s %s\n", "sha256:", sha256(data));
return 0; }
Regards ----------------------------- Pontus Östlund Developer • Roxen AB +46 70-662 81 69
www.roxen.com http://www.roxen.com/ | twitter.com/roxen https://twitter.com/roxen