summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Kendrick (trite) <rjek@rjek.com>2013-07-30 16:22:01 +0100
committerRob Kendrick (trite) <rjek@rjek.com>2013-07-30 16:22:01 +0100
commit33fb309807262347fdd8a2e3a4818dd4f1602065 (patch)
treeb019777acc0ee9fdd65e3cc0659883055d4ee274
parent9ef95ab57b583d722359c2b5a5a7599f0e52bcf1 (diff)
downloadlua-scrypt-33fb309807262347fdd8a2e3a4818dd4f1602065.tar.gz
Password hashing and verification, Makefile stolen from Luxio
-rw-r--r--Makefile135
-rw-r--r--luascrypt.c208
2 files changed, 337 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index d6a39ea..8f428a9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,109 @@
+ifeq ($(strip $(shell which pkg-config > /dev/null || echo NONE)),NONE)
+ $(error This makefile requires pkg-config)
+endif
+
+ifeq ($(strip $(shell which $(CC) > /dev/null || echo NONE)),NONE)
+ $(info lua-scrypt: Hmm, CC make variable contains nonsense. Overriding to gcc.)
+ CC := gcc
+endif
+
+NAKED_LUA_VER := $(shell (pkg-config --exists lua && \
+ pkg-config --modversion lua || \
+ pkg-config --variable V lua) | cut -d. -f1-2)
+
+# fine appropriate Lua interpreter
+LUA_REPL := $(shell (which lua5.1 > /dev/null 2>&1 && echo lua5.1) || \
+ (which lua-5.1 > /dev/null 2>&1 && echo lua-5.1) || \
+ (which lua51 > /dev/null 2>&1 && echo lua51) || \
+ (lua -e"print(_VERSION)" | grep -q 5.1 && echo lua) || \
+ (which lua-5.2 > /dev/null 2>&1 && echo lua-5.2) || \
+ (which lua52 > /dev/null 2>&1 && echo lua52))
+
+# find appropriate Lua libraries
+LUA51_PKG := $(shell (pkg-config --exists lua5.1 && echo lua5.1) || \
+ (pkg-config --exists lua-5.1 && echo lua-5.1) || \
+ (pkg-config --exists lua51 && echo lua51) || \
+ (echo "NONE"))
+
+
+LUA51_PKG := $(strip $(LUA51_PKG))
+
+ifeq ($(LUA51_PKG),NONE)
+ ifeq ($(NAKED_LUA_VER),5.1)
+ LUA51_PKG := lua
+ endif
+endif
+
+ifneq ($(LUA51_PKG),NONE)
+ $(info lua-scrypt: Lua 5.1 package name on this system is $(LUA51_PKG))
+ LUA51_HAS_MODINST := $(shell test x`pkg-config --variable INSTALL_LMOD $(LUA51_PKG)` != x && echo YES)
+ LUA51_INC := $(shell pkg-config --cflags $(LUA51_PKG))
+ LUA51_LIB := $(shell pkg-config --libs $(LUA51_PKG))
+ ifeq ($(LUA51_HAS_MODINST),)
+ LOCAL := YES
+ endif
+ ifeq ($(LOCAL),)
+ LUA51_LMOD_INST := $(shell pkg-config --variable=INSTALL_LMOD $(LUA51_PKG))
+ LUA51_CMOD_INST := $(shell pkg-config --variable=INSTALL_CMOD $(LUA51_PKG))
+ else
+ LUA51_LMOD_INST := /usr/local/share/lua/5.1
+ LUA51_CMOD_INST := /usr/local/lib/lua/5.1
+ endif
+ lua-5.1-try: lua-5.1
+ lua-5.1-try-install: lua-5.1-install
+else
+lua-5.1-try:
+ @echo lua-scrypt: Lua 5.1 could not be found, so lua-scrypt was not built for it.
+lua-5.1-try-install:
+ @echo lua-scrypt: Lua 5.1 could not be found, so lua-scrypt was not installed for it.
+endif
+
+LUA52_PKG := $(shell (pkg-config --exists lua5.2 && echo lua5.2) || \
+ (pkg-config --exists lua-5.2 && echo lua-5.2) || \
+ (pkg-config --exists lua52 && echo lua52) || \
+ (echo "NONE"))
+
+LUA52_PKG := $(strip $(LUA52_PKG))
+
+ifeq ($(LUA52_PKG),NONE)
+ ifeq ($(NAKED_LUA_VER),5.2)
+ LUA52_PKG := lua
+ endif
+endif
+
+ifneq ($(LUA52_PKG),NONE)
+ $(info lua-scrypt: Lua 5.2 package name on this system is $(LUA52_PKG))
+ LUA52_HAS_MODINST := $(shell test x`pkg-config --variable INSTALL_LMOD $(LUA52_PKG)` != x && echo YES)
+ LUA52_INC := $(shell pkg-config --cflags $(LUA52_PKG))
+ LUA52_LIB := $(shell pkg-config --libs $(LUA52_PKG))
+ ifeq ($(LUA52_HAS_MODINST),)
+ LOCAL := YES
+ endif
+ ifeq ($(LOCAL),)
+ LUA52_LMOD_INST := $(shell pkg-config --variable=INSTALL_LMOD $(LUA52_PKG))
+ LUA52_CMOD_INST := $(shell pkg-config --variable=INSTALL_CMOD $(LUA52_PKG))
+ else
+ LUA52_LMOD_INST := /usr/local/share/lua/5.2
+ LUA52_CMOD_INST := /usr/local/lib/lua/5.2
+ endif
+ lua-5.2-try: lua-5.2
+ lua-5.2-try-install: lua-5.2-install
+else
+lua-5.2-try:
+ @echo lua-scrypt: Lua 5.2 could not be found, so lua-scrypt was not built for it.
+lua-5.2-try-install:
+ @echo lua-scrypt: Lua 5.2 could not be found, so lua-scrypt was not installed for it.
+endif
LIBCRYPT_C := lib/crypto/crypto_aesctr.c \
lib/crypto/crypto_scrypt-nosse.c \
lib/crypto/crypto_scrypt-ref.c \
lib/crypto/sha256.c
+
+ifneq ($(USE_SSE),)
+ LIBCRYPT_C := $(subst -nosse.c$,-sse.c,$(LIBCRYPT_C))
+endif
+
LIBCRYPT_O := $(subst .c$,.o,$(LIBCRYPT_C))
LIBSCRYPTENC_C := lib/scryptenc/scryptenc.c lib/scryptenc/scryptenc_cpuperf.c
@@ -11,19 +112,19 @@ LIBSCRYPTENC_O := $(subst .c$,.o,$(LIBSCRYPTENC_C))
LIBUTIL_C := lib/util/memlimit.c lib/util/readpass.c lib/util/warn.c
LIBUTIL_O := $(subst .c$,.o,$(LIBUTIL_C))
-all: libscrypt.so
+SCRYPT_LIBS := libcrypt.a libscryptenc.a libutil.a
+
+all: lua-5.1-try lua-5.2-try
clean:
- $(RM) libscrypt.so
- $(RM) libcrypt.a
+ $(RM) scrypt-5.1.so scrypt-5.2.so scrypt.so
+ $(RM) $(SCRYPT_LIBS)
$(RM) $(LIBCRYPT_O)
$(RM) $(LIBSCRYPTENC_O)
$(RM) $(LIBUTIL_O)
%.o: %.c
- $(CC) $(CFLAGS) -I lib/util -I lib/crypto -c $< -o $@
-
-libscrypt.so: libcrypt.a libscryptenc.a libutil.a
+ $(CC) $(CFLAGS) -fPIC $(LUA51_INC) -I lib/util -I lib/crypto -I lib/scryptenc -c $< -o $@
libcrypt.a: $(LIBCRYPT_O)
$(AR) q libcrypt.a $(LIBCRYPT_O)
@@ -33,3 +134,25 @@ libscryptenc.a: $(LIBSCRYPTENC_O)
libutil.a: $(LIBUTIL_O)
$(AR) q libutil.a $(LIBUTIL_O)
+
+lua-5.1: scrypt-5.1.so
+ ln -s -f scrypt-5.1.so scrypt.so
+
+lua-5.1-install: lua-5.1
+ $(INSTALL) -d $(DESTDIR)$(LUA51_CMOD_INST)
+ $(INSTALL) -m 755 scrypt-5.1.so $(DESTDIR)$(LUA51_CMOD_INST)/scrypt.so
+
+scrypt-5.1.so: luascrypt.o $(SCRYPT_LIBS)
+ $(CC) $(CFLAGS) -shared -o $@ $^ $(LUA51_LIB) $(SCRYPT_LIBS)
+
+lua-5.2: scrypt-5.2.so
+ ln -s -f scrypt-5.2.so scrypt.so
+
+lua-5.2-install: lua-5.2
+ $(INSTALL) -d $(DESTDIR)$(LUA52_CMOD_INST)
+ $(INSTALL) -m 755 scrypt-5.2.so $(DESTDIR)$(LUA52_CMOD_INST)/scrypt.so
+
+scrypt-5.2.so: luascrypt.o $(SCRYPT_LIBS)
+ $(CC) $(CFLAGS) -shared -o $@ $^ $(LUA51_LIB) $(SCRYPT_LIBS)
+
+
diff --git a/luascrypt.c b/luascrypt.c
new file mode 100644
index 0000000..f863381
--- /dev/null
+++ b/luascrypt.c
@@ -0,0 +1,208 @@
+/* scrypt for Lua
+ * Copyright 2013 Rob Kendrick <rjek+luascrypt@rjek.com>
+ *
+ * Heavy based on Barry Steyn's code, and distributed under the same licence:
+ *
+ * Copyright (C) 2012 Barry Steyn (http://doctrina.org/Scrypt-Authentication-For-Node.html)
+ *
+ * This source code is provided 'as-is', without any express or implied
+ * warranty. In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this source code must not be misrepresented; you must not
+ * claim that you wrote the original source code. If you use this source code
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original source code.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * Barry Steyn barry.steyn@gmail.com
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <math.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#include "sha256.h"
+#include "sysendian.h"
+#include "crypto_scrypt.h"
+#include "memlimit.h"
+#include "scryptenc_cpuperf.h"
+
+/*
+ * Obtains salt for password hash. This function is copied from Colin Percival's scrypt reference code
+ */
+static int
+getsalt(uint8_t salt[32]) {
+ int fd;
+ ssize_t lenread;
+ uint8_t * buf = salt;
+ size_t buflen = 32;
+
+ /* Open /dev/urandom. */
+ if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
+ goto err0;
+
+ /* Read bytes until we have filled the buffer. */
+ while (buflen > 0) {
+ if ((lenread = read(fd, buf, buflen)) == -1)
+ goto err1;
+
+ /* The random device should never EOF. */
+ if (lenread == 0)
+ goto err1;
+
+ /* We're partly done. */
+ buf += lenread;
+ buflen -= lenread;
+ }
+
+ /* Close the device. */
+ while (close(fd) == -1) {
+ if (errno != EINTR)
+ goto err0;
+ }
+
+ /* Success! */
+ return (0);
+
+err1:
+ close(fd);
+err0:
+ /* Failure! */
+ return (4);
+}
+
+static int
+ls_hash_password(lua_State *L)
+{
+ const uint8_t *passwd = (const uint8_t *)luaL_checkstring(L, 1);
+ size_t passwdlen = lua_objlen(L, 1);
+ uint64_t N = luaL_checknumber(L, 2);
+ uint32_t r = luaL_checknumber(L, 3);
+ uint32_t p = luaL_checknumber(L, 4);
+
+ uint8_t dk[64], salt[32], hbuf[32], header[96];
+ uint8_t *key_hmac = &dk[32];
+
+ SHA256_CTX ctx;
+ HMAC_SHA256_CTX hctx;
+
+ int result;
+
+ errno = 0;
+ if ((result = getsalt(salt)) != 0) {
+ lua_pushstring(L, strerror(errno));
+ lua_error(L);
+ }
+
+ errno = 0;
+ if (crypto_scrypt(passwd, passwdlen, salt, 32, N, r, p, dk, 64) != 0) {
+ lua_pushstring(L, strerror(errno));
+ lua_error(L);
+ }
+
+ memcpy(header, "scrypt", 6);
+ header[6] = 0;
+ header[7] = (int)log2(N);
+ be32enc(&header[8], r);
+ be32enc(&header[12], p);
+ memcpy(&header[16], salt, 32);
+
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, header, 48);
+ SHA256_Final(hbuf, &ctx);
+ memcpy(&header[48], hbuf, 16);
+
+ HMAC_SHA256_Init(&hctx, key_hmac, 32);
+ HMAC_SHA256_Update(&hctx, header, 64);
+ HMAC_SHA256_Final(hbuf, &hctx);
+ memcpy(&header[64], hbuf, 32);
+
+ lua_pushlstring(L, (const char *)header, 96);
+ return 1;
+}
+
+static int
+ls_verify_password(lua_State *L) {
+ const uint8_t *header = (uint8_t *)luaL_checkstring(L, 1);
+ const uint8_t *passwd = (uint8_t *)luaL_checkstring(L, 2);
+ size_t headerlen = lua_objlen(L, 1);
+ size_t passwdlen = lua_objlen(L, 2);
+
+ int N;
+ uint32_t r, p;
+ uint8_t dk[64], salt[32], hbuf[32];
+ uint8_t *key_hmac = &dk[32];
+
+ HMAC_SHA256_CTX hctx;
+ SHA256_CTX ctx;
+
+ if (headerlen != 96) {
+ lua_pushliteral(L, "password hash must be 96 bytes");
+ lua_error(L);
+ }
+
+ N = (uint64_t) 1 << header[7];
+ r = be32dec(&header[8]);
+ p = be32dec(&header[12]);
+ memcpy(salt, &header[16], 32);
+
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, header, 48);
+ SHA256_Final(hbuf, &ctx);
+
+ if (memcmp(&header[48], hbuf, 16)) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "header SHA does not verify; hash corrupt");
+ return 2;
+ }
+
+ errno = 0;
+ if (crypto_scrypt(passwd, passwdlen, salt, 32, N, r, p, dk, 64) != 0) {
+ lua_pushstring(L, strerror(errno));
+ lua_error(L);
+ }
+
+ HMAC_SHA256_Init(&hctx, key_hmac, 32);
+ HMAC_SHA256_Update(&hctx, header, 64);
+ HMAC_SHA256_Final(hbuf, &hctx);
+
+ if (memcmp(hbuf, &header[64], 32)) {
+ lua_pushboolean(L, 0);
+ } else {
+ lua_pushboolean(L, 1);
+ }
+
+ return 1;
+}
+
+static const struct luaL_Reg
+ls_functions[] = {
+ { "hash_password", ls_hash_password },
+ { "verify_password", ls_verify_password },
+
+ { NULL, NULL }
+};
+
+int
+luaopen_scrypt(lua_State *L)
+{
+
+ luaL_register(L, "scrypt", ls_functions);
+ return 1;
+}