diff options
author | Nicolas "Pixel" Noble <pixel@nobis-crew.org> | 2013-08-08 09:23:03 +0200 |
---|---|---|
committer | Nicolas "Pixel" Noble <pixel@nobis-crew.org> | 2013-08-08 09:23:03 +0200 |
commit | 29e4a0512331a36c1cde22ed26c6ae059fa20757 (patch) | |
tree | 09496f029124fe4fc61aa7e014df50349128ced3 /lcrypt | |
parent | 8fd11c9821c23c69da76158c87acdefe2ae9586f (diff) |
Adding libtommath, libtomcrypt and lcrypt, mainly for the bignum support.
Diffstat (limited to 'lcrypt')
-rw-r--r-- | lcrypt/Makefile | 7 | ||||
-rw-r--r-- | lcrypt/lcrypt.c | 604 | ||||
-rw-r--r-- | lcrypt/lcrypt_bits.c | 234 | ||||
-rw-r--r-- | lcrypt/lcrypt_ciphers.c | 403 | ||||
-rw-r--r-- | lcrypt/lcrypt_hashes.c | 211 | ||||
-rw-r--r-- | lcrypt/lcrypt_math.c | 401 |
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); +} |