Merge 0.10->trunk
[prosody.git] / util-src / hashes.c
index 41cf6f509f6d4142763ec9e4c3691f745791f72c..ecab2e328e892833d8d5780066e6afaf8c8f88c8 100644 (file)
-/*\r
-* hashes.c\r
-* Lua library for sha1, sha256 and md5 hashes\r
-*/\r
-\r
-#include <string.h>\r
-\r
-#include "lua.h"\r
-#include "lauxlib.h"\r
-#include <openssl/sha.h>\r
-#include <openssl/md5.h>\r
-\r
-const char* hex_tab = "0123456789abcdef";\r
-void toHex(const char* in, int length, char* out) {\r
-       int i;\r
-       for (i = 0; i < length; i++) {\r
-               out[i*2] = hex_tab[(in[i] >> 4) & 0xF];\r
-               out[i*2+1] = hex_tab[(in[i]) & 0xF];\r
-       }\r
-}\r
-\r
-#define MAKE_HASH_FUNCTION(myFunc, func, size) \\r
-static int myFunc(lua_State *L) { \\r
-       size_t len; \\r
-       const char *s = luaL_checklstring(L, 1, &len); \\r
-       int hex_out = lua_toboolean(L, 2); \\r
-       char hash[size]; \\r
-       char result[size*2]; \\r
-       func((const unsigned char*)s, len, (unsigned char*)hash);  \\r
-       if (hex_out) { \\r
-               toHex(hash, size, result); \\r
-               lua_pushlstring(L, result, size*2); \\r
-       } else { \\r
-               lua_pushlstring(L, hash, size);\\r
-       } \\r
-       return 1; \\r
-}\r
-\r
-MAKE_HASH_FUNCTION(Lsha1, SHA1, 20)\r
-MAKE_HASH_FUNCTION(Lsha256, SHA256, 32)\r
-MAKE_HASH_FUNCTION(Lmd5, MD5, 16)\r
-\r
-static const luaL_Reg Reg[] =\r
-{\r
-       { "sha1",       Lsha1   },\r
-       { "sha256",     Lsha256 },\r
-       { "md5",        Lmd5    },\r
-       { NULL,         NULL    }\r
-};\r
-\r
-LUALIB_API int luaopen_util_hashes(lua_State *L)\r
-{\r
-       luaL_register(L, "hashes", Reg);\r
-       lua_pushliteral(L, "version");                  /** version */\r
-       lua_pushliteral(L, "-3.14");\r
-       lua_settable(L,-3);\r
-       return 1;\r
-}\r
+/* Prosody IM
+-- Copyright (C) 2009-2010 Matthew Wild
+-- Copyright (C) 2009-2010 Waqas Hussain
+--
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+*/
+
+
+/*
+* hashes.c
+* Lua library for sha1, sha256 and md5 hashes
+*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+typedef unsigned __int32 uint32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#include "lua.h"
+#include "lauxlib.h"
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+
+#if (LUA_VERSION_NUM == 501)
+#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
+#endif
+
+#define HMAC_IPAD 0x36363636
+#define HMAC_OPAD 0x5c5c5c5c
+
+const char* hex_tab = "0123456789abcdef";
+void toHex(const unsigned char* in, int length, unsigned char* out) {
+       int i;
+
+       for(i = 0; i < length; i++) {
+               out[i * 2] = hex_tab[(in[i] >> 4) & 0xF];
+               out[i * 2 + 1] = hex_tab[(in[i]) & 0xF];
+       }
+}
+
+#define MAKE_HASH_FUNCTION(myFunc, func, size) \
+static int myFunc(lua_State *L) { \
+       size_t len; \
+       const char *s = luaL_checklstring(L, 1, &len); \
+       int hex_out = lua_toboolean(L, 2); \
+       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); \
+       if (hex_out) { \
+               toHex(hash, size, result); \
+               lua_pushlstring(L, (char*)result, size*2); \
+       } else { \
+               lua_pushlstring(L, (char*)hash, size); \
+       } \
+       return 1; \
+}
+
+MAKE_HMAC_FUNCTION(Lhmac_sha1, SHA1, SHA_DIGEST_LENGTH, SHA_CTX)
+MAKE_HMAC_FUNCTION(Lhmac_sha256, SHA256, SHA256_DIGEST_LENGTH, SHA256_CTX)
+MAKE_HMAC_FUNCTION(Lhmac_sha512, SHA512, SHA512_DIGEST_LENGTH, SHA512_CTX)
+MAKE_HMAC_FUNCTION(Lhmac_md5, MD5, MD5_DIGEST_LENGTH, MD5_CTX)
+
+static int LscramHi(lua_State* L) {
+       union xory {
+               unsigned char bytes[SHA_DIGEST_LENGTH];
+               uint32_t quadbytes[SHA_DIGEST_LENGTH / 4];
+       };
+       int i;
+       SHA_CTX ctx, ctxo;
+       unsigned char Ust[SHA_DIGEST_LENGTH];
+       union xory Und;
+       union xory res;
+       size_t str_len, salt_len;
+       struct hash_desc desc;
+       const char* str = luaL_checklstring(L, 1, &str_len);
+       const char* salt = luaL_checklstring(L, 2, &salt_len);
+       char* salt2;
+       const int iter = luaL_checkinteger(L, 3);
+
+       desc.Init = (int (*)(void*))SHA1_Init;
+       desc.Update = (int (*)(void*, const void*, size_t))SHA1_Update;
+       desc.Final = (int (*)(unsigned char*, void*))SHA1_Final;
+       desc.digestLength = SHA_DIGEST_LENGTH;
+       desc.ctx = &ctx;
+       desc.ctxo = &ctxo;
+
+       salt2 = malloc(salt_len + 4);
+
+       if(salt2 == NULL) {
+               return luaL_error(L, "Out of memory in scramHi");
+       }
+
+       memcpy(salt2, salt, salt_len);
+       memcpy(salt2 + salt_len, "\0\0\0\1", 4);
+       hmac(&desc, str, str_len, salt2, salt_len + 4, Ust);
+       free(salt2);
+
+       memcpy(res.bytes, Ust, sizeof(res));
+
+       for(i = 1; i < iter; i++) {
+               int j;
+               hmac(&desc, str, str_len, (char*)Ust, sizeof(Ust), Und.bytes);
+
+               for(j = 0; j < SHA_DIGEST_LENGTH / 4; j++) {
+                       res.quadbytes[j] ^= Und.quadbytes[j];
+               }
+
+               memcpy(Ust, Und.bytes, sizeof(Ust));
+       }
+
+       lua_pushlstring(L, (char*)res.bytes, SHA_DIGEST_LENGTH);
+
+       return 1;
+}
+
+static const luaL_Reg Reg[] = {
+       { "sha1",               Lsha1           },
+       { "sha224",             Lsha224         },
+       { "sha256",             Lsha256         },
+       { "sha384",             Lsha384         },
+       { "sha512",             Lsha512         },
+       { "md5",                Lmd5            },
+       { "hmac_sha1",          Lhmac_sha1      },
+       { "hmac_sha256",        Lhmac_sha256    },
+       { "hmac_sha512",        Lhmac_sha512    },
+       { "hmac_md5",           Lhmac_md5       },
+       { "scram_Hi_sha1",      LscramHi        },
+       { NULL,                 NULL            }
+};
+
+LUALIB_API int luaopen_util_hashes(lua_State* L) {
+       lua_newtable(L);
+       luaL_setfuncs(L, Reg, 0);;
+       lua_pushliteral(L, "-3.14");
+       lua_setfield(L, -2, "version");
+       return 1;
+}