Merge 0.9->trunk
authorMatthew Wild <mwild1@gmail.com>
Mon, 29 Apr 2013 10:54:25 +0100
changeset 5540 34ec16920685
parent 5536 abb6c6e3d6dc (current diff)
parent 5539 0ae7ed378405 (diff)
child 5543 d3f5165c4113
Merge 0.9->trunk
--- a/tests/test_util_sasl_scram.lua	Mon Apr 29 10:44:18 2013 +0100
+++ b/tests/test_util_sasl_scram.lua	Mon Apr 29 10:54:25 2013 +0100
@@ -1,6 +1,6 @@
 
 
-local hmac_sha1 = require "util.hmac".sha1;
+local hmac_sha1 = require "util.hashes".hmac_sha1;
 local function toHex(s)
 	return s and (s:gsub(".", function (c) return ("%02x"):format(c:byte()); end));
 end
--- a/util-src/Makefile	Mon Apr 29 10:44:18 2013 +0100
+++ b/util-src/Makefile	Mon Apr 29 10:54:25 2013 +0100
@@ -9,6 +9,7 @@
 CC?=gcc
 CXX?=g++
 LD?=gcc
+CFLAGS+=-ggdb
 
 .PHONY: all install clean
 .SUFFIXES: .c .o .so
--- a/util-src/hashes.c	Mon Apr 29 10:44:18 2013 +0100
+++ b/util-src/hashes.c	Mon Apr 29 10:54:25 2013 +0100
@@ -14,14 +14,19 @@
 */
 
 #include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
 
 #include "lua.h"
 #include "lauxlib.h"
 #include <openssl/sha.h>
 #include <openssl/md5.h>
 
-const char* hex_tab = "0123456789abcdef";
-void toHex(const char* in, int length, char* out) {
+#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];
@@ -34,14 +39,13 @@
 	size_t len; \
 	const char *s = luaL_checklstring(L, 1, &len); \
 	int hex_out = lua_toboolean(L, 2); \
-	char hash[size]; \
-	char result[size*2]; \
-	func((const unsigned char*)s, len, (unsigned char*)hash);  \
+	unsigned char hash[size], result[size*2]; \
+	func((const unsigned char*)s, len, hash);  \
 	if (hex_out) { \
 		toHex(hash, size, result); \
-		lua_pushlstring(L, result, size*2); \
+		lua_pushlstring(L, (char*)result, size*2); \
 	} else { \
-		lua_pushlstring(L, hash, size);\
+		lua_pushlstring(L, (char*)hash, size);\
 	} \
 	return 1; \
 }
@@ -53,15 +57,143 @@
 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;
