summaryrefslogtreecommitdiff
path: root/lcrypt/lcrypt_ciphers.c
diff options
context:
space:
mode:
Diffstat (limited to 'lcrypt/lcrypt_ciphers.c')
-rw-r--r--lcrypt/lcrypt_ciphers.c403
1 files changed, 403 insertions, 0 deletions
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
+}