summaryrefslogtreecommitdiff
path: root/lcrypt
diff options
context:
space:
mode:
authorNicolas "Pixel" Noble <pixel@nobis-crew.org>2013-08-08 09:23:03 +0200
committerNicolas "Pixel" Noble <pixel@nobis-crew.org>2013-08-08 09:23:03 +0200
commit29e4a0512331a36c1cde22ed26c6ae059fa20757 (patch)
tree09496f029124fe4fc61aa7e014df50349128ced3 /lcrypt
parent8fd11c9821c23c69da76158c87acdefe2ae9586f (diff)
Adding libtommath, libtomcrypt and lcrypt, mainly for the bignum support.
Diffstat (limited to 'lcrypt')
-rw-r--r--lcrypt/Makefile7
-rw-r--r--lcrypt/lcrypt.c604
-rw-r--r--lcrypt/lcrypt_bits.c234
-rw-r--r--lcrypt/lcrypt_ciphers.c403
-rw-r--r--lcrypt/lcrypt_hashes.c211
-rw-r--r--lcrypt/lcrypt_math.c401
6 files changed, 1860 insertions, 0 deletions
diff --git a/lcrypt/Makefile b/lcrypt/Makefile
new file mode 100644
index 0000000..ea1ac3b
--- /dev/null
+++ b/lcrypt/Makefile
@@ -0,0 +1,7 @@
+CFLAGS += -O3 -Wall -DLITTLE_ENDIAN -DLTM_DESC -DLTC_SOURCE -DUSE_LTM -fPIC -I$(TOMCRYPT)/src/headers -I$(LUA)/src -I../src
+
+lcrypt.o: lcrypt.c lcrypt_ciphers.c lcrypt_hashes.c lcrypt_math.c lcrypt_bits.c
+ $(CC) $(CFLAGS) -c lcrypt.c -o $@
+
+clean:
+ rm -f lcrypt.o lcrypt.so
diff --git a/lcrypt/lcrypt.c b/lcrypt/lcrypt.c
new file mode 100644
index 0000000..d757f11
--- /dev/null
+++ b/lcrypt/lcrypt.c
@@ -0,0 +1,604 @@
+// gcc -Wall -O3 -shared -fPIC -DLITTLE_ENDIAN -DLTM_DESC -DLTC_SOURCE -DUSE_LTM -I/usr/include/tomcrypt -I/usr/include/tommath -lz -lutil -ltomcrypt -ltommath lcrypt.c -o /usr/lib64/lua/5.1/lcrypt.so
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <zlib.h>
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include <tomcrypt.h>
+#include <termios.h>
+
+#ifdef USE_NCIPHER
+ #include "ncipher.h"
+ extern NFastApp_Connection nfast_conn;
+ extern NFast_AppHandle nfast_app;
+#else
+ #include <pty.h>
+#endif
+
+#define likely(x) __builtin_expect((x),1)
+#define unlikely(x) __builtin_expect((x),0)
+
+#define ADD_FUNCTION(L,name) { lua_pushstring(L, #name); lua_pushcfunction(L, lcrypt_ ## name); lua_settable(L, -3); }
+#define ADD_CONSTANT(L,name) { lua_pushstring(L, #name); lua_pushinteger(L, name); lua_settable(L, -3); }
+
+static void lcrypt_error(lua_State *L, int err, void *tofree)
+{
+ if(unlikely(err != CRYPT_OK))
+ {
+ if(tofree != NULL) free(tofree);
+ lua_pushstring(L, error_to_string(err));
+ (void)lua_error(L);
+ }
+}
+
+static void* lcrypt_malloc(lua_State *L, size_t size)
+{
+ void *ret = malloc(size);
+ if(unlikely(ret == NULL))
+ {
+ lua_pushstring(L, "Out of memory");
+ (void)lua_error(L);
+ }
+ memset(ret, 0, size);
+ return ret;
+}
+
+#include "lcrypt_ciphers.c"
+#include "lcrypt_hashes.c"
+#include "lcrypt_math.c"
+#include "lcrypt_bits.c"
+
+static int lcrypt_tohex(lua_State *L)
+{
+ const char digits[] = "0123456789ABCDEF";
+ size_t in_length = 0, spacer_length = 0, prepend_length = 0;
+ const unsigned char *in;
+ const char *spacer, *prepend;
+ int i, j, pos = 0;
+ if(unlikely(lua_isnil(L, 1))) { lua_pushlstring(L, "", 0); return 1; }
+ in = (const unsigned char*)luaL_checklstring(L, 1, &in_length);
+ if(unlikely(in_length == 0)) { lua_pushlstring(L, "", 0); return 1; }
+ spacer = luaL_optlstring(L, 2, "", &spacer_length);
+ prepend = luaL_optlstring(L, 3, "", &prepend_length);
+ char *result = lcrypt_malloc(L, prepend_length + in_length * 2 + (in_length - 1) * spacer_length);
+ for(j = 0; j < (int)prepend_length; j++) result[pos++] = prepend[j];
+ result[pos++] = digits[(*in >> 4) & 0x0f];
+ result[pos++] = digits[*in++ & 0x0f];
+ for(i = 1; i < (int)in_length; i++)
+ {
+ for(j = 0; j < (int)spacer_length; j++) result[pos++] = spacer[j];
+ result[pos++] = digits[(*in >> 4) & 0x0f];
+ result[pos++] = digits[*in++ & 0x0f];
+ }
+ lua_pushlstring(L, result, pos);
+ free(result);
+ return 1;
+}
+
+static int lcrypt_fromhex(lua_State *L)
+{
+ size_t in_length;
+ const unsigned char *in = (const unsigned char*)luaL_checklstring(L, 1, &in_length);
+ unsigned char result[in_length];
+ int i, d = -1, e = -1, pos = 0;
+ for(i = 0; i < (int)in_length; i++)
+ {
+ if(d == -1)
+ {
+ if(*in >= '0' && *in <= '9')
+ d = *in - '0';
+ else if(*in >= 'A' && *in <= 'F')
+ d = *in - 'A' + 10;
+ else if(*in >= 'a' && *in <= 'f')
+ d = *in - 'a' + 10;
+ }
+ else if(e == -1)
+ {
+ if(*in >= '0' && *in <= '9')
+ e = *in - '0';
+ else if(*in >= 'A' && *in <= 'F')
+ e = *in - 'A' + 10;
+ else if(*in >= 'a' && *in <= 'f')
+ e = *in - 'a' + 10;
+ }
+ if(d >= 0 && e >= 0)
+ {
+ result[pos++] = d << 4 | e;
+ d = e = -1;
+ }
+ in++;
+ }
+ lua_pushlstring(L, (char*)result, pos);
+ return 1;
+}
+
+static int lcrypt_compress(lua_State *L)
+{
+ int err;
+ size_t inlen;
+ const unsigned char *in = (const unsigned char*)luaL_checklstring(L, 1, &inlen);
+ uLongf outlen = compressBound(inlen);
+ unsigned char *out = lcrypt_malloc(L, outlen);
+ if(unlikely((err = compress(out, &outlen, in, inlen)) != Z_OK))
+ {
+ free(out);
+ lua_pushstring(L, zError(err));
+ return lua_error(L);
+ }
+ lua_pushlstring(L, (char*)out, outlen);
+ free(out);
+ return 1;
+}
+
+static int lcrypt_uncompress(lua_State *L)
+{
+ int i, err;
+ size_t inlen;
+ const unsigned char *in = (const unsigned char*)luaL_checklstring(L, 1, &inlen);
+ uLongf outlen = inlen << 1;
+ unsigned char *out = NULL;
+ for(i = 2; i < 16; i++)
+ {
+ out = lcrypt_malloc(L, outlen);
+ if(likely((err = uncompress(out, &outlen, in, inlen)) == Z_OK)) break;
+ if(unlikely(err != Z_BUF_ERROR))
+ {
+ free(out);
+ lua_pushstring(L, zError(err));
+ return lua_error(L);
+ }
+ free(out);
+ outlen = inlen << i;
+ }
+ if(unlikely(err == Z_BUF_ERROR))
+ {
+ free(out);
+ lua_pushstring(L, zError(err));
+ return lua_error(L);
+ }
+ lua_pushlstring(L, (char*)out, outlen);
+ free(out);
+ return 1;
+}
+
+static int lcrypt_base64_encode(lua_State *L)
+{
+ size_t inlen;
+ const unsigned char *in = (const unsigned char*)luaL_checklstring(L, 1, &inlen);
+ unsigned long outlen = (inlen + 3) * 4 / 3;
+ unsigned char *out = malloc(outlen);
+ if(out == NULL) return 0;
+ lcrypt_error(L, base64_encode(in, inlen, out, &outlen), out);
+ lua_pushlstring(L, (char*)out, outlen);
+ free(out);
+ return 1;
+}
+
+static int lcrypt_base64_decode(lua_State *L)
+{
+ size_t inlen;
+ const unsigned char *in = (const unsigned char*)luaL_checklstring(L, 1, &inlen);
+ unsigned long outlen = inlen * 3 / 4;
+ unsigned char *out = malloc(outlen);
+ if(out == NULL) return 0;
+ lcrypt_error(L, base64_decode(in, inlen, out, &outlen), out);
+ lua_pushlstring(L, (char*)out, outlen);
+ free(out);
+ return 1;
+}
+
+static int lcrypt_xor(lua_State *L)
+{
+ int i;
+ size_t a_length, b_length;
+ const unsigned char *a = (const unsigned char*)luaL_checklstring(L, 1, &a_length);
+ const unsigned char *b = (const unsigned char*)luaL_checklstring(L, 2, &b_length);
+ unsigned char *c = NULL;
+ if(a_length > b_length)
+ {
+ size_t temp = a_length;
+ a_length = b_length;
+ b_length = temp;
+ c = (void*)a; a = b; b = c;
+ }
+ c = lcrypt_malloc(L, b_length);
+ for(i = 0; i < a_length; i++) c[i] = a[i] ^ b[i];
+ for(; i < b_length; i++) c[i] = b[i];
+ lua_pushlstring(L, (char*)c, b_length);
+ free(c);
+ return 1;
+}
+
+static int lcrypt_sleep(lua_State *L)
+{
+ usleep(1000000.0 * luaL_checknumber(L, 1));
+ return(0);
+}
+
+static int lcrypt_time(lua_State *L)
+{
+ double ret;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ ret = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+ lua_pushnumber(L, ret);
+ return(1);
+}
+
+static int lcrypt_random(lua_State *L)
+{
+ int len = luaL_checkint(L, 1);
+ #ifdef USE_NCIPHER
+ M_Command command;
+ M_Reply reply;
+ M_Status rc;
+ memset(&command, 0, sizeof(command));
+ memset(&reply, 0, sizeof(reply));
+ command.cmd = Cmd_GenerateRandom;
+ command.args.generaterandom.lenbytes = len;
+ if(unlikely((rc = NFastApp_Transact(nfast_conn, NULL, &command, &reply, NULL)) != Status_OK))
+ {
+ lua_pushstring(L, NF_Lookup(rc, NF_Status_enumtable));
+ (void)lua_error(L);
+ }
+ if(unlikely(reply.status != Status_OK))
+ {
+ lua_pushstring(L, NF_Lookup(reply.status, NF_Status_enumtable));
+ (void)lua_error(L);
+ }
+ if(unlikely(len != reply.reply.generaterandom.data.len))
+ {
+ lua_pushstring(L, "Wrong length returned");
+ (void)lua_error(L);
+ }
+ lua_pushlstring(L, reply.reply.generaterandom.data.ptr, len);
+ NFastApp_Free_Reply(nfast_app, NULL, NULL, &reply);
+ #else
+ FILE *fp;
+ char *buffer = lcrypt_malloc(L, len);
+ if(unlikely((fp = fopen("/dev/urandom", "rb")) == NULL))
+ {
+ lua_pushstring(L, "Unable to open /dev/urandom.");
+ (void)lua_error(L);
+ }
+ if(unlikely(fread(buffer, len, 1, fp) != 1))
+ {
+ fclose(fp);
+ lua_pushstring(L, "Unable to read /dev/urandom.");
+ (void)lua_error(L);
+ }
+ fclose(fp);
+ lua_pushlstring(L, buffer, len);
+ free(buffer);
+ #endif
+ return 1;
+}
+
+static FILE *lgetfile(lua_State *L, int index)
+{
+ FILE **fp = lua_touserdata(L, index);
+ if(unlikely(fp == NULL)) return NULL;
+ if(lua_getmetatable(L, index))
+ {
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
+ if(lua_rawequal(L, -1, -2))
+ {
+ lua_pop(L, 2);
+ return *fp;
+ }
+ lua_pop(L, 2);
+ }
+ return NULL;
+}
+
+static int lcrypt_tcsetattr(lua_State* L)
+{
+ struct termios old, new;
+ FILE *fp = lgetfile(L, 1);
+ if(unlikely(fp == NULL)) return 0;
+ if(unlikely(tcgetattr(fileno(fp), &old) != 0)) return 0;
+ new = old;
+ new.c_iflag = luaL_optint(L, 2, old.c_iflag);
+ new.c_oflag = luaL_optint(L, 3, old.c_oflag);
+ new.c_cflag = luaL_optint(L, 4, old.c_cflag);
+ new.c_lflag = luaL_optint(L, 5, old.c_lflag);
+ if(unlikely(tcsetattr(fileno(fp), TCSAFLUSH, &new) != 0)) return 0;
+ lua_pushinteger(L, new.c_iflag);
+ lua_pushinteger(L, new.c_oflag);
+ lua_pushinteger(L, new.c_cflag);
+ lua_pushinteger(L, new.c_lflag);
+ return 4;
+}
+
+static int lcrypt_flag_add(lua_State *L)
+{
+ uint32_t a = luaL_checkint(L, 1);
+ uint32_t b = luaL_checkint(L, 2);
+ lua_pushinteger(L, a | b);
+ return 1;
+}
+
+static int lcrypt_flag_remove(lua_State *L)
+{
+ uint32_t a = luaL_checkint(L, 1);
+ uint32_t b = luaL_checkint(L, 2);
+ lua_pushinteger(L, a & ~b);
+ return 1;
+}
+
+#ifndef USE_NCIPHER
+
+typedef struct
+{
+ int fd;
+ int pid;
+ char *command;
+} lcrypt_spawn_t;
+
+static int lcrypt_spawn(lua_State *L)
+{
+ int fd, pid, argc;
+ #define MAX_ARGUMENT 128
+ const char *command = luaL_checkstring(L, 1);
+ char *cmd = strdup(command);
+ char *pos = cmd, *p;
+ char *argv[MAX_ARGUMENT];
+ for(argc = 0; argc < MAX_ARGUMENT-1; argc++)
+ {
+ // eat whitespace
+ while(*pos == ' ' || *pos == '\t' || *pos == '\n' || *pos == '\r')
+ {
+ if(*pos == '\\') for(p = pos; *p != '\0'; p++) *p = *(p + 1);
+ pos++;
+ }
+ // start of argument found
+ argv[argc] = pos;
+ if(*argv[argc] == '"' || *argv[argc] == '\'') // quoted argument
+ {
+ pos++;
+ while(*pos != *argv[argc] && *pos != '\0')
+ {
+ if(*pos == '\\') for(p = pos; *p != '\0'; p++) *p = *(p + 1);
+ pos++;
+ }
+ argv[argc]++;
+ }
+ else // non-quoted argument
+ {
+ while(*pos != ' ' && *pos != '\t' && *pos != '\n' && *pos != '\r' && *pos != '\0')
+ {
+ if(*pos == '\\') for(p = pos; *p != '\0'; p++) *p = *(p + 1);
+ pos++;
+ }
+ }
+ if(*pos == '\0') break;
+ *pos++ = '\0';
+ }
+ argv[++argc] = NULL;
+
+ errno = 0;
+ pid = forkpty(&fd, NULL, NULL, NULL);
+ if(pid == 0) // child
+ {
+ execvp(argv[0], argv);
+ // if we get here, it's an error!
+ perror("'unable to spawn process");
+ return 0;
+ }
+ else if(errno != 0)
+ {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ return 2;
+ }
+ else
+ {
+ lcrypt_spawn_t *lsp = lua_newuserdata(L, sizeof(lcrypt_spawn_t));
+ lsp->fd = fd;
+ lsp->pid = pid;
+ lsp->command = cmd;
+ luaL_getmetatable(L, "LSPAWN");
+ (void)lua_setmetatable(L, -2);
+ return 1;
+ }
+}
+
+static int lcrypt_spawn_close(lua_State *L)
+{
+ lcrypt_spawn_t *lsp = (lcrypt_spawn_t*)luaL_checkudata(L, 1, "LSPAWN");
+ if(lsp->pid > 0)
+ {
+ (void)kill(lsp->pid, SIGQUIT);
+ lsp->pid = -1;
+ }
+ if(lsp->fd >= 0)
+ {
+ (void)close(lsp->fd);
+ lsp->fd = -1;
+ }
+ if(lsp->command != NULL)
+ {
+ free(lsp->command);
+ lsp->command = NULL;
+ }
+ return 0;
+}
+
+static int lcrypt_spawn_read(lua_State *L)
+{
+ lcrypt_spawn_t *lsp = (lcrypt_spawn_t*)luaL_checkudata(L, 1, "LSPAWN");
+ int count = luaL_optint(L, 2, 4096);
+ char *buffer;
+ if(lsp->fd < 0)
+ {
+ lua_pushstring(L, "Spawn closed");
+ lua_error(L);
+ return 0;
+ }
+ if((buffer = malloc(count)) == NULL)
+ {
+ lua_pushnil(L);
+ lua_pushstring(L, "Unable to allocate memory");
+ return 2;
+ }
+ count = read(lsp->fd, buffer, count);
+ if(errno != 0)
+ {
+ free(buffer);
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ return 2;
+ }
+ lua_pushlstring(L, buffer, count);
+ free(buffer);
+ return 1;
+}
+
+static int lcrypt_spawn_write(lua_State *L)
+{
+ lcrypt_spawn_t *lsp = (lcrypt_spawn_t*)luaL_checkudata(L, 1, "LSPAWN");
+ size_t in_length = 0;
+ const char* in = luaL_checklstring(L, 2, &in_length);
+ if(lsp->fd < 0)
+ {
+ lua_pushstring(L, "closed");
+ lua_error(L);
+ return 0;
+ }
+ write(lsp->fd, in, in_length);
+ if(errno != 0)
+ {
+ lua_pushstring(L, strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+static int lcrypt_spawn_index(lua_State *L)
+{
+ (void)luaL_checkudata(L, 1, "LSPAWN");
+ const char *index = luaL_checkstring(L, 2);
+ if(strcmp(index, "read") == 0)
+ lua_pushcfunction(L, lcrypt_spawn_read);
+ else if(strcmp(index, "write") == 0)
+ lua_pushcfunction(L, lcrypt_spawn_write);
+ else if(strcmp(index, "close") == 0)
+ lua_pushcfunction(L, lcrypt_spawn_close);
+ else
+ return 0;
+ return 1;
+}
+
+static const luaL_Reg lcrypt_spawn_flib[] =
+{
+ {"__gc", lcrypt_spawn_close},
+ {NULL, NULL}
+};
+
+#endif
+
+static const luaL_Reg lcryptlib[] =
+{
+ {"tohex", lcrypt_tohex},
+ {"fromhex", lcrypt_fromhex},
+ {"compress", lcrypt_compress},
+ {"uncompress", lcrypt_uncompress},
+ {"base64_encode", lcrypt_base64_encode},
+ {"base64_decode", lcrypt_base64_decode},
+ {"xor", lcrypt_xor},
+ {"sleep", lcrypt_sleep},
+ {"time", lcrypt_time},
+ {"random", lcrypt_random},
+ {"tcsetattr", lcrypt_tcsetattr},
+ {"flag_add", lcrypt_flag_add},
+ {"flag_remove", lcrypt_flag_remove},
+ #ifndef USE_NCIPHER
+ {"spawn", lcrypt_spawn},
+ #endif
+ {NULL, NULL}
+};
+
+int luaopen_lcrypt(lua_State *L);
+int luaopen_lcrypt(lua_State *L)
+{
+ luaL_register(L, "lcrypt", lcryptlib);
+
+ #ifndef USE_NCIPHER
+ (void)luaL_newmetatable(L, "LSPAWN");
+ lua_pushliteral(L, "__index");
+ lua_pushcfunction(L, lcrypt_spawn_index);
+ lua_rawset(L, -3);
+ luaL_register(L, NULL, lcrypt_spawn_flib);
+ #endif
+
+ lua_getglobal(L, "lcrypt");
+
+ lcrypt_start_ciphers(L);
+ lcrypt_start_hashes(L);
+ lcrypt_start_math(L);
+ lcrypt_start_bits(L);
+
+ lua_pushstring(L, "iflag");
+ lua_newtable(L);
+ ADD_CONSTANT(L, IGNBRK); ADD_CONSTANT(L, BRKINT); ADD_CONSTANT(L, IGNPAR); ADD_CONSTANT(L, PARMRK);
+ ADD_CONSTANT(L, INPCK); ADD_CONSTANT(L, ISTRIP); ADD_CONSTANT(L, INLCR); ADD_CONSTANT(L, IGNCR);
+ ADD_CONSTANT(L, ICRNL); ADD_CONSTANT(L, IXON); ADD_CONSTANT(L, IXANY); ADD_CONSTANT(L, IXOFF);
+ lua_settable(L, -3);
+
+ lua_pushstring(L, "oflag");
+ lua_newtable(L);
+ #ifdef OLCUC
+ ADD_CONSTANT(L, OLCUC);
+ #endif
+ #ifdef OFILL
+ ADD_CONSTANT(L, OFILL);
+ #endif
+ #ifdef OFDEL
+ ADD_CONSTANT(L, OFDEL);
+ #endif
+ #ifdef NLDLY
+ ADD_CONSTANT(L, NLDLY);
+ #endif
+ #ifdef CRDLY
+ ADD_CONSTANT(L, CRDLY);
+ #endif
+ #ifdef TABDLY
+ ADD_CONSTANT(L, TABDLY);
+ #endif
+ #ifdef BSDLY
+ ADD_CONSTANT(L, BSDLY);
+ #endif
+ #ifdef VTDLY
+ ADD_CONSTANT(L, VTDLY);
+ #endif
+ #ifdef FFDLY
+ ADD_CONSTANT(L, FFDLY);
+ #endif
+ ADD_CONSTANT(L, OPOST); ADD_CONSTANT(L, ONLCR); ADD_CONSTANT(L, OCRNL); ADD_CONSTANT(L, ONOCR);
+ ADD_CONSTANT(L, ONLRET);
+ lua_settable(L, -3);
+
+ lua_pushstring(L, "cflag");
+ lua_newtable(L);
+ ADD_CONSTANT(L, CS5); ADD_CONSTANT(L, CS6); ADD_CONSTANT(L, CS7); ADD_CONSTANT(L, CS8);
+ ADD_CONSTANT(L, CSTOPB); ADD_CONSTANT(L, CREAD); ADD_CONSTANT(L, PARENB); ADD_CONSTANT(L, PARODD);
+ ADD_CONSTANT(L, HUPCL); ADD_CONSTANT(L, CLOCAL);
+ lua_settable(L, -3);
+
+ lua_pushstring(L, "lflag");
+ lua_newtable(L);
+ ADD_CONSTANT(L, ISIG); ADD_CONSTANT(L, ICANON); ADD_CONSTANT(L, ECHO); ADD_CONSTANT(L, ECHOE);
+ ADD_CONSTANT(L, ECHOK); ADD_CONSTANT(L, ECHONL); ADD_CONSTANT(L, NOFLSH); ADD_CONSTANT(L, TOSTOP);
+ ADD_CONSTANT(L, IEXTEN);
+ lua_settable(L, -3);
+
+ lua_pop(L, 1);
+ return 1;
+}
diff --git a/lcrypt/lcrypt_bits.c b/lcrypt/lcrypt_bits.c
new file mode 100644
index 0000000..0ea7851
--- /dev/null
+++ b/lcrypt/lcrypt_bits.c
@@ -0,0 +1,234 @@
+#include <stdint.h>
+
+static void copy_bits(uint8_t *out, unsigned int out_pos, const uint8_t *in, unsigned int in_pos, unsigned int length)
+{
+ unsigned int offset, chunk_size;
+ uint8_t temp, mask;
+
+ // skip untouched out bytes
+ offset = out_pos / 8;
+ out += offset;
+ out_pos -= offset * 8;
+
+ // skip untouched in bytes
+ offset = in_pos / 8;
+ in += offset;
+ in_pos -= offset * 8;
+
+ while(length > 0)
+ {
+ chunk_size = (in_pos < out_pos) ? 8 - out_pos : 8 - in_pos;
+ if(chunk_size == 0) chunk_size = 8;
+ if(chunk_size > length) chunk_size = length;
+
+ temp = ((*in) << in_pos);
+ temp >>= out_pos;
+ mask = 0xff << (8 - chunk_size);
+ mask = /*0xff ^*/ (mask >> out_pos);
+ *out |= mask & temp;
+
+ in_pos += chunk_size;
+ if(in_pos >= 8)
+ {
+ in++;
+ in_pos -= 8;
+ }
+ out_pos += chunk_size;
+ if(out_pos >= 8)
+ {
+ out++;
+ out_pos -= 8;
+ }
+ length -= chunk_size;
+ }
+}
+
+static void reverse_data(uint8_t *a, int len)
+{
+ int i;
+ uint8_t temp;
+ for(i = len / 2 - 1; i >= 0; i--)
+ {
+ temp = a[i];
+ a[i] = a[len-1-i];
+ a[len-1-i] = temp;
+ }
+}
+
+static uint64_t reverse_bits(uint64_t a, int bits)
+{
+ int i;
+ uint64_t b = 0;
+ for(i = 0; i < bits; i++)
+ {
+ b = (b << 1) | (a & 1);
+ a >>= 1;
+ }
+ return b;
+}
+
+static int64_t sign_extend(uint64_t a, int bits)
+{
+ int64_t sret;;
+ if((a & (1 << (bits - 1))) != 0)
+ {
+ a = ((uint64_t)0xffffffffffffffffLL << bits) | a;
+ memcpy(&sret, &a, 8);
+ return sret;
+ }
+ return a;
+}
+
+#define B_SKIP 0
+#define B_STR 1
+#define B_INT 2
+#define B_LSB 4
+#define B_LE 8
+#define B_SIGN 16
+
+#define BSKIP B_SKIP
+#define BSTR B_STR
+#define BMSB B_INT
+#define BLSB (B_INT|B_LSB)
+#define BLE (B_INT|B_LE)
+#define BSMSB (B_INT|B_SIGN)
+#define BSLSB (B_INT|B_LSB|B_SIGN)
+#define BSLE (B_INT|B_LE|B_SIGN)
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ #define BMO BLE
+ #define BSMO BSLE
+#else
+ #define BMO BMSB
+ #define BSMO BSMSB
+#endif
+
+static int lcrypt_bget(lua_State *L)
+{
+ int count = 0, argc = lua_gettop(L);
+ size_t length;
+ const unsigned char *in = (const unsigned char*)luaL_checklstring(L, 1, &length);
+ int i, type, bits, offset = luaL_checkint(L, 2);
+ length *= 8;
+ for(i = 3; i <= argc && offset < (int)length; i += 2)
+ {
+ type = luaL_checkint(L, i);
+ if(i+1 > argc)
+ bits = length;
+ else
+ bits = luaL_checkint(L, i+1);
+
+ if(offset + bits > (int)length) bits = length - offset;
+ if(type == B_SKIP)
+ {
+ count--;
+ }
+ else if(type == B_STR)
+ {
+ int len = (bits + 7) / 8;
+ uint8_t data[len];
+ memset(data, 0, len);
+ copy_bits(data, 0, in, offset, bits);
+ lua_pushlstring(L, (char*)data, len);
+ }
+ else // integer
+ {
+ uint64_t ret = 0;
+ copy_bits((uint8_t*)&ret, sizeof(ret) * 8 - bits, in, offset, bits);
+ #if BYTE_ORDER == LITTLE_ENDIAN
+ reverse_data((uint8_t*)&ret, sizeof(ret));
+ #endif
+ if((type & B_LSB) == B_LSB) ret = reverse_bits(ret, bits);
+ #if BYTE_ORDER == LITTLE_ENDIAN
+ if((type & B_LE) == B_LE) reverse_data((uint8_t*)&ret, (bits+7)/8);
+ #else
+ if((type & B_LE) == B_LE) reverse_data((uint8_t*)&ret + 8-(bits+7)/8, (bits+7)/8);
+ #endif
+ if((type & B_SIGN) == B_SIGN)
+ lua_pushnumber(L, sign_extend(ret, bits));
+ else
+ lua_pushnumber(L, ret);
+ }
+ count++;
+ offset += bits;
+ }
+ return count;
+}
+
+static int lcrypt_bput(lua_State *L)
+{
+ int argc = lua_gettop(L);
+ int i, type, bits = 0, offset = 0, len = 0;
+ size_t length;
+ for(i = 1; i <= argc; i += 3)
+ {
+ type = luaL_checkint(L, i+1);
+ if(type == B_STR && lua_isnil(L, i+2) == 1)
+ {
+ (void)luaL_checklstring(L, i, &length);
+ bits = (lua_isnil(L, i+2) == 1) ? length * 8 : luaL_checkint(L, i+2);
+ if(bits > (int)length * 8) bits = length * 8;
+ }
+ else
+ {
+ bits = luaL_checkint(L, i+2);
+ }
+ len += bits;
+ }
+ len = (len + 7) / 8;
+ uint8_t ret[len];
+ memset(ret, 0, len);
+
+ for(i = 1; i <= argc; i += 3)
+ {
+ type = luaL_checkint(L, i+1);
+ if(type == B_STR)
+ {
+ const uint8_t *in = (const uint8_t *)luaL_checklstring(L, i, &length);
+ bits = (lua_isnil(L, i+2) == 1) ? length * 8 : luaL_checkint(L, i+2);
+ if(bits > (int)length * 8) bits = length * 8;
+ copy_bits(ret, offset, in, 0, bits);
+ }
+ else if(type != B_SKIP) // integer
+ {
+ uint64_t in;
+ bits = luaL_checkint(L, i+2);
+ if((type & B_SIGN) == B_SIGN)
+ {
+ int64_t sin = luaL_checknumber(L, i);
+ memcpy(&in, &sin, 8);
+ }
+ else
+ {
+ in = luaL_checknumber(L, i);
+ }
+ #if BYTE_ORDER == LITTLE_ENDIAN
+ reverse_data((uint8_t*)&in, sizeof(in));
+ #endif
+
+ if((type & B_LSB) == B_LSB)
+ {
+ in = reverse_bits(in, 64);
+ copy_bits(ret, offset, (uint8_t*)&in, 0, bits);
+ }
+ else if((type & B_LE) == B_LE)
+ {
+ reverse_data((uint8_t*)&in, sizeof(in));
+ copy_bits(ret, offset, (uint8_t*)&in, 0, bits);
+ }
+ else
+ copy_bits(ret, offset, (uint8_t*)&in, sizeof(in) * 8 - bits, bits);
+ }
+ offset += bits;
+ }
+ lua_pushlstring(L, (char*)ret, len);
+ return 1;
+}
+
+static void lcrypt_start_bits(lua_State *L)
+{
+ ADD_FUNCTION(L, bget); ADD_FUNCTION(L, bput);
+ ADD_CONSTANT(L, BSKIP); ADD_CONSTANT(L, BSTR); ADD_CONSTANT(L, BMSB); ADD_CONSTANT(L, BLSB);
+ ADD_CONSTANT(L, BLE); ADD_CONSTANT(L, BSMSB); ADD_CONSTANT(L, BSLSB); ADD_CONSTANT(L, BSLE);
+ ADD_CONSTANT(L, BMO); ADD_CONSTANT(L, BSMO);
+}
diff --git a/lcrypt/lcrypt_ciphers.c b/lcrypt/lcrypt_ciphers.c
new file mode 100644
index 0000000..dc8c47b
--- /dev/null
+++ b/lcrypt/lcrypt_ciphers.c
@@ -0,0 +1,403 @@
+static void lcrypt_ivlength(lua_State *L, int cipher, size_t *iv_length)
+{
+ if(unlikely(*iv_length < (size_t)cipher_descriptor[cipher].block_length))
+ {
+ lua_pushstring(L, "IV wrong length");
+ (void)lua_error(L);
+ }
+ *iv_length = (size_t)cipher_descriptor[cipher].block_length;
+}
+
+#define LCRYPT_CIPHER_XXX_START(NAME, name) \
+static int lcrypt_cipher_ ## name (lua_State *L) \
+{ \
+ symmetric_ ## NAME *skey; \
+ int err = CRYPT_OK, *cipher = luaL_checkudata(L, 1, "LCRYPT_CIPHER"); \
+ size_t key_length, iv_length; \
+ const unsigned char *key = (const unsigned char *)luaL_checklstring(L, 2, &key_length); \
+ const unsigned char *iv = (const unsigned char *)luaL_checklstring(L, 3, &iv_length); \
+ lcrypt_ivlength(L, *cipher, &iv_length); \
+ skey = lua_newuserdata(L, sizeof(symmetric_ ## NAME)); \
+ luaL_getmetatable(L, "LCRYPT_CIPHER_" #NAME); \
+ (void)lua_setmetatable(L, -2); \
+ memset(skey, 0, sizeof(symmetric_ ## NAME)); \
+ if(unlikely((err = name ## _start(*cipher, iv, key, (int)key_length, 0, skey)) != CRYPT_OK)) \
+ { \
+ skey->cipher = -1; \
+ lcrypt_error(L, err, NULL); \
+ } \
+ return 1; \
+}
+
+#define LCRYPT_CIPHER_XXX_INDEX(NAME, _name) \
+static int lcrypt_cipher_ ## _name ## _index(lua_State *L) \
+{ \
+ symmetric_ ## NAME *skey = luaL_checkudata(L, 1, "LCRYPT_CIPHER_" #NAME); \
+ if(unlikely(skey->cipher < 0)) return 0; \
+ const char *index = luaL_checkstring(L, 2); \
+ if(strcmp(index, "type") == 0) { lua_pushstring(L, "LCRYPT_CIPHER_" #NAME); return 1; } \
+ if(strcmp(index, "iv") == 0) \
+ { \
+ unsigned char iv[MAXBLOCKSIZE]; \
+ unsigned long length = MAXBLOCKSIZE; \
+ lcrypt_error(L, _name ## _getiv(iv, &length, skey), NULL); \
+ lua_pushlstring(L, (char*)iv, (size_t)length); \
+ return 1; \
+ } \
+ if(strcmp(index, "block_size") == 0) \
+ { \
+ lua_pushinteger(L, cipher_descriptor[skey->cipher].block_length); \
+ return 1; \
+ } \
+ if(strcmp(index, "encrypt") == 0) \
+ { \
+ lua_pushcfunction(L, lcrypt_cipher_ ## _name ## _encrypt); \
+ return 1; \
+ } \
+ if(strcmp(index, "decrypt") == 0) \
+ { \
+ lua_pushcfunction(L, lcrypt_cipher_ ## _name ## _decrypt); \
+ return 1; \
+ } \
+ if(strcmp(index, "cipher_name") == 0) \
+ { \
+ lua_pushstring(L, cipher_descriptor[skey->cipher].name); \
+ return 1; \
+ } \
+ if(strcmp(index, "mode_name") == 0) \
+ { \
+ lua_pushstring(L, #_name); \
+ return 1; \
+ } \
+ return 0; \
+}
+
+#define LCRYPT_CIPHER_XXX_NEWINDEX(NAME, name) \
+static int lcrypt_cipher_ ## name ## _newindex(lua_State *L) \
+{ \
+ symmetric_ ## NAME *skey = luaL_checkudata(L, 1, "LCRYPT_CIPHER_" #NAME); \
+ size_t v_length = 0; \
+ const char *index = luaL_checkstring(L, 2); \
+ const unsigned char *v = (const unsigned char *)luaL_checklstring(L, 3, &v_length); \
+ if(unlikely(skey->cipher < 0)) return 0; \
+ if(strcmp(index, "iv") == 0) \
+ { \
+ lcrypt_error(L, name ## _setiv(v, v_length, skey), NULL); \
+ } \
+ return 0; \
+}
+
+#define LCRYPT_CIPHER_XXX_GC(NAME, name) \
+static int lcrypt_cipher_ ## name ## _gc(lua_State *L) \
+{ \
+ symmetric_ ## NAME *skey = luaL_checkudata(L, 1, "LCRYPT_CIPHER_" #NAME); \
+ if(likely(skey->cipher != -1)) lcrypt_error(L, name ## _done(skey), NULL); \
+ return 0; \
+}
+
+#define LCRYPT_CIPHER_XXX_ENCRYPT(NAME, name) \
+static int lcrypt_cipher_ ## name ## _encrypt(lua_State *L) \
+{ \
+ symmetric_ ## NAME *skey = luaL_checkudata(L, 1, "LCRYPT_CIPHER_" #NAME); \
+ if(likely(skey->cipher >= 0)) \
+ { \
+ size_t in_length = 0; \
+ const unsigned char *in = (const unsigned char *)luaL_checklstring(L, 2, &in_length); \
+ int i, block_length = cipher_descriptor[skey->cipher].block_length; \
+ int padding_length = in_length + block_length - in_length % block_length; \
+printf("in_length = %d, padding_length = %d\n", in_length, padding_length); \
+ unsigned char *out = lcrypt_malloc(L, 2 * (in_length + padding_length)); \
+ memcpy(out + in_length + padding_length, in, in_length); \
+ memset(out + in_length + padding_length + in_length, padding_length, padding_length); \
+ in = out + in_length + padding_length; \
+ for(i = 0; i < in_length + padding_length; i += block_length) \
+ { \
+ lcrypt_error(L, name ## _encrypt(in + i, out + i, block_length, skey), out); \
+ } \
+ lua_pushlstring(L, (char*)out, in_length + padding_length); \
+ free(out); \
+ return 1; \
+ } \
+ return 0; \
+}
+
+#define LCRYPT_CIPHER_XXX_DECRYPT(NAME, name) \
+static int lcrypt_cipher_ ## name ## _decrypt(lua_State *L) \
+{ \
+ symmetric_ ## NAME *skey = luaL_checkudata(L, 1, "LCRYPT_CIPHER_" #NAME); \
+ if(likely(skey->cipher >= 0)) \
+ { \
+ size_t in_length = 0; \
+ const unsigned char *in = (const unsigned char *)luaL_checklstring(L, 2, &in_length); \
+ unsigned char *out = lcrypt_malloc(L, in_length); \
+ lcrypt_error(L, name ## _decrypt(in, out, in_length, skey), out); \
+ in_length -= out[in_length - 1]; \
+ lua_pushlstring(L, (char*)out, in_length); \
+ free(out); \
+ return 1; \
+ } \
+ return 0; \
+}
+
+#define LCRYPT_CIPHER_XXX(NAME, name) \
+ LCRYPT_CIPHER_XXX_START(NAME, name) \
+ LCRYPT_CIPHER_XXX_NEWINDEX(NAME, name) \
+ LCRYPT_CIPHER_XXX_GC(NAME, name) \
+ LCRYPT_CIPHER_XXX_ENCRYPT(NAME, name) \
+ LCRYPT_CIPHER_XXX_DECRYPT(NAME, name) \
+ LCRYPT_CIPHER_XXX_INDEX(NAME, name)
+
+static int lcrypt_cipher_ecb(lua_State *L)
+{
+ int err = CRYPT_OK, *cipher = luaL_checkudata(L, 1, "LCRYPT_CIPHER");
+ size_t key_length;
+ const unsigned char *key = (const unsigned char *)luaL_checklstring(L, 2, &key_length);
+ symmetric_ECB *skey = lua_newuserdata(L, sizeof(symmetric_ECB));
+ memset(skey, 0, sizeof(symmetric_ECB));
+ luaL_getmetatable(L, "LCRYPT_CIPHER_ECB");
+ (void)lua_setmetatable(L, -2);
+ if(unlikely((err = ecb_start(*cipher, key, (int)key_length, 0, skey)) != CRYPT_OK))
+ {
+ skey->cipher = -1;
+ lcrypt_error(L, err, NULL);
+ }
+ return 1;
+}
+
+LCRYPT_CIPHER_XXX_ENCRYPT(ECB, ecb)
+LCRYPT_CIPHER_XXX_DECRYPT(ECB, ecb)
+
+static int lcrypt_cipher_ecb_index(lua_State *L)
+{
+ symmetric_ECB *skey = luaL_checkudata(L, 1, "LCRYPT_CIPHER_ECB");
+ const char *index = luaL_checkstring(L, 2);
+ if(unlikely(skey->cipher < 0)) return 0;
+ if(strcmp(index, "type") == 0) { lua_pushstring(L, "LCRYPT_CIPHER_ECB"); return 1; }
+ if(strcmp(index, "encrypt") == 0)
+ {
+ lua_pushcfunction(L, lcrypt_cipher_ecb_encrypt);
+ return 1;
+ }
+ if(strcmp(index, "decrypt") == 0)
+ {
+ lua_pushcfunction(L, lcrypt_cipher_ecb_decrypt);
+ return 1;
+ }
+ if(strcmp(index, "cipher_name") == 0)
+ {
+ lua_pushstring(L, cipher_descriptor[skey->cipher].name);
+ return 1;
+ }
+ if(strcmp(index, "mode_name") == 0)
+ {
+ lua_pushstring(L, "ecb");
+ return 1;
+ }
+ return 0;
+}
+
+static int lcrypt_cipher_ecb_newindex(lua_State *L)
+{
+ luaL_checkudata(L, 1, "LCRYPT_CIPHER_ECB");
+ return 0;
+}
+
+LCRYPT_CIPHER_XXX_GC(ECB, ecb)
+
+static int lcrypt_cipher_ctr(lua_State *L)
+{
+ symmetric_CTR *skey;
+ int err = CRYPT_OK, *cipher = luaL_checkudata(L, 1, "LCRYPT_CIPHER");
+ size_t key_length, iv_length;
+ const unsigned char *key = (const unsigned char *)luaL_checklstring(L, 2, &key_length);
+ const unsigned char *iv = (const unsigned char *)luaL_checklstring(L, 3, &iv_length);
+ const char *endian = luaL_optstring(L, 4, "big");
+ lcrypt_ivlength(L, *cipher, &iv_length);
+ skey = lua_newuserdata(L, sizeof(symmetric_CTR));
+ memset(skey, 0, sizeof(symmetric_CTR));
+ luaL_getmetatable(L, "LCRYPT_CIPHER_CTR");
+ (void)lua_setmetatable(L, -2);
+ if(strcmp(endian, "big") == 0)
+ {
+ err = ctr_start(*cipher, iv, key, (int)key_length, 0, CTR_COUNTER_BIG_ENDIAN, skey);
+ }
+ else if(strcmp(endian, "little") == 0)
+ {
+ err = ctr_start(*cipher, iv, key, (int)key_length, 0, CTR_COUNTER_LITTLE_ENDIAN, skey);
+ }
+ else
+ {
+ lua_pushstring(L, "Unknown endian");
+ (void)lua_error(L);
+ }
+ if(unlikely(err != CRYPT_OK))
+ {
+ skey->cipher = -1;
+ lcrypt_error(L, err, NULL);
+ }
+ return 1;
+}
+
+LCRYPT_CIPHER_XXX_ENCRYPT(CTR, ctr)
+LCRYPT_CIPHER_XXX_DECRYPT(CTR, ctr)
+LCRYPT_CIPHER_XXX_INDEX(CTR, ctr)
+LCRYPT_CIPHER_XXX_NEWINDEX(CTR, ctr)
+LCRYPT_CIPHER_XXX_GC(CTR, ctr)
+
+LCRYPT_CIPHER_XXX(CBC, cbc)
+LCRYPT_CIPHER_XXX(CFB, cfb)
+LCRYPT_CIPHER_XXX(OFB, ofb)
+
+static int lcrypt_cipher_lrw(lua_State *L)
+{
+ symmetric_LRW *skey;
+ int err = CRYPT_OK, *cipher = luaL_checkudata(L, 1, "LCRYPT_CIPHER");
+ size_t key_length, iv_length, tweak_length;
+ const unsigned char *key = (const unsigned char *)luaL_checklstring(L, 2, &key_length);
+ const unsigned char *iv = (const unsigned char *)luaL_checklstring(L, 3, &iv_length);
+ const unsigned char *tweak = (const unsigned char *)luaL_checklstring(L, 4, &tweak_length);
+ if(unlikely(tweak_length != 16))
+ {
+ lua_pushstring(L, "Tweak must be 16 characters");
+ (void)lua_error(L);
+ }
+ lcrypt_ivlength(L, *cipher, &iv_length);
+ skey = lua_newuserdata(L, sizeof(symmetric_LRW));
+ memset(skey, 0, sizeof(symmetric_LRW));
+ luaL_getmetatable(L, "LCRYPT_CIPHER_LRW");
+ (void)lua_setmetatable(L, -2);
+ if(unlikely((err = lrw_start(*cipher, iv, key, (int)key_length, tweak, 0, skey)) != CRYPT_OK))
+ {
+ skey->cipher = -1;
+ lcrypt_error(L, err, NULL);
+ }
+ return 1;
+}
+
+LCRYPT_CIPHER_XXX_ENCRYPT(LRW, lrw)
+LCRYPT_CIPHER_XXX_DECRYPT(LRW, lrw)
+LCRYPT_CIPHER_XXX_INDEX(LRW, lrw)
+LCRYPT_CIPHER_XXX_NEWINDEX(LRW, lrw)
+LCRYPT_CIPHER_XXX_GC(LRW, lrw)
+
+static int lcrypt_cipher_f8(lua_State *L)
+{
+ symmetric_F8 *skey;
+ int err = CRYPT_OK, *cipher = luaL_checkudata(L, 1, "LCRYPT_CIPHER");
+ size_t key_length, iv_length, salt_length;
+ const unsigned char *key = (const unsigned char *)luaL_checklstring(L, 2, &key_length);
+ const unsigned char *iv = (const unsigned char *)luaL_checklstring(L, 3, &iv_length);
+ const unsigned char *salt = (const unsigned char *)luaL_checklstring(L, 4, &salt_length);
+ lcrypt_ivlength(L, *cipher, &iv_length);
+ skey = lua_newuserdata(L, sizeof(symmetric_F8));
+ memset(skey, 0, sizeof(symmetric_F8));
+ luaL_getmetatable(L, "LCRYPT_CIPHER_F8");
+ (void)lua_setmetatable(L, -2);
+ if(unlikely((err = f8_start(*cipher, iv, key, (int)key_length, salt, salt_length, 0, skey)) != CRYPT_OK))
+ {
+ skey->cipher = -1;
+ lcrypt_error(L, err, NULL);
+ }
+ return 1;
+}
+
+LCRYPT_CIPHER_XXX_ENCRYPT(F8, f8)
+LCRYPT_CIPHER_XXX_DECRYPT(F8, f8)
+LCRYPT_CIPHER_XXX_INDEX(F8, f8)
+LCRYPT_CIPHER_XXX_NEWINDEX(F8, f8)
+LCRYPT_CIPHER_XXX_GC(F8, f8)
+
+#undef LCRYPT_CIPHER_XXX
+#undef LCRYPT_CIPHER_XXX_START
+#undef LCRYPT_CIPHER_XXX_INDEX
+#undef LCRYPT_CIPHER_XXX_NEWINDEX
+#undef LCRYPT_CIPHER_XXX_GC
+
+
+static int lcrypt_cipher_key_size(lua_State *L)
+{
+ int *cipher = luaL_checkudata(L, 1, "LCRYPT_CIPHER");
+ int keysize = luaL_checkint(L, 2);
+ lcrypt_error(L, cipher_descriptor[*cipher].keysize(&keysize), NULL);
+ lua_pushinteger(L, keysize);
+ return 1;
+}
+
+static int lcrypt_cipher_index(lua_State *L)
+{
+ int *cipher = luaL_checkudata(L, 1, "LCRYPT_CIPHER");
+ const char *index = luaL_checkstring(L, 2);
+
+ #define RETURN_BLOCK_MODE(name) { if(strcmp(index, #name) == 0) { lua_pushcfunction(L, lcrypt_cipher_ ## name); return 1; } }
+ RETURN_BLOCK_MODE(ecb); RETURN_BLOCK_MODE(cbc); RETURN_BLOCK_MODE(ctr); RETURN_BLOCK_MODE(cfb);
+ RETURN_BLOCK_MODE(ofb); RETURN_BLOCK_MODE(f8);
+ if(cipher_descriptor[*cipher].block_length == 16) RETURN_BLOCK_MODE(lrw);
+ #undef RETURN_BLOCK_MODE
+
+ if(strcmp(index, "type") == 0) { lua_pushstring(L, "LCRYPT_CIPHER"); return 1; }
+ if(strcmp(index, "name") == 0) { lua_pushstring(L, cipher_descriptor[*cipher].name); return 1; }
+ if(strcmp(index, "min_key_length") == 0) { lua_pushinteger(L, cipher_descriptor[*cipher].min_key_length); return 1; }
+ if(strcmp(index, "max_key_length") == 0) { lua_pushinteger(L, cipher_descriptor[*cipher].max_key_length); return 1; }
+ if(strcmp(index, "block_length") == 0) { lua_pushinteger(L, cipher_descriptor[*cipher].block_length); return 1; }
+ if(strcmp(index, "key_size") == 0) { lua_pushcfunction(L, lcrypt_cipher_key_size); return 1; }
+ if(strcmp(index, "modes") == 0)
+ {
+ lua_newtable(L);
+ #define ADD_MODE(i, name) { lua_pushinteger(L, i); lua_pushstring(L, #name); lua_settable(L, -3); }
+ ADD_MODE(1, ecb); ADD_MODE(2, cbc); ADD_MODE(3, ctr); ADD_MODE(4, cfb);
+ ADD_MODE(5, ofb); ADD_MODE(6, f8);
+ if(cipher_descriptor[*cipher].block_length == 16) ADD_MODE(7, lrw);
+ #undef ADD_MODE
+ return 1;
+ }
+
+ return 0;
+}
+
+static const struct luaL_reg lcrypt_cipher_flib[] =
+{
+ { "__index", lcrypt_cipher_index },
+ { NULL, NULL }
+};
+
+#define CIPHER_MODE_FLIB(mode) \
+static const struct luaL_reg lcrypt_cipher_ ## mode ## _flib[] = \
+{ \
+ { "__index", lcrypt_cipher_ ## mode ## _index }, \
+ { "__newindex", lcrypt_cipher_ ## mode ## _newindex }, \
+ { "__gc", lcrypt_cipher_ ## mode ## _gc }, \
+ { NULL, NULL } \
+};
+CIPHER_MODE_FLIB(ecb); CIPHER_MODE_FLIB(cbc); CIPHER_MODE_FLIB(ctr);
+CIPHER_MODE_FLIB(cfb); CIPHER_MODE_FLIB(ofb); CIPHER_MODE_FLIB(f8);
+CIPHER_MODE_FLIB(lrw);
+#undef CIPHER_MODE_FLIB
+
+static void lcrypt_start_ciphers(lua_State *L)
+{
+ (void)luaL_newmetatable(L, "LCRYPT_CIPHER"); (void)luaL_register(L, NULL, lcrypt_cipher_flib); lua_pop(L, 1);
+ lua_pushstring(L, "ciphers");
+ lua_newtable(L);
+ #define ADD_CIPHER(L,name) \
+ { \
+ lua_pushstring(L, #name); \
+ int *cipher_index = lua_newuserdata(L, sizeof(int)); \
+ luaL_getmetatable(L, "LCRYPT_CIPHER"); \
+ (void)lua_setmetatable(L, -2); \
+ *cipher_index = register_cipher(&name ## _desc); \
+ lua_settable(L, -3); \
+ }
+ ADD_CIPHER(L, blowfish); ADD_CIPHER(L, xtea); ADD_CIPHER(L, rc2); ADD_CIPHER(L, rc5);
+ ADD_CIPHER(L, rc6); ADD_CIPHER(L, saferp); ADD_CIPHER(L, aes); ADD_CIPHER(L, twofish);
+ ADD_CIPHER(L, des); ADD_CIPHER(L, des3); ADD_CIPHER(L, cast5); ADD_CIPHER(L, noekeon);
+ ADD_CIPHER(L, skipjack); ADD_CIPHER(L, anubis); ADD_CIPHER(L, khazad); ADD_CIPHER(L, kseed);
+ ADD_CIPHER(L, kasumi);
+ #undef ADD_CIPHER
+ lua_settable(L, -3);
+
+ #define NEW_MODE_TYPE(NAME, name) (void)luaL_newmetatable(L, "LCRYPT_CIPHER_" #NAME); (void)luaL_register(L, NULL, lcrypt_cipher_ ## name ## _flib); lua_pop(L, 1);
+ NEW_MODE_TYPE(ECB, ecb); NEW_MODE_TYPE(CBC, cbc); NEW_MODE_TYPE(CTR, ctr);
+ NEW_MODE_TYPE(CFB, cfb); NEW_MODE_TYPE(OFB, ofb); NEW_MODE_TYPE(F8, f8);
+ NEW_MODE_TYPE(LRW, lrw);
+ #undef NEW_MODE_TYPE
+}
diff --git a/lcrypt/lcrypt_hashes.c b/lcrypt/lcrypt_hashes.c
new file mode 100644
index 0000000..4eccbfc
--- /dev/null
+++ b/lcrypt/lcrypt_hashes.c
@@ -0,0 +1,211 @@
+typedef struct
+{
+ int hash;
+ hash_state state;
+} lcrypt_hash;
+
+static int lcrypt_hash_add(lua_State *L)
+{
+ lcrypt_hash *h = luaL_checkudata(L, 1, "LCRYPT_HASH_STATE");
+ if(likely(h->hash >= 0))
+ {
+ size_t in_length = 0;
+ const unsigned char *in = (const unsigned char*)luaL_checklstring(L, 2, &in_length);
+ lcrypt_error(L, hash_descriptor[h->hash].process(&h->state, in, (unsigned long)in_length), NULL);
+ }
+ return 0;
+}
+
+static int lcrypt_hash_done(lua_State *L)
+{
+ lcrypt_hash *h = luaL_checkudata(L, 1, "LCRYPT_HASH_STATE");
+ if(likely(h->hash >= 0))
+ {
+ unsigned char out[hash_descriptor[h->hash].hashsize];
+ lcrypt_error(L, hash_descriptor[h->hash].done(&h->state, out), NULL);
+ lua_pushlstring(L, (char*)out, hash_descriptor[h->hash].hashsize);
+ }
+ memset(h, 0, sizeof(lcrypt_hash));
+ h->hash = -1;
+ return 1;
+}
+
+static int lcrypt_hash_state_gc(lua_State *L)
+{
+ lcrypt_hash *h = luaL_checkudata(L, 1, "LCRYPT_HASH_STATE");
+ if(likely(h->hash >= 0))
+ {
+ unsigned char out[hash_descriptor[h->hash].hashsize];
+ lcrypt_error(L, hash_descriptor[h->hash].done(&h->state, out), NULL);
+ memset(h, 0, sizeof(lcrypt_hash));
+ h->hash = -1;
+ }
+ return 0;
+}
+
+static int lcrypt_hash_hash(lua_State *L)
+{
+ int *hash = luaL_checkudata(L, 1, "LCRYPT_HASH");
+ size_t in_length = 0;
+ const unsigned char *in = (const unsigned char*)luaL_optlstring(L, 2, "", &in_length);
+ lcrypt_hash *h = lua_newuserdata(L, sizeof(lcrypt_hash));
+ luaL_getmetatable(L, "LCRYPT_HASH_STATE");
+ (void)lua_setmetatable(L, -2);
+ h->hash = -1;
+ lcrypt_error(L, hash_descriptor[*hash].init(&h->state), NULL);
+ if(in_length > 0)
+ {
+ lcrypt_error(L, hash_descriptor[*hash].process(&h->state, in, (unsigned long)in_length), NULL);
+ }
+ h->hash = *hash;
+ return 1;
+}
+
+static int lcrypt_hash_hmac(lua_State *L)
+{
+ int *hash = luaL_checkudata(L, 1, "LCRYPT_HASH");
+ size_t key_length = 0, in_length = 0;
+ const unsigned char *key = (const unsigned char*)luaL_checklstring(L, 2, &key_length);
+ const unsigned char *in = (const unsigned char*)luaL_optlstring(L, 3, "", &in_length);
+ hmac_state *h = lua_newuserdata(L, sizeof(hmac_state));
+ luaL_getmetatable(L, "LCRYPT_HMAC_STATE");
+ (void)lua_setmetatable(L, -2);
+ lcrypt_error(L, hmac_init(h, *hash, key, key_length), NULL);
+ if(in_length > 0)
+ {
+ lcrypt_error(L, hmac_process(h, in, (unsigned long)in_length), NULL);
+ }
+ return 1;
+}
+
+static int lcrypt_hmac_add(lua_State *L)
+{
+ hmac_state *h = luaL_checkudata(L, 1, "LCRYPT_HMAC_STATE");
+ if(likely(h->hash >= 0))
+ {
+ size_t in_length = 0;
+ const unsigned char *in = (const unsigned char*)luaL_checklstring(L, 2, &in_length);
+ lcrypt_error(L, hmac_process(h, in, (unsigned long)in_length), NULL);
+ }
+ return 0;
+}
+
+static int lcrypt_hmac_done(lua_State *L)
+{
+ hmac_state *h = luaL_checkudata(L, 1, "LCRYPT_HMAC_STATE");
+ if(likely(h->hash >= 0))
+ {
+ unsigned long out_length = hash_descriptor[h->hash].hashsize;
+ unsigned char out[out_length];
+ lcrypt_error(L, hmac_done(h, out, &out_length), NULL);
+ lua_pushlstring(L, (char*)out, out_length);
+ memset(h, 0, sizeof(hmac_state));
+ h->hash = -1;
+ return 1;
+ }
+ return 0;
+}
+
+static int lcrypt_hmac_state_gc(lua_State *L)
+{
+ hmac_state *h = luaL_checkudata(L, 1, "LCRYPT_HMAC_STATE");
+ if(likely(h->hash >= 0))
+ {
+ unsigned long out_length = hash_descriptor[h->hash].hashsize;
+ unsigned char out[out_length];
+ lcrypt_error(L, hmac_done(h, out, &out_length), NULL);
+ memset(h, 0, sizeof(hmac_state));
+ h->hash = -1;
+ }
+ return 0;
+}
+
+static int lcrypt_hash_index(lua_State *L)
+{
+ int *h = luaL_checkudata(L, 1, "LCRYPT_HASH");
+ const char *index = luaL_checkstring(L, 2);
+ if(strcmp(index, "type") == 0) { lua_pushstring(L, "LCRYPT_HASH"); return 1; }
+ if(strcmp(index, "name") == 0) { lua_pushstring(L, hash_descriptor[*h].name); return 1; }
+ if(strcmp(index, "hash_size") == 0) { lua_pushinteger(L, hash_descriptor[*h].hashsize); return 1; }
+ if(strcmp(index, "block_size") == 0) { lua_pushinteger(L, hash_descriptor[*h].blocksize); return 1; }
+ if(strcmp(index, "hash") == 0) { lua_pushcfunction(L, lcrypt_hash_hash); return 1; }
+ if(strcmp(index, "hmac") == 0) { lua_pushcfunction(L, lcrypt_hash_hmac); return 1; }
+ return 0;
+}
+
+static int lcrypt_hash_state_index(lua_State *L)
+{
+ lcrypt_hash *h = luaL_checkudata(L, 1, "LCRYPT_HASH_STATE");
+ if(likely(h->hash >= 0))
+ {
+ const char *index = luaL_checkstring(L, 2);
+ if(strcmp(index, "type") == 0) { lua_pushstring(L, "LCRYPT_HASH_STATE"); return 1; }
+ if(strcmp(index, "name") == 0) { lua_pushstring(L, hash_descriptor[h->hash].name); return 1; }
+ if(strcmp(index, "hash_size") == 0) { lua_pushinteger(L, hash_descriptor[h->hash].hashsize); return 1; }
+ if(strcmp(index, "block_size") == 0) { lua_pushinteger(L, hash_descriptor[h->hash].blocksize); return 1; }
+ if(strcmp(index, "add") == 0) { lua_pushcfunction(L, lcrypt_hash_add); return 1; }
+ if(strcmp(index, "done") == 0) { lua_pushcfunction(L, lcrypt_hash_done); return 1; }
+ }
+ return 0;
+}
+
+static int lcrypt_hmac_state_index(lua_State *L)
+{
+ hmac_state *h = luaL_checkudata(L, 1, "LCRYPT_HMAC_STATE");
+ if(likely(h->hash >= 0))
+ {
+ const char *index = luaL_checkstring(L, 2);
+ if(strcmp(index, "type") == 0) { lua_pushstring(L, "LCRYPT_HMAC_STATE"); return 1; }
+ if(strcmp(index, "hash") == 0) { lua_pushstring(L, hash_descriptor[h->hash].name); return 1; }
+ if(strcmp(index, "hash_size") == 0) { lua_pushinteger(L, hash_descriptor[h->hash].hashsize); return 1; }
+ if(strcmp(index, "block_size") == 0) { lua_pushinteger(L, hash_descriptor[h->hash].blocksize); return 1; }
+ if(strcmp(index, "add") == 0) { lua_pushcfunction(L, lcrypt_hmac_add); return 1; }
+ if(strcmp(index, "done") == 0) { lua_pushcfunction(L, lcrypt_hmac_done); return 1; }
+ }
+ return 0;
+}
+
+static const struct luaL_reg lcrypt_hash_flib[] =
+{
+ { "__index", lcrypt_hash_index },
+ { NULL, NULL }
+};
+
+static const struct luaL_reg lcrypt_hash_state_flib[] =
+{
+ { "__index", lcrypt_hash_state_index },
+ { "__gc", lcrypt_hash_state_gc },
+ { NULL, NULL }
+};
+
+static const struct luaL_reg lcrypt_hmac_state_flib[] =
+{
+ { "__index", lcrypt_hmac_state_index },
+ { "__gc", lcrypt_hmac_state_gc },
+ { NULL, NULL }
+};
+
+static void lcrypt_start_hashes(lua_State *L)
+{
+ (void)luaL_newmetatable(L, "LCRYPT_HASH"); (void)luaL_register(L, NULL, lcrypt_hash_flib); lua_pop(L, 1);
+ lua_pushstring(L, "hashes");
+ lua_newtable(L);
+ #define ADD_HASH(L,name) \
+ { \
+ lua_pushstring(L, #name); \
+ int *hash_index = lua_newuserdata(L, sizeof(int)); \
+ luaL_getmetatable(L, "LCRYPT_HASH"); \
+ (void)lua_setmetatable(L, -2); \
+ *hash_index = register_hash(&name ## _desc); \
+ lua_settable(L, -3); \
+ }
+ ADD_HASH(L, whirlpool); ADD_HASH(L, sha512); ADD_HASH(L, sha384); ADD_HASH(L, rmd320);
+ ADD_HASH(L, sha256); ADD_HASH(L, rmd256); ADD_HASH(L, sha224); ADD_HASH(L, tiger);
+ ADD_HASH(L, sha1); ADD_HASH(L, rmd160); ADD_HASH(L, rmd128); ADD_HASH(L, md5);
+ ADD_HASH(L, md4); ADD_HASH(L, md2);
+ #undef ADD_HASH
+ lua_settable(L, -3);
+
+ (void)luaL_newmetatable(L, "LCRYPT_HASH_STATE"); (void)luaL_register(L, NULL, lcrypt_hash_state_flib); lua_pop(L, 1);
+ (void)luaL_newmetatable(L, "LCRYPT_HMAC_STATE"); (void)luaL_register(L, NULL, lcrypt_hmac_state_flib); lua_pop(L, 1);
+}
diff --git a/lcrypt/lcrypt_math.c b/lcrypt/lcrypt_math.c
new file mode 100644
index 0000000..769a3a4
--- /dev/null
+++ b/lcrypt/lcrypt_math.c
@@ -0,0 +1,401 @@
+#ifdef USE_NCIPHER
+ typedef sbigint lcrypt_bigint;
+#else
+ typedef void* lcrypt_bigint;
+#endif
+
+static lcrypt_bigint* lcrypt_new_bigint(lua_State *L)
+{
+ lcrypt_bigint *bi = lua_newuserdata(L, sizeof(lcrypt_bigint));
+ luaL_getmetatable(L, "LCRYPT_BIGINT");
+ (void)lua_setmetatable(L, -2);
+ #ifdef USE_NCIPHER
+ sbigint_create(bi, NULL, 0);
+ #else
+ *bi = NULL;
+ lcrypt_error(L, ltc_mp.init(bi), NULL);
+ #endif
+ return bi;
+}
+
+static int lcrypt_bigint_add(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_add(bi_a, bi_b, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.add(*bi_a, *bi_b, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_sub(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_sub(bi_a, bi_b, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.sub(*bi_a, *bi_b, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_mul(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_mul(bi_a, bi_b, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.mul(*bi_a, *bi_b, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_div(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_divmod(bi_a, bi_b, bi, NULL) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.mpdiv(*bi_a, *bi_b, *bi, NULL), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_divmod(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_q = lcrypt_new_bigint(L);
+ lcrypt_bigint *bi_r = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_divmod(bi_a, bi_b, bi_q, bi_r) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.mpdiv(*bi_a, *bi_b, *bi_q, *bi_r), NULL);
+ #endif
+ return 2;
+}
+
+static int lcrypt_bigint_mod(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_divmod(bi_a, bi_b, NULL, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.mpdiv(*bi_a, *bi_b, NULL, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_invmod(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_invmod(bi_a, bi_b, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.invmod(*bi_a, *bi_b, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_mulmod(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_c = luaL_checkudata(L, 3, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_mulmod(bi_a, bi_b, bi_c, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.mulmod(*bi_a, *bi_b, *bi_c, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_exptmod(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_c = luaL_checkudata(L, 3, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_exptmod(bi_a, bi_b, bi_c, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.exptmod(*bi_a, *bi_b, *bi_c, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_gcd(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_gcd(bi_a, bi_b, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.gcd(*bi_a, *bi_b, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_lcm(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ if(unlikely(sbigint_lcm(bi_a, bi_b, bi) != 0)) return 0;
+ #else
+ lcrypt_error(L, ltc_mp.lcm(*bi_a, *bi_b, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_unm(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ #ifdef USE_NCIPHER
+ sbigint_copy(bi, bi_a);
+ bi->sign = (bi_a->sign == SBIGINT_POSITIVE) ? SBIGINT_NEGATIVE : SBIGINT_POSITIVE;
+ #else
+ lcrypt_error(L, ltc_mp.neg(*bi_a, *bi), NULL);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_eq(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ #ifdef USE_NCIPHER
+ lua_pushboolean(L, (sbigint_cmp(bi_a, bi_b) == 0) ? 1 : 0);
+ #else
+ lua_pushboolean(L, (ltc_mp.compare(*bi_a, *bi_b) == LTC_MP_EQ) ? 1 : 0);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_lt(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ #ifdef USE_NCIPHER
+ lua_pushboolean(L, (sbigint_cmp(bi_a, bi_b) < 0) ? 1 : 0);
+ #else
+ lua_pushboolean(L, (ltc_mp.compare(*bi_a, *bi_b) == LTC_MP_LT) ? 1 : 0);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_le(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ lcrypt_bigint *bi_b = luaL_checkudata(L, 2, "LCRYPT_BIGINT");
+ #ifdef USE_NCIPHER
+ lua_pushboolean(L, (sbigint_cmp(bi_a, bi_b) <= 0) ? 1 : 0);
+ #else
+ lua_pushboolean(L, (ltc_mp.compare(*bi_a, *bi_b) == LTC_MP_GT) ? 0 : 1);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_tostring(lua_State *L)
+{
+ lcrypt_bigint *bi_a = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ #ifdef USE_NCIPHER
+ unsigned char out[4097];
+ int length = sizeof(out);
+ sbigint_tostring(bi_a, out + 1, &length);
+ if(bi_a->sign == SBIGINT_NEGATIVE || (out[1] & 0x80) == 0x80)
+ {
+ out[0] = bi_a->sign;
+ lua_pushlstring(L, (char*)out, length + 1);
+ }
+ else
+ {
+ lua_pushlstring(L, (char*)out + 1, length);
+ }
+ #else
+ size_t out_length = (size_t)ltc_mp.unsigned_size(*bi_a) + 1;
+ unsigned char *out = lcrypt_malloc(L, out_length);
+ out[0] = (ltc_mp.compare_d(*bi_a, 0) == LTC_MP_LT) ? (unsigned char)0x80 : (unsigned char)0x00;
+ lcrypt_error(L, ltc_mp.unsigned_write(*bi_a, out+1), out);
+ if(out[0] == 0 && out[1] < 0x7f)
+ lua_pushlstring(L, (char*)out+1, out_length-1);
+ else
+ lua_pushlstring(L, (char*)out, out_length);
+ free(out);
+ #endif
+ return 1;
+}
+
+static int lcrypt_bigint_index(lua_State *L)
+{
+ lcrypt_bigint *bi = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ const char *index = luaL_checkstring(L, 2);
+ #ifdef USE_NCIPHER
+ if(strcmp(index, "bits") == 0)
+ {
+ int len = bi->num.nbytes - 1;
+ while(len > 0 && bi->num.bytes[len] == 0) len--;
+ int bits = len * 8;
+ if(bi->num.bytes[len] & 0x80) bits += 8;
+ else if(bi->num.bytes[len] & 0x40) bits += 7;
+ else if(bi->num.bytes[len] & 0x20) bits += 6;
+ else if(bi->num.bytes[len] & 0x10) bits += 5;
+ else if(bi->num.bytes[len] & 0x08) bits += 4;
+ else if(bi->num.bytes[len] & 0x04) bits += 3;
+ else if(bi->num.bytes[len] & 0x02) bits += 2;
+ else bits++;
+ lua_pushinteger(L, bits);
+ return 1;
+ }
+ if(strcmp(index, "isprime") == 0)
+ {
+ sbigint c;
+ int i, prime = 0;
+ if(unlikely(sbigint_is_prime(bi, &c) != 0)) return 0;
+ for(i = 0; i < c.num.nbytes; i++) if(c.num.bytes[i] != 0) { prime = 1; break; }
+ lua_pushboolean(L, prime);
+ return 1;
+ }
+ #else
+ if(strcmp(index, "bits") == 0) { lua_pushinteger(L, ltc_mp.count_bits(*bi)); return 1; }
+ if(strcmp(index, "isprime") == 0)
+ {
+ int ret = LTC_MP_NO;
+ lcrypt_error(L, ltc_mp.isprime(*bi, &ret), NULL);
+ lua_pushboolean(L, (ret == LTC_MP_YES) ? 1 : 0);
+ return 1;
+ }
+ #endif
+ if(strcmp(index, "add") == 0) { lua_pushcfunction(L, lcrypt_bigint_add); return 1; }
+ if(strcmp(index, "sub") == 0) { lua_pushcfunction(L, lcrypt_bigint_sub); return 1; }
+ if(strcmp(index, "mul") == 0) { lua_pushcfunction(L, lcrypt_bigint_mul); return 1; }
+ if(strcmp(index, "div") == 0) { lua_pushcfunction(L, lcrypt_bigint_divmod); return 1; }
+ if(strcmp(index, "mod") == 0) { lua_pushcfunction(L, lcrypt_bigint_mod); return 1; }
+ if(strcmp(index, "gcd") == 0) { lua_pushcfunction(L, lcrypt_bigint_gcd); return 1; }
+ if(strcmp(index, "lcm") == 0) { lua_pushcfunction(L, lcrypt_bigint_lcm); return 1; }
+ if(strcmp(index, "invmod") == 0) { lua_pushcfunction(L, lcrypt_bigint_invmod); return 1; }
+ if(strcmp(index, "mulmod") == 0) { lua_pushcfunction(L, lcrypt_bigint_mulmod); return 1; }
+ if(strcmp(index, "exptmod") == 0) { lua_pushcfunction(L, lcrypt_bigint_exptmod); return 1; }
+ return 0;
+}
+
+static int lcrypt_bigint_gc(lua_State *L)
+{
+ #ifdef USE_NCIPHER
+ (void)luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ #else
+ lcrypt_bigint *bi = luaL_checkudata(L, 1, "LCRYPT_BIGINT");
+ if(likely(*bi != NULL))
+ {
+ ltc_mp.deinit(*bi);
+ *bi = NULL;
+ }
+ #endif
+ return 0;
+}
+
+static int lcrypt_bigint_create(lua_State *L)
+{
+ #ifdef USE_NCIPHER
+ if(lua_isnumber(L, 1) == 1)
+ {
+ long n = luaL_checknumber(L, 1);
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ if(n < 0)
+ {
+ bi->sign = SBIGINT_NEGATIVE;
+ n = -n;
+ }
+ bi->num.nbytes = 0;
+ while(n != 0 || bi->num.nbytes % 4 != 0)
+ {
+ bi->num.bytes[bi->num.nbytes++] = n & 0xff;
+ n >>= 8;
+ }
+ }
+ else
+ {
+ size_t n_length = 0;
+ unsigned char *n = (unsigned char*)luaL_optlstring(L, 1, "", &n_length);
+ lcrypt_bigint *bi = lua_newuserdata(L, sizeof(lcrypt_bigint));
+ luaL_getmetatable(L, "LCRYPT_BIGINT");
+ (void)lua_setmetatable(L, -2);
+ sbigint_create(bi, n, n_length);
+ }
+ #else
+ if(lua_isnumber(L, 1) == 1)
+ {
+ long n = luaL_checknumber(L, 1);
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ if(n < 0)
+ {
+ void *temp;
+ int err = CRYPT_OK;
+ lcrypt_error(L, ltc_mp.init(&temp), NULL);
+ if((err = ltc_mp.set_int(temp, -n)) == CRYPT_OK)
+ {
+ err = ltc_mp.neg(temp, *bi);
+ }
+ ltc_mp.deinit(temp);
+ lcrypt_error(L, err, NULL);
+ }
+ else
+ {
+ lcrypt_error(L, ltc_mp.set_int(*bi, n), NULL);
+ }
+ }
+ else
+ {
+ size_t n_length = 0;
+ unsigned char *n = (unsigned char*)luaL_optlstring(L, 1, "", &n_length);
+ lcrypt_bigint *bi = lcrypt_new_bigint(L);
+ lcrypt_error(L, ltc_mp.unsigned_read(*bi, n, n_length), NULL);
+ }
+ #endif
+ return 1;
+}
+
+static const struct luaL_reg lcrypt_bigint_flib[] =
+{
+ { "__index", lcrypt_bigint_index },
+ { "__add", lcrypt_bigint_add },
+ { "__sub", lcrypt_bigint_sub },
+ { "__mul", lcrypt_bigint_mul },
+ { "__div", lcrypt_bigint_div },
+ { "__mod", lcrypt_bigint_mod },
+ { "__unm", lcrypt_bigint_unm },
+ { "__eq", lcrypt_bigint_eq },
+ { "__lt", lcrypt_bigint_lt },
+ { "__le", lcrypt_bigint_le },
+ { "__tostring", lcrypt_bigint_tostring },
+ { "__gc", lcrypt_bigint_gc },
+ { NULL, NULL }
+};
+
+static void lcrypt_start_math(lua_State *L)
+{
+ (void)luaL_newmetatable(L, "LCRYPT_BIGINT"); (void)luaL_register(L, NULL, lcrypt_bigint_flib); lua_pop(L, 1);
+
+ #ifndef USE_NCIPHER
+ ltc_mp = ltm_desc;
+ #endif
+
+ lua_pushstring(L, "bigint"); lua_pushcfunction(L, lcrypt_bigint_create); lua_settable(L, -3);
+}