+	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(desc->ctx, hashedKey);
+		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)
+		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	},
-	{ NULL,		NULL	}
+	{ "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)
--- a/util/hmac.lua	Mon Apr 29 10:44:18 2013 +0100
+++ b/util/hmac.lua	Mon Apr 29 10:54:25 2013 +0100
@@ -6,64 +6,10 @@
 -- COPYING file in the source package for more information.
 --
 
+-- COMPAT: Only for external pre-0.9 modules
+
 local hashes = require "util.hashes"
 
-local s_char = string.char;
-local s_gsub = string.gsub;
-local s_rep = string.rep;
-
-module "hmac"
-
-local xor_map = {0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;1;0;3;2;5;4;7;6;9;8;11;10;13;12;15;14;2;3;0;1;6;7;4;5;10;11;8;9;14;15;12;13;3;2;1;0;7;6;5;4;11;10;9;8;15;14;13;12;4;5;6;7;0;1;2;3;12;13;14;15;8;9;10;11;5;4;7;6;1;0;3;2;13;12;15;14;9;8;11;10;6;7;4;5;2;3;0;1;14;15;12;13;10;11;8;9;7;6;5;4;3;2;1;0;15;14;13;12;11;10;9;8;8;9;10;11;12;13;14;15;0;1;2;3;4;5;6;7;9;8;11;10;13;12;15;14;1;0;3;2;5;4;7;6;10;11;8;9;14;15;12;13;2;3;0;1;6;7;4;5;11;10;9;8;15;14;13;12;3;2;1;0;7;6;5;4;12;13;14;15;8;9;10;11;4;5;6;7;0;1;2;3;13;12;15;14;9;8;11;10;5;4;7;6;1;0;3;2;14;15;12;13;10;11;8;9;6;7;4;5;2;3;0;1;15;14;13;12;11;10;9;8;7;6;5;4;3;2;1;0;};
-local function xor(x, y)
-	local lowx, lowy = x % 16, y % 16;
-	local hix, hiy = (x - lowx) / 16, (y - lowy) / 16;
-	local lowr, hir = xor_map[lowx * 16 + lowy + 1], xor_map[hix * 16 + hiy + 1];
-	local r = hir * 16 + lowr;
-	return r;
-end
-local opadc, ipadc = s_char(0x5c), s_char(0x36);
-local ipad_map = {};
-local opad_map = {};
-for i=0,255 do
-	ipad_map[s_char(i)] = s_char(xor(0x36, i));
-	opad_map[s_char(i)] = s_char(xor(0x5c, i));
-end
-
---[[
-key
-	the key to use in the hash
-message
-	the message to hash
-hash
-	the hash function
-blocksize
-	the blocksize for the hash function in bytes
-hex
-	return raw hash or hexadecimal string
---]]
-function hmac(key, message, hash, blocksize, hex)
-	if #key > blocksize then
-		key = hash(key)
-	end
-
-	local padding = blocksize - #key;
-	local ipad = s_gsub(key, ".", ipad_map)..s_rep(ipadc, padding);
-	local opad = s_gsub(key, ".", opad_map)..s_rep(opadc, padding);
-
-	return hash(opad..hash(ipad..message), hex)
-end
-
-function md5(key, message, hex)
-	return hmac(key, message, hashes.md5, 64, hex)
-end
-
-function sha1(key, message, hex)
-	return hmac(key, message, hashes.sha1, 64, hex)
-end
-
-function sha256(key, message, hex)
-	return hmac(key, message, hashes.sha256, 64, hex)
-end
-
-return _M
+return { md5 = hashes.hmac_md5,
+	 sha1 = hashes.hmac_sha1,
+	 sha256 = hashes.hmac_sha256 };
--- a/util/sasl/scram.lua	Mon Apr 29 10:44:18 2013 +0100
+++ b/util/sasl/scram.lua	Mon Apr 29 10:54:25 2013 +0100
@@ -15,8 +15,9 @@
 local type = type
 local string = string
 local base64 = require "util.encodings".base64;
-local hmac_sha1 = require "util.hmac".sha1;
+local hmac_sha1 = require "util.hashes".hmac_sha1;
 local sha1 = require "util.hashes".sha1;
+local Hi = require "util.hashes".scram_Hi_sha1;
 local generate_uuid = require "util.uuid".generate;
 local saslprep = require "util.encodings".stringprep.saslprep;
 local nodeprep = require "util.encodings".stringprep.nodeprep;
@@ -65,18 +66,6 @@
 	return t_concat(result);
 end
 
--- hash algorithm independent Hi(PBKDF2) implementation
-function Hi(hmac, str, salt, i)
-	local Ust = hmac(str, salt.."\0\0\0\1");
-	local res = Ust;
-	for n=1,i-1 do
-		local Und = hmac(str, Ust)
-		res = binaryXOR(res, Und)
-		Ust = Und
-	end
-	return res
-end
-
 local function validate_username(username, _nodeprep)
 	-- check for forbidden char sequences
 	for eq in username:gmatch("=(.?.?)") do
@@ -110,7 +99,7 @@
 	if iteration_count < 4096 then
 		log("warn", "Iteration count < 4096 which is the suggested minimum according to RFC 5802.")
 	end
-	local salted_password = Hi(hmac_sha1, password, salt, iteration_count);
+	local salted_password = Hi(password, salt, iteration_count);
 	local stored_key = sha1(hmac_sha1(salted_password, "Client Key"))
 	local server_key = hmac_sha1(salted_password, "Server Key");
 	return true, stored_key, server_key