+ unsigned char hash[size], result[size*2]; \
+ func((const unsigned char*)s, len, hash); \
+ if (hex_out) { \
+ toHex(hash, size, result); \
+ lua_pushlstring(L, (char*)result, size*2); \
+ } else { \
+ lua_pushlstring(L, (char*)hash, size);\
+ } \
+ return 1; \
+}
+
+MAKE_HASH_FUNCTION(Lsha1, SHA1, SHA_DIGEST_LENGTH)
+MAKE_HASH_FUNCTION(Lsha224, SHA224, SHA224_DIGEST_LENGTH)
+MAKE_HASH_FUNCTION(Lsha256, SHA256, SHA256_DIGEST_LENGTH)
+MAKE_HASH_FUNCTION(Lsha384, SHA384, SHA384_DIGEST_LENGTH)
+MAKE_HASH_FUNCTION(Lsha512, SHA512, SHA512_DIGEST_LENGTH)
+MAKE_HASH_FUNCTION(Lmd5, MD5, MD5_DIGEST_LENGTH)
+
+struct hash_desc {
+ int (*Init)(void*);
+ int (*Update)(void*, const void *, size_t);
+ int (*Final)(unsigned char*, void*);
+ size_t digestLength;
+ void *ctx, *ctxo;
+};
+
+static void hmac(struct hash_desc *desc, const char *key, size_t key_len,
+ const char *msg, size_t msg_len, unsigned char *result)
+{
+ union xory {
+ unsigned char bytes[64];
+ uint32_t quadbytes[16];
+ };
+
+ int i;
+ unsigned char hashedKey[64]; /* Maximum used digest length */
+ union xory k_ipad, k_opad;
+
+ if (key_len > 64) {
+ desc->Init(desc->ctx);
+ desc->Update(desc->ctx, key, key_len);
+ desc->Final(hashedKey, desc->ctx);
+ key = (const char*)hashedKey;
+ key_len = desc->digestLength;
+ }
+
+ memcpy(k_ipad.bytes, key, key_len);
+ memset(k_ipad.bytes + key_len, 0, 64 - key_len);
+ memcpy(k_opad.bytes, k_ipad.bytes, 64);
+
+ for (i = 0; i < 16; i++) {
+ k_ipad.quadbytes[i] ^= HMAC_IPAD;
+ k_opad.quadbytes[i] ^= HMAC_OPAD;
+ }
+
+ desc->Init(desc->ctx);
+ desc->Update(desc->ctx, k_ipad.bytes, 64);
+ desc->Init(desc->ctxo);
+ desc->Update(desc->ctxo, k_opad.bytes, 64);
+ desc->Update(desc->ctx, msg, msg_len);
+ desc->Final(result, desc->ctx);
+ desc->Update(desc->ctxo, result, desc->digestLength);
+ desc->Final(result, desc->ctxo);
+}
+
+#define MAKE_HMAC_FUNCTION(myFunc, func, size, type) \
+static int myFunc(lua_State *L) { \
+ type ctx, ctxo; \
+ unsigned char hash[size], result[2*size]; \
+ size_t key_len, msg_len; \
+ const char *key = luaL_checklstring(L, 1, &key_len); \
+ const char *msg = luaL_checklstring(L, 2, &msg_len); \
+ const int hex_out = lua_toboolean(L, 3); \
+ struct hash_desc desc; \
+ desc.Init = (int (*)(void*))func##_Init; \
+ desc.Update = (int (*)(void*, const void *, size_t))func##_Update; \
+ desc.Final = (int (*)(unsigned char*, void*))func##_Final; \
+ desc.digestLength = size; \
+ desc.ctx = &ctx; \
+ desc.ctxo = &ctxo; \
+ hmac(&desc, key, key_len, msg, msg_len, hash); \