Merge 0.10->trunk
[prosody.git] / util-src / hashes.c
1 /* Prosody IM
2 -- Copyright (C) 2009-2010 Matthew Wild
3 -- Copyright (C) 2009-2010 Waqas Hussain
4 --
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8 */
9
10
11 /*
12 * hashes.c
13 * Lua library for sha1, sha256 and md5 hashes
14 */
15
16 #include <string.h>
17 #include <stdlib.h>
18
19 #ifdef _MSC_VER
20 typedef unsigned __int32 uint32_t;
21 #else
22 #include <inttypes.h>
23 #endif
24
25 #include "lua.h"
26 #include "lauxlib.h"
27 #include <openssl/sha.h>
28 #include <openssl/md5.h>
29
30 #if (LUA_VERSION_NUM == 501)
31 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
32 #endif
33
34 #define HMAC_IPAD 0x36363636
35 #define HMAC_OPAD 0x5c5c5c5c
36
37 const char* hex_tab = "0123456789abcdef";
38 void toHex(const unsigned char* in, int length, unsigned char* out) {
39         int i;
40
41         for(i = 0; i < length; i++) {
42                 out[i * 2] = hex_tab[(in[i] >> 4) & 0xF];
43                 out[i * 2 + 1] = hex_tab[(in[i]) & 0xF];
44         }
45 }
46
47 #define MAKE_HASH_FUNCTION(myFunc, func, size) \
48 static int myFunc(lua_State *L) { \
49         size_t len; \
50         const char *s = luaL_checklstring(L, 1, &len); \
51         int hex_out = lua_toboolean(L, 2); \
52         unsigned char hash[size], result[size*2]; \
53         func((const unsigned char*)s, len, hash);  \
54         if (hex_out) { \
55                 toHex(hash, size, result); \
56                 lua_pushlstring(L, (char*)result, size*2); \
57         } else { \
58                 lua_pushlstring(L, (char*)hash, size);\
59         } \
60         return 1; \
61 }
62
63 MAKE_HASH_FUNCTION(Lsha1, SHA1, SHA_DIGEST_LENGTH)
64 MAKE_HASH_FUNCTION(Lsha224, SHA224, SHA224_DIGEST_LENGTH)
65 MAKE_HASH_FUNCTION(Lsha256, SHA256, SHA256_DIGEST_LENGTH)
66 MAKE_HASH_FUNCTION(Lsha384, SHA384, SHA384_DIGEST_LENGTH)
67 MAKE_HASH_FUNCTION(Lsha512, SHA512, SHA512_DIGEST_LENGTH)
68 MAKE_HASH_FUNCTION(Lmd5, MD5, MD5_DIGEST_LENGTH)
69
70 struct hash_desc {
71         int (*Init)(void*);
72         int (*Update)(void*, const void*, size_t);
73         int (*Final)(unsigned char*, void*);
74         size_t digestLength;
75         void* ctx, *ctxo;
76 };
77
78 static void hmac(struct hash_desc* desc, const char* key, size_t key_len,
79                  const char* msg, size_t msg_len, unsigned char* result) {
80         union xory {
81                 unsigned char bytes[64];
82                 uint32_t quadbytes[16];
83         };
84
85         int i;
86         unsigned char hashedKey[64]; /* Maximum used digest length */
87         union xory k_ipad, k_opad;
88
89         if(key_len > 64) {
90                 desc->Init(desc->ctx);
91                 desc->Update(desc->ctx, key, key_len);
92                 desc->Final(hashedKey, desc->ctx);
93                 key = (const char*)hashedKey;
94                 key_len = desc->digestLength;
95         }
96
97         memcpy(k_ipad.bytes, key, key_len);
98         memset(k_ipad.bytes + key_len, 0, 64 - key_len);
99         memcpy(k_opad.bytes, k_ipad.bytes, 64);
100
101         for(i = 0; i < 16; i++) {
102                 k_ipad.quadbytes[i] ^= HMAC_IPAD;
103                 k_opad.quadbytes[i] ^= HMAC_OPAD;
104         }
105
106         desc->Init(desc->ctx);
107         desc->Update(desc->ctx, k_ipad.bytes, 64);
108         desc->Init(desc->ctxo);
109         desc->Update(desc->ctxo, k_opad.bytes, 64);
110         desc->Update(desc->ctx, msg, msg_len);
111         desc->Final(result, desc->ctx);
112         desc->Update(desc->ctxo, result, desc->digestLength);
113         desc->Final(result, desc->ctxo);
114 }
115
116 #define MAKE_HMAC_FUNCTION(myFunc, func, size, type) \
117 static int myFunc(lua_State *L) { \
118         type ctx, ctxo; \
119         unsigned char hash[size], result[2*size]; \
120         size_t key_len, msg_len; \
121         const char *key = luaL_checklstring(L, 1, &key_len); \
122         const char *msg = luaL_checklstring(L, 2, &msg_len); \
123         const int hex_out = lua_toboolean(L, 3); \
124         struct hash_desc desc; \
125         desc.Init = (int (*)(void*))func##_Init; \
126         desc.Update = (int (*)(void*, const void *, size_t))func##_Update; \
127         desc.Final = (int (*)(unsigned char*, void*))func##_Final; \
128         desc.digestLength = size; \
129         desc.ctx = &ctx; \
130         desc.ctxo = &ctxo; \
131         hmac(&desc, key, key_len, msg, msg_len, hash); \
132         if (hex_out) { \
133                 toHex(hash, size, result); \
134                 lua_pushlstring(L, (char*)result, size*2); \
135         } else { \
136                 lua_pushlstring(L, (char*)hash, size); \
137         } \
138         return 1; \
139 }
140
141 MAKE_HMAC_FUNCTION(Lhmac_sha1, SHA1, SHA_DIGEST_LENGTH, SHA_CTX)
142 MAKE_HMAC_FUNCTION(Lhmac_sha256, SHA256, SHA256_DIGEST_LENGTH, SHA256_CTX)
143 MAKE_HMAC_FUNCTION(Lhmac_sha512, SHA512, SHA512_DIGEST_LENGTH, SHA512_CTX)
144 MAKE_HMAC_FUNCTION(Lhmac_md5, MD5, MD5_DIGEST_LENGTH, MD5_CTX)
145
146 static int LscramHi(lua_State* L) {
147         union xory {
148                 unsigned char bytes[SHA_DIGEST_LENGTH];
149                 uint32_t quadbytes[SHA_DIGEST_LENGTH / 4];
150         };
151         int i;
152         SHA_CTX ctx, ctxo;
153         unsigned char Ust[SHA_DIGEST_LENGTH];
154         union xory Und;
155         union xory res;
156         size_t str_len, salt_len;
157         struct hash_desc desc;
158         const char* str = luaL_checklstring(L, 1, &str_len);
159         const char* salt = luaL_checklstring(L, 2, &salt_len);
160         char* salt2;
161         const int iter = luaL_checkinteger(L, 3);
162
163         desc.Init = (int (*)(void*))SHA1_Init;
164         desc.Update = (int (*)(void*, const void*, size_t))SHA1_Update;
165         desc.Final = (int (*)(unsigned char*, void*))SHA1_Final;
166         desc.digestLength = SHA_DIGEST_LENGTH;
167         desc.ctx = &ctx;
168         desc.ctxo = &ctxo;
169
170         salt2 = malloc(salt_len + 4);
171
172         if(salt2 == NULL) {
173                 return luaL_error(L, "Out of memory in scramHi");
174         }
175
176         memcpy(salt2, salt, salt_len);
177         memcpy(salt2 + salt_len, "\0\0\0\1", 4);
178         hmac(&desc, str, str_len, salt2, salt_len + 4, Ust);
179         free(salt2);
180
181         memcpy(res.bytes, Ust, sizeof(res));
182
183         for(i = 1; i < iter; i++) {
184                 int j;
185                 hmac(&desc, str, str_len, (char*)Ust, sizeof(Ust), Und.bytes);
186
187                 for(j = 0; j < SHA_DIGEST_LENGTH / 4; j++) {
188                         res.quadbytes[j] ^= Und.quadbytes[j];
189                 }
190
191                 memcpy(Ust, Und.bytes, sizeof(Ust));
192         }
193
194         lua_pushlstring(L, (char*)res.bytes, SHA_DIGEST_LENGTH);
195
196         return 1;
197 }
198
199 static const luaL_Reg Reg[] = {
200         { "sha1",               Lsha1           },
201         { "sha224",             Lsha224         },
202         { "sha256",             Lsha256         },
203         { "sha384",             Lsha384         },
204         { "sha512",             Lsha512         },
205         { "md5",                Lmd5            },
206         { "hmac_sha1",          Lhmac_sha1      },
207         { "hmac_sha256",        Lhmac_sha256    },
208         { "hmac_sha512",        Lhmac_sha512    },
209         { "hmac_md5",           Lhmac_md5       },
210         { "scram_Hi_sha1",      LscramHi        },
211         { NULL,                 NULL            }
212 };
213
214 LUALIB_API int luaopen_util_hashes(lua_State* L) {
215         lua_newtable(L);
216         luaL_setfuncs(L, Reg, 0);;
217         lua_pushliteral(L, "-3.14");
218         lua_setfield(L, -2, "version");
219         return 1;
220 }