luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

crypto.c (44803B)


      1 /*
      2  * crypto.c - Lua bindings for encryption library
      3  *
      4  * Provides Lua interface to AES, ChaCha20, Serpent, and Twofish encryption
      5  * All functions use the format: [Nonce(12)][Tag(16)][Ciphertext(var)]
      6  *
      7  * All functions take key as first parameter (binary or base64)
      8  */
      9 
     10 #include <lua.h>
     11 #include <lauxlib.h>
     12 #include <string.h>
     13 #include <stdlib.h>
     14 #include <stdint.h>
     15 #include "EasyCrypto.h"
     16 #include "CSPRNG.h"
     17 #include "CSPRNG_Lua.h"
     18 #include "PBKDF2_Lua.h"
     19 #include "Hash_Lua.h"
     20 #include "X25519_Lua.h"
     21 #include "Ed25519_Lua.h"
     22 #include "RSA_Lua.h"
     23 #include "P256_Lua.h"
     24 #include "Kyber_Lua.h"
     25 #include "Dilithium_Lua.h"
     26 
     27 /* Base64 encoding table */
     28 static const char base64_chars[] =
     29     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     30 
     31 /* Base64 encode */
     32 char* base64_encode(const uint8_t *data, size_t len, size_t *out_len) {
     33     size_t encoded_len = 4 * ((len + 2) / 3);
     34     char *encoded = malloc(encoded_len + 1);
     35     if (!encoded) return NULL;
     36 
     37     size_t i, j;
     38     for (i = 0, j = 0; i < len; ) {
     39         uint32_t octet_a = i < len ? data[i++] : 0;
     40         uint32_t octet_b = i < len ? data[i++] : 0;
     41         uint32_t octet_c = i < len ? data[i++] : 0;
     42 
     43         uint32_t triple = (octet_a << 16) + (octet_b << 8) + octet_c;
     44 
     45         encoded[j++] = base64_chars[(triple >> 18) & 0x3F];
     46         encoded[j++] = base64_chars[(triple >> 12) & 0x3F];
     47         encoded[j++] = base64_chars[(triple >> 6) & 0x3F];
     48         encoded[j++] = base64_chars[triple & 0x3F];
     49     }
     50 
     51     /* Add padding */
     52     for (i = 0; i < (3 - len % 3) % 3; i++) {
     53         encoded[encoded_len - 1 - i] = '=';
     54     }
     55 
     56     encoded[encoded_len] = '\0';
     57     *out_len = encoded_len;
     58     return encoded;
     59 }
     60 
     61 /* Base64 decode (non-static for RSA_Lua.c) */
     62 uint8_t* base64_decode(const char *data, size_t len, size_t *out_len) {
     63     if (len % 4 != 0) return NULL;
     64 
     65     size_t decoded_len = len / 4 * 3;
     66     if (data[len - 1] == '=') decoded_len--;
     67     if (data[len - 2] == '=') decoded_len--;
     68 
     69     uint8_t *decoded = malloc(decoded_len);
     70     if (!decoded) return NULL;
     71 
     72     /* Build decode table */
     73     uint8_t decode_table[256];
     74     memset(decode_table, 0xFF, 256);
     75     for (int i = 0; i < 64; i++) {
     76         decode_table[(uint8_t)base64_chars[i]] = i;
     77     }
     78 
     79     size_t i, j;
     80     for (i = 0, j = 0; i < len; ) {
     81         uint32_t sextet_a = data[i] == '=' ? 0 : decode_table[(uint8_t)data[i]]; i++;
     82         uint32_t sextet_b = data[i] == '=' ? 0 : decode_table[(uint8_t)data[i]]; i++;
     83         uint32_t sextet_c = data[i] == '=' ? 0 : decode_table[(uint8_t)data[i]]; i++;
     84         uint32_t sextet_d = data[i] == '=' ? 0 : decode_table[(uint8_t)data[i]]; i++;
     85 
     86         uint32_t triple = (sextet_a << 18) + (sextet_b << 12) + (sextet_c << 6) + sextet_d;
     87 
     88         if (j < decoded_len) decoded[j++] = (triple >> 16) & 0xFF;
     89         if (j < decoded_len) decoded[j++] = (triple >> 8) & 0xFF;
     90         if (j < decoded_len) decoded[j++] = triple & 0xFF;
     91     }
     92 
     93     *out_len = decoded_len;
     94     return decoded;
     95 }
     96 
     97 /* Hex encoding */
     98 static char* hex_encode(const uint8_t *data, size_t len, size_t *out_len) {
     99     static const char hex_chars[] = "0123456789abcdef";
    100     char *encoded = malloc(len * 2 + 1);
    101     if (!encoded) return NULL;
    102 
    103     for (size_t i = 0; i < len; i++) {
    104         encoded[i * 2] = hex_chars[(data[i] >> 4) & 0xF];
    105         encoded[i * 2 + 1] = hex_chars[data[i] & 0xF];
    106     }
    107     encoded[len * 2] = '\0';
    108     *out_len = len * 2;
    109     return encoded;
    110 }
    111 
    112 /* Hex decode */
    113 static uint8_t* hex_decode(const char *data, size_t len, size_t *out_len) {
    114     if (len % 2 != 0) return NULL;
    115 
    116     size_t decoded_len = len / 2;
    117     uint8_t *decoded = malloc(decoded_len);
    118     if (!decoded) return NULL;
    119 
    120     for (size_t i = 0; i < decoded_len; i++) {
    121         char high = data[i * 2];
    122         char low = data[i * 2 + 1];
    123 
    124         uint8_t h = (high >= '0' && high <= '9') ? (high - '0') :
    125                     (high >= 'a' && high <= 'f') ? (high - 'a' + 10) :
    126                     (high >= 'A' && high <= 'F') ? (high - 'A' + 10) : 0;
    127         uint8_t l = (low >= '0' && low <= '9') ? (low - '0') :
    128                     (low >= 'a' && low <= 'f') ? (low - 'a' + 10) :
    129                     (low >= 'A' && low <= 'F') ? (low - 'A' + 10) : 0;
    130 
    131         decoded[i] = (h << 4) | l;
    132     }
    133 
    134     *out_len = decoded_len;
    135     return decoded;
    136 }
    137 
    138 /* Metamethod for raw data: result:raw() */
    139 static int encrypted_data_raw(lua_State *L) {
    140     /* Get _raw field (internal storage) */
    141     lua_getfield(L, 1, "_raw");
    142     return 1;
    143 }
    144 
    145 /* Metamethod for base64 encoding: result:base64() */
    146 static int encrypted_data_base64(lua_State *L) {
    147     /* Get _raw field */
    148     lua_getfield(L, 1, "_raw");
    149     size_t len;
    150     const uint8_t *data = (const uint8_t*)lua_tolstring(L, -1, &len);
    151 
    152     /* Encode to base64 */
    153     size_t b64_len;
    154     char *b64 = base64_encode(data, len, &b64_len);
    155     if (!b64) {
    156         return luaL_error(L, "Base64 encoding failed");
    157     }
    158 
    159     lua_pushlstring(L, b64, b64_len);
    160     free(b64);
    161     return 1;
    162 }
    163 
    164 /* Metamethod for hex encoding: result:hex() */
    165 static int encrypted_data_hex(lua_State *L) {
    166     /* Get _raw field */
    167     lua_getfield(L, 1, "_raw");
    168     size_t len;
    169     const uint8_t *data = (const uint8_t*)lua_tolstring(L, -1, &len);
    170 
    171     /* Encode to hex */
    172     size_t hex_len;
    173     char *hex = hex_encode(data, len, &hex_len);
    174     if (!hex) {
    175         return luaL_error(L, "Hex encoding failed");
    176     }
    177 
    178     lua_pushlstring(L, hex, hex_len);
    179     free(hex);
    180     return 1;
    181 }
    182 
    183 /* Create encrypted data table with raw(), length, base64(), and hex() methods */
    184 static void push_encrypted_data(lua_State *L, const uint8_t *data, size_t len) {
    185     lua_newtable(L);  /* Create result table */
    186 
    187     /* Set _raw field (internal storage with underscore prefix) */
    188     lua_pushlstring(L, (const char*)data, len);
    189     lua_setfield(L, -2, "_raw");
    190 
    191     /* Set length field */
    192     lua_pushinteger(L, len);
    193     lua_setfield(L, -2, "length");
    194 
    195     /* Create metatable with raw, base64, and hex methods */
    196     lua_newtable(L);  /* Create metatable */
    197 
    198     lua_pushcfunction(L, encrypted_data_raw);
    199     lua_setfield(L, -2, "raw");
    200 
    201     lua_pushcfunction(L, encrypted_data_base64);
    202     lua_setfield(L, -2, "base64");
    203 
    204     lua_pushcfunction(L, encrypted_data_hex);
    205     lua_setfield(L, -2, "hex");
    206 
    207     /* Set __index to point to itself so methods work */
    208     lua_pushvalue(L, -1);  /* Duplicate metatable */
    209     lua_setfield(L, -2, "__index");
    210 
    211     lua_setmetatable(L, -2);  /* Set metatable on result table */
    212 }
    213 
    214 /* Get encrypted data from argument - accepts encrypted result table or binary string */
    215 static const uint8_t* get_encrypted_from_arg(lua_State *L, int arg, size_t *len) {
    216     if (lua_istable(L, arg)) {
    217         /* Table: Try calling :raw() method first */
    218         lua_getfield(L, arg, "raw");
    219         if (lua_isfunction(L, -1)) {
    220             /* Call the raw() method */
    221             lua_pushvalue(L, arg);  /* Push table as self */
    222             lua_call(L, 1, 1);      /* Call raw(self) */
    223 
    224             if (lua_isstring(L, -1)) {
    225                 const uint8_t *data = (const uint8_t*)lua_tolstring(L, -1, len);
    226                 lua_replace(L, arg);  /* Replace arg with raw string */
    227                 return data;
    228             }
    229             lua_pop(L, 1);
    230         } else {
    231             lua_pop(L, 1);
    232         }
    233 
    234         /* Fallback: try _raw field directly */
    235         lua_getfield(L, arg, "_raw");
    236         if (!lua_isnil(L, -1)) {
    237             const uint8_t *data = (const uint8_t*)lua_tolstring(L, -1, len);
    238             lua_replace(L, arg);  /* Replace arg with raw string */
    239             return data;
    240         }
    241         lua_pop(L, 1);
    242 
    243         luaL_error(L, "Encrypted data table must have :raw() method or '_raw' field");
    244         return NULL;
    245     } else if (lua_isstring(L, arg)) {
    246         /* Binary string */
    247         return (const uint8_t*)lua_tolstring(L, arg, len);
    248     } else {
    249         luaL_error(L, "Encrypted data must be a table or binary string");
    250         return NULL;
    251     }
    252 }
    253 
    254 /*
    255  * Get key from binary string
    256  * Returns pointer to key data (valid until Lua string is collected)
    257  */
    258 static const uint8_t* get_key_from_arg(lua_State *L, int arg, size_t *key_len) {
    259     size_t len;
    260     const char *key_str = luaL_checklstring(L, arg, &len);
    261     *key_len = len;
    262     return (const uint8_t*)key_str;
    263 }
    264 
    265 /* generateKey() - Generate a random 32-byte key (returns binary string) */
    266 static int l_generateKey(lua_State *L) {
    267     uint8_t key[32];
    268     random_bytes(key, 32);
    269     lua_pushlstring(L, (const char*)key, 32);
    270     return 1;
    271 }
    272 
    273 /* generateKeyString() - Generate a random key as base64 string */
    274 static int l_generateKeyString(lua_State *L) {
    275     uint8_t key[32];
    276     random_bytes(key, 32);
    277 
    278     size_t b64_len;
    279     char *b64 = base64_encode(key, 32, &b64_len);
    280     if (!b64) {
    281         return luaL_error(L, "Base64 encoding failed");
    282     }
    283 
    284     lua_pushlstring(L, b64, b64_len);
    285     free(b64);
    286     return 1;
    287 }
    288 
    289 /* ============================================================================
    290  * PBKDF2 Functions
    291  * ========================================================================= */
    292 
    293 /* ============================================================================
    294  * AES-256-GCM Functions
    295  * ========================================================================= */
    296 
    297 /* encrypt(key, plaintext, [length]) - Encrypt with AES-256-GCM, returns table with raw, length, :base64(), :hex() */
    298 static int l_encrypt(lua_State *L) {
    299     size_t key_len;
    300     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    301 
    302     size_t plaintext_len;
    303     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    304 
    305     /* Optional explicit length parameter - when provided, use exact binary length */
    306     if (!lua_isnoneornil(L, 3)) {
    307         size_t explicit_len = luaL_checkinteger(L, 3);
    308         if (explicit_len <= plaintext_len) {
    309             plaintext_len = explicit_len;
    310         }
    311     }
    312 
    313     size_t encrypted_len;
    314     void *encrypted = ENCRYPT_AES(key, plaintext, plaintext_len, &encrypted_len);
    315 
    316     if (!encrypted) {
    317         return luaL_error(L, "Encryption failed");
    318     }
    319 
    320     push_encrypted_data(L, encrypted, encrypted_len);
    321     free(encrypted);
    322     return 1;
    323 }
    324 
    325 /* decrypt(key, encrypted) - Decrypt with AES-256-GCM, accepts table or binary string, returns binary string */
    326 static int l_decrypt(lua_State *L) {
    327     size_t key_len;
    328     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    329 
    330     size_t encrypted_len;
    331     const uint8_t *encrypted = get_encrypted_from_arg(L, 2, &encrypted_len);
    332 
    333     size_t plaintext_len;
    334     void *plaintext = DECRYPT_AES(key, encrypted, encrypted_len, &plaintext_len);
    335 
    336     if (!plaintext) {
    337         return luaL_error(L, "Decryption failed (authentication error or corrupted data)");
    338     }
    339 
    340     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    341     free(plaintext);
    342     return 1;
    343 }
    344 
    345 /* encryptAsBase64(key, plaintext) - Encrypt and return base64 string */
    346 static int l_encryptAsBase64(lua_State *L) {
    347     size_t key_len;
    348     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    349 
    350     size_t plaintext_len;
    351     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    352 
    353     size_t encrypted_len;
    354     void *encrypted = ENCRYPT_AES(key, plaintext, plaintext_len, &encrypted_len);
    355 
    356     if (!encrypted) {
    357         return luaL_error(L, "Encryption failed");
    358     }
    359 
    360     size_t b64_len;
    361     char *b64 = base64_encode(encrypted, encrypted_len, &b64_len);
    362     free(encrypted);
    363 
    364     if (!b64) {
    365         return luaL_error(L, "Base64 encoding failed");
    366     }
    367 
    368     lua_pushlstring(L, b64, b64_len);
    369     free(b64);
    370     return 1;
    371 }
    372 
    373 /* decryptFromBase64(key, base64_encrypted) - Decrypt from base64 string */
    374 static int l_decryptFromBase64(lua_State *L) {
    375     size_t key_len;
    376     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    377 
    378     size_t b64_len;
    379     const char *b64 = luaL_checklstring(L, 2, &b64_len);
    380 
    381     size_t encrypted_len;
    382     uint8_t *encrypted = base64_decode(b64, b64_len, &encrypted_len);
    383 
    384     if (!encrypted) {
    385         return luaL_error(L, "Base64 decoding failed");
    386     }
    387 
    388     size_t plaintext_len;
    389     void *plaintext = DECRYPT_AES(key, encrypted, encrypted_len, &plaintext_len);
    390     free(encrypted);
    391 
    392     if (!plaintext) {
    393         return luaL_error(L, "Decryption failed (authentication error or corrupted data)");
    394     }
    395 
    396     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    397     free(plaintext);
    398     return 1;
    399 }
    400 
    401 /* ============================================================================
    402  * AES-128-GCM Functions
    403  * ========================================================================= */
    404 
    405 /* encryptAES128(key, plaintext, [length]) - Encrypt with AES-128-GCM, returns table with raw, length, :base64(), :hex() */
    406 static int l_encryptAES128(lua_State *L) {
    407     size_t key_len;
    408     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    409 
    410     /* Verify key is 16 bytes */
    411     if (key_len != 16) {
    412         return luaL_error(L, "AES-128 requires 16-byte key (got %d bytes)", (int)key_len);
    413     }
    414 
    415     size_t plaintext_len;
    416     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    417 
    418     /* Optional explicit length parameter - when provided, use exact binary length */
    419     if (!lua_isnoneornil(L, 3)) {
    420         size_t explicit_len = luaL_checkinteger(L, 3);
    421         if (explicit_len <= plaintext_len) {
    422             plaintext_len = explicit_len;
    423         }
    424     }
    425 
    426     size_t encrypted_len;
    427     void *encrypted = ENCRYPT_AES128(key, plaintext, plaintext_len, &encrypted_len);
    428 
    429     if (!encrypted) {
    430         return luaL_error(L, "AES-128 encryption failed");
    431     }
    432 
    433     push_encrypted_data(L, encrypted, encrypted_len);
    434     free(encrypted);
    435     return 1;
    436 }
    437 
    438 /* decryptAES128(key, encrypted) - Decrypt with AES-128-GCM, accepts table or binary string, returns binary string */
    439 static int l_decryptAES128(lua_State *L) {
    440     size_t key_len;
    441     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    442 
    443     /* Verify key is 16 bytes */
    444     if (key_len != 16) {
    445         return luaL_error(L, "AES-128 requires 16-byte key (got %d bytes)", (int)key_len);
    446     }
    447 
    448     size_t encrypted_len;
    449     const uint8_t *encrypted = get_encrypted_from_arg(L, 2, &encrypted_len);
    450 
    451     size_t plaintext_len;
    452     void *plaintext = DECRYPT_AES128(key, encrypted, encrypted_len, &plaintext_len);
    453 
    454     if (!plaintext) {
    455         return luaL_error(L, "AES-128 decryption failed (authentication error or corrupted data)");
    456     }
    457 
    458     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    459     free(plaintext);
    460     return 1;
    461 }
    462 
    463 /* encryptAES128String(key, plaintext) - Encrypt and return base64 string */
    464 static int l_encryptAES128String(lua_State *L) {
    465     size_t key_len;
    466     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    467 
    468     /* Verify key is 16 bytes */
    469     if (key_len != 16) {
    470         return luaL_error(L, "AES-128 requires 16-byte key (got %d bytes)", (int)key_len);
    471     }
    472 
    473     size_t plaintext_len;
    474     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    475 
    476     size_t encrypted_len;
    477     void *encrypted = ENCRYPT_AES128(key, plaintext, plaintext_len, &encrypted_len);
    478 
    479     if (!encrypted) {
    480         return luaL_error(L, "AES-128 encryption failed");
    481     }
    482 
    483     size_t b64_len;
    484     char *b64 = base64_encode(encrypted, encrypted_len, &b64_len);
    485     free(encrypted);
    486 
    487     if (!b64) {
    488         return luaL_error(L, "Base64 encoding failed");
    489     }
    490 
    491     lua_pushlstring(L, b64, b64_len);
    492     free(b64);
    493     return 1;
    494 }
    495 
    496 /* decryptAES128String(key, base64_encrypted) - Decrypt from base64 string */
    497 static int l_decryptAES128String(lua_State *L) {
    498     size_t key_len;
    499     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    500 
    501     /* Verify key is 16 bytes */
    502     if (key_len != 16) {
    503         return luaL_error(L, "AES-128 requires 16-byte key (got %d bytes)", (int)key_len);
    504     }
    505 
    506     size_t b64_len;
    507     const char *b64 = luaL_checklstring(L, 2, &b64_len);
    508 
    509     size_t encrypted_len;
    510     uint8_t *encrypted = base64_decode(b64, b64_len, &encrypted_len);
    511 
    512     if (!encrypted) {
    513         return luaL_error(L, "Base64 decoding failed");
    514     }
    515 
    516     size_t plaintext_len;
    517     void *plaintext = DECRYPT_AES128(key, encrypted, encrypted_len, &plaintext_len);
    518     free(encrypted);
    519 
    520     if (!plaintext) {
    521         return luaL_error(L, "AES-128 decryption failed (authentication error or corrupted data)");
    522     }
    523 
    524     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    525     free(plaintext);
    526     return 1;
    527 }
    528 
    529 /* ============================================================================
    530  * ChaCha20-Poly1305 Functions
    531  * ========================================================================= */
    532 
    533 /* encryptChaCha(key, plaintext, [length]) - Returns table with raw, length, :base64(), :hex() */
    534 static int l_encryptChaCha(lua_State *L) {
    535     size_t key_len;
    536     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    537 
    538     size_t plaintext_len;
    539     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    540 
    541     /* Optional explicit length parameter - when provided, use exact binary length */
    542     if (!lua_isnoneornil(L, 3)) {
    543         size_t explicit_len = luaL_checkinteger(L, 3);
    544         if (explicit_len <= plaintext_len) {
    545             plaintext_len = explicit_len;
    546         }
    547     }
    548 
    549     size_t encrypted_len;
    550     void *encrypted = ENCRYPT_CHACHA(key, plaintext, plaintext_len, &encrypted_len);
    551 
    552     if (!encrypted) {
    553         return luaL_error(L, "ChaCha20 encryption failed");
    554     }
    555 
    556     push_encrypted_data(L, encrypted, encrypted_len);
    557     free(encrypted);
    558     return 1;
    559 }
    560 
    561 /* decryptChaCha(key, encrypted) - Accepts table or binary string, returns binary string */
    562 static int l_decryptChaCha(lua_State *L) {
    563     size_t key_len;
    564     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    565 
    566     size_t encrypted_len;
    567     const uint8_t *encrypted = get_encrypted_from_arg(L, 2, &encrypted_len);
    568 
    569     size_t plaintext_len;
    570     void *plaintext = DECRYPT_CHACHA(key, encrypted, encrypted_len, &plaintext_len);
    571 
    572     if (!plaintext) {
    573         return luaL_error(L, "ChaCha20 decryption failed");
    574     }
    575 
    576     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    577     free(plaintext);
    578     return 1;
    579 }
    580 
    581 /* encryptChaChaString(key, plaintext) - Returns base64 string */
    582 static int l_encryptChaChaString(lua_State *L) {
    583     size_t key_len;
    584     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    585 
    586     size_t plaintext_len;
    587     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    588 
    589     size_t encrypted_len;
    590     void *encrypted = ENCRYPT_CHACHA(key, plaintext, plaintext_len, &encrypted_len);
    591 
    592     if (!encrypted) {
    593         return luaL_error(L, "ChaCha20 encryption failed");
    594     }
    595 
    596     size_t b64_len;
    597     char *b64 = base64_encode(encrypted, encrypted_len, &b64_len);
    598     free(encrypted);
    599 
    600     if (!b64) {
    601         return luaL_error(L, "Base64 encoding failed");
    602     }
    603 
    604     lua_pushlstring(L, b64, b64_len);
    605     free(b64);
    606     return 1;
    607 }
    608 
    609 /* decryptChaChaString(key, base64_encrypted) - Returns binary string */
    610 static int l_decryptChaChaString(lua_State *L) {
    611     size_t key_len;
    612     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    613 
    614     size_t b64_len;
    615     const char *b64 = luaL_checklstring(L, 2, &b64_len);
    616 
    617     size_t encrypted_len;
    618     uint8_t *encrypted = base64_decode(b64, b64_len, &encrypted_len);
    619 
    620     if (!encrypted) {
    621         return luaL_error(L, "Base64 decoding failed");
    622     }
    623 
    624     size_t plaintext_len;
    625     void *plaintext = DECRYPT_CHACHA(key, encrypted, encrypted_len, &plaintext_len);
    626     free(encrypted);
    627 
    628     if (!plaintext) {
    629         return luaL_error(L, "ChaCha20 decryption failed");
    630     }
    631 
    632     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    633     free(plaintext);
    634     return 1;
    635 }
    636 
    637 /* ============================================================================
    638  * XChaCha20-Poly1305 Functions
    639  * ========================================================================= */
    640 
    641 /* encryptXChaCha(key, plaintext, [length]) - Returns table with raw, length, :base64(), :hex() */
    642 static int l_encryptXChaCha(lua_State *L) {
    643     size_t key_len;
    644     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    645 
    646     size_t plaintext_len;
    647     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    648 
    649     /* Optional explicit length parameter - when provided, use exact binary length */
    650     if (!lua_isnoneornil(L, 3)) {
    651         size_t explicit_len = luaL_checkinteger(L, 3);
    652         if (explicit_len <= plaintext_len) {
    653             plaintext_len = explicit_len;
    654         }
    655     }
    656 
    657     size_t encrypted_len;
    658     void *encrypted = ENCRYPT_XCHACHA(key, plaintext, plaintext_len, &encrypted_len);
    659 
    660     if (!encrypted) {
    661         return luaL_error(L, "XChaCha20 encryption failed");
    662     }
    663 
    664     push_encrypted_data(L, encrypted, encrypted_len);
    665     free(encrypted);
    666     return 1;
    667 }
    668 
    669 /* decryptXChaCha(key, encrypted) - Accepts table or binary string, returns binary string */
    670 static int l_decryptXChaCha(lua_State *L) {
    671     size_t key_len;
    672     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    673 
    674     size_t encrypted_len;
    675     const uint8_t *encrypted = get_encrypted_from_arg(L, 2, &encrypted_len);
    676 
    677     size_t plaintext_len;
    678     void *plaintext = DECRYPT_XCHACHA(key, encrypted, encrypted_len, &plaintext_len);
    679 
    680     if (!plaintext) {
    681         return luaL_error(L, "XChaCha20 decryption failed");
    682     }
    683 
    684     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    685     free(plaintext);
    686     return 1;
    687 }
    688 
    689 /* encryptXChaChaString(key, plaintext) - Returns base64 string */
    690 static int l_encryptXChaChaString(lua_State *L) {
    691     size_t key_len;
    692     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    693 
    694     size_t plaintext_len;
    695     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    696 
    697     size_t encrypted_len;
    698     void *encrypted = ENCRYPT_XCHACHA(key, plaintext, plaintext_len, &encrypted_len);
    699 
    700     if (!encrypted) {
    701         return luaL_error(L, "XChaCha20 encryption failed");
    702     }
    703 
    704     size_t b64_len;
    705     char *b64 = base64_encode(encrypted, encrypted_len, &b64_len);
    706     free(encrypted);
    707 
    708     if (!b64) {
    709         return luaL_error(L, "Base64 encoding failed");
    710     }
    711 
    712     lua_pushlstring(L, b64, b64_len);
    713     free(b64);
    714     return 1;
    715 }
    716 
    717 /* decryptXChaChaString(key, base64_encrypted) - Returns binary string */
    718 static int l_decryptXChaChaString(lua_State *L) {
    719     size_t key_len;
    720     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    721 
    722     size_t b64_len;
    723     const char *b64 = luaL_checklstring(L, 2, &b64_len);
    724 
    725     size_t encrypted_len;
    726     uint8_t *encrypted = base64_decode(b64, b64_len, &encrypted_len);
    727 
    728     if (!encrypted) {
    729         return luaL_error(L, "Base64 decoding failed");
    730     }
    731 
    732     size_t plaintext_len;
    733     void *plaintext = DECRYPT_XCHACHA(key, encrypted, encrypted_len, &plaintext_len);
    734     free(encrypted);
    735 
    736     if (!plaintext) {
    737         return luaL_error(L, "XChaCha20 decryption failed");
    738     }
    739 
    740     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    741     free(plaintext);
    742     return 1;
    743 }
    744 
    745 /* ============================================================================
    746  * Serpent-256-GCM Functions
    747  * ========================================================================= */
    748 
    749 /* encryptSerpent(key, plaintext, [length]) - Returns table with raw, length, :base64(), :hex() */
    750 static int l_encryptSerpent(lua_State *L) {
    751     size_t key_len;
    752     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    753 
    754     size_t plaintext_len;
    755     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    756 
    757     /* Optional explicit length parameter - when provided, use exact binary length */
    758     if (!lua_isnoneornil(L, 3)) {
    759         size_t explicit_len = luaL_checkinteger(L, 3);
    760         if (explicit_len <= plaintext_len) {
    761             plaintext_len = explicit_len;
    762         }
    763     }
    764 
    765     size_t encrypted_len;
    766     void *encrypted = ENCRYPT_SERPENT(key, plaintext, plaintext_len, &encrypted_len);
    767 
    768     if (!encrypted) {
    769         return luaL_error(L, "Serpent encryption failed");
    770     }
    771 
    772     push_encrypted_data(L, encrypted, encrypted_len);
    773     free(encrypted);
    774     return 1;
    775 }
    776 
    777 /* decryptSerpent(key, encrypted) - Accepts table or binary string, returns binary string */
    778 static int l_decryptSerpent(lua_State *L) {
    779     size_t key_len;
    780     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    781 
    782     size_t encrypted_len;
    783     const uint8_t *encrypted = get_encrypted_from_arg(L, 2, &encrypted_len);
    784 
    785     size_t plaintext_len;
    786     void *plaintext = DECRYPT_SERPENT(key, encrypted, encrypted_len, &plaintext_len);
    787 
    788     if (!plaintext) {
    789         return luaL_error(L, "Serpent decryption failed");
    790     }
    791 
    792     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    793     free(plaintext);
    794     return 1;
    795 }
    796 
    797 /* encryptSerpentString(key, plaintext) - Returns base64 string */
    798 static int l_encryptSerpentString(lua_State *L) {
    799     size_t key_len;
    800     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    801 
    802     size_t plaintext_len;
    803     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    804 
    805     size_t encrypted_len;
    806     void *encrypted = ENCRYPT_SERPENT(key, plaintext, plaintext_len, &encrypted_len);
    807 
    808     if (!encrypted) {
    809         return luaL_error(L, "Serpent encryption failed");
    810     }
    811 
    812     size_t b64_len;
    813     char *b64 = base64_encode(encrypted, encrypted_len, &b64_len);
    814     free(encrypted);
    815 
    816     if (!b64) {
    817         return luaL_error(L, "Base64 encoding failed");
    818     }
    819 
    820     lua_pushlstring(L, b64, b64_len);
    821     free(b64);
    822     return 1;
    823 }
    824 
    825 /* decryptSerpentString(key, base64_encrypted) - Returns binary string */
    826 static int l_decryptSerpentString(lua_State *L) {
    827     size_t key_len;
    828     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    829 
    830     size_t b64_len;
    831     const char *b64 = luaL_checklstring(L, 2, &b64_len);
    832 
    833     size_t encrypted_len;
    834     uint8_t *encrypted = base64_decode(b64, b64_len, &encrypted_len);
    835 
    836     if (!encrypted) {
    837         return luaL_error(L, "Base64 decoding failed");
    838     }
    839 
    840     size_t plaintext_len;
    841     void *plaintext = DECRYPT_SERPENT(key, encrypted, encrypted_len, &plaintext_len);
    842     free(encrypted);
    843 
    844     if (!plaintext) {
    845         return luaL_error(L, "Serpent decryption failed");
    846     }
    847 
    848     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    849     free(plaintext);
    850     return 1;
    851 }
    852 
    853 /* ============================================================================
    854  * Twofish-256-GCM Functions
    855  * ========================================================================= */
    856 
    857 /* encryptTwofish(key, plaintext, [length]) - Returns table with raw, length, :base64(), :hex() */
    858 static int l_encryptTwofish(lua_State *L) {
    859     size_t key_len;
    860     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    861 
    862     size_t plaintext_len;
    863     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    864 
    865     /* Optional explicit length parameter - when provided, use exact binary length */
    866     if (!lua_isnoneornil(L, 3)) {
    867         size_t explicit_len = luaL_checkinteger(L, 3);
    868         if (explicit_len <= plaintext_len) {
    869             plaintext_len = explicit_len;
    870         }
    871     }
    872 
    873     size_t encrypted_len;
    874     void *encrypted = ENCRYPT_TWOFISH(key, plaintext, plaintext_len, &encrypted_len);
    875 
    876     if (!encrypted) {
    877         return luaL_error(L, "Twofish encryption failed");
    878     }
    879 
    880     push_encrypted_data(L, encrypted, encrypted_len);
    881     free(encrypted);
    882     return 1;
    883 }
    884 
    885 /* decryptTwofish(key, encrypted) - Accepts table or binary string, returns binary string */
    886 static int l_decryptTwofish(lua_State *L) {
    887     size_t key_len;
    888     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    889 
    890     size_t encrypted_len;
    891     const uint8_t *encrypted = get_encrypted_from_arg(L, 2, &encrypted_len);
    892 
    893     size_t plaintext_len;
    894     void *plaintext = DECRYPT_TWOFISH(key, encrypted, encrypted_len, &plaintext_len);
    895 
    896     if (!plaintext) {
    897         return luaL_error(L, "Twofish decryption failed");
    898     }
    899 
    900     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    901     free(plaintext);
    902     return 1;
    903 }
    904 
    905 /* encryptTwofishString(key, plaintext) - Returns base64 string */
    906 static int l_encryptTwofishString(lua_State *L) {
    907     size_t key_len;
    908     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    909 
    910     size_t plaintext_len;
    911     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    912 
    913     size_t encrypted_len;
    914     void *encrypted = ENCRYPT_TWOFISH(key, plaintext, plaintext_len, &encrypted_len);
    915 
    916     if (!encrypted) {
    917         return luaL_error(L, "Twofish encryption failed");
    918     }
    919 
    920     size_t b64_len;
    921     char *b64 = base64_encode(encrypted, encrypted_len, &b64_len);
    922     free(encrypted);
    923 
    924     if (!b64) {
    925         return luaL_error(L, "Base64 encoding failed");
    926     }
    927 
    928     lua_pushlstring(L, b64, b64_len);
    929     free(b64);
    930     return 1;
    931 }
    932 
    933 /* decryptTwofishString(key, base64_encrypted) - Returns binary string */
    934 static int l_decryptTwofishString(lua_State *L) {
    935     size_t key_len;
    936     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    937 
    938     size_t b64_len;
    939     const char *b64 = luaL_checklstring(L, 2, &b64_len);
    940 
    941     size_t encrypted_len;
    942     uint8_t *encrypted = base64_decode(b64, b64_len, &encrypted_len);
    943 
    944     if (!encrypted) {
    945         return luaL_error(L, "Base64 decoding failed");
    946     }
    947 
    948     size_t plaintext_len;
    949     void *plaintext = DECRYPT_TWOFISH(key, encrypted, encrypted_len, &plaintext_len);
    950     free(encrypted);
    951 
    952     if (!plaintext) {
    953         return luaL_error(L, "Twofish decryption failed");
    954     }
    955 
    956     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
    957     free(plaintext);
    958     return 1;
    959 }
    960 
    961 /* ============================================================================
    962  * Salsa20-Poly1305 Functions
    963  * ========================================================================= */
    964 
    965 /* encryptSalsa(key, plaintext, [length]) - Returns table with raw, length, :base64(), :hex() */
    966 static int l_encryptSalsa(lua_State *L) {
    967     size_t key_len;
    968     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    969 
    970     size_t plaintext_len;
    971     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
    972 
    973     /* Optional explicit length parameter - when provided, use exact binary length */
    974     if (!lua_isnoneornil(L, 3)) {
    975         size_t explicit_len = luaL_checkinteger(L, 3);
    976         if (explicit_len <= plaintext_len) {
    977             plaintext_len = explicit_len;
    978         }
    979     }
    980 
    981     size_t encrypted_len;
    982     void *encrypted = ENCRYPT_SALSA(key, plaintext, plaintext_len, &encrypted_len);
    983 
    984     if (!encrypted) {
    985         return luaL_error(L, "Salsa20 encryption failed");
    986     }
    987 
    988     push_encrypted_data(L, encrypted, encrypted_len);
    989     free(encrypted);
    990     return 1;
    991 }
    992 
    993 /* decryptSalsa(key, encrypted) - Accepts table or binary string, returns binary string */
    994 static int l_decryptSalsa(lua_State *L) {
    995     size_t key_len;
    996     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
    997 
    998     size_t encrypted_len;
    999     const uint8_t *encrypted = get_encrypted_from_arg(L, 2, &encrypted_len);
   1000 
   1001     size_t plaintext_len;
   1002     void *plaintext = DECRYPT_SALSA(key, encrypted, encrypted_len, &plaintext_len);
   1003 
   1004     if (!plaintext) {
   1005         return luaL_error(L, "Salsa20 decryption failed");
   1006     }
   1007 
   1008     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
   1009     free(plaintext);
   1010     return 1;
   1011 }
   1012 
   1013 /* encryptSalsaString(key, plaintext) - Returns base64 string */
   1014 static int l_encryptSalsaString(lua_State *L) {
   1015     size_t key_len;
   1016     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
   1017 
   1018     size_t plaintext_len;
   1019     const uint8_t *plaintext = (const uint8_t*)luaL_checklstring(L, 2, &plaintext_len);
   1020 
   1021     size_t encrypted_len;
   1022     void *encrypted = ENCRYPT_SALSA(key, plaintext, plaintext_len, &encrypted_len);
   1023 
   1024     if (!encrypted) {
   1025         return luaL_error(L, "Salsa20 encryption failed");
   1026     }
   1027 
   1028     size_t b64_len;
   1029     char *b64 = base64_encode(encrypted, encrypted_len, &b64_len);
   1030     free(encrypted);
   1031 
   1032     if (!b64) {
   1033         return luaL_error(L, "Base64 encoding failed");
   1034     }
   1035 
   1036     lua_pushlstring(L, b64, b64_len);
   1037     free(b64);
   1038     return 1;
   1039 }
   1040 
   1041 /* decryptSalsaString(key, base64_encrypted) - Returns binary string */
   1042 static int l_decryptSalsaString(lua_State *L) {
   1043     size_t key_len;
   1044     const uint8_t *key = get_key_from_arg(L, 1, &key_len);
   1045 
   1046     size_t b64_len;
   1047     const char *b64 = luaL_checklstring(L, 2, &b64_len);
   1048 
   1049     size_t encrypted_len;
   1050     uint8_t *encrypted = base64_decode(b64, b64_len, &encrypted_len);
   1051 
   1052     if (!encrypted) {
   1053         return luaL_error(L, "Base64 decoding failed");
   1054     }
   1055 
   1056     size_t plaintext_len;
   1057     void *plaintext = DECRYPT_SALSA(key, encrypted, encrypted_len, &plaintext_len);
   1058     free(encrypted);
   1059 
   1060     if (!plaintext) {
   1061         return luaL_error(L, "Salsa20 decryption failed");
   1062     }
   1063 
   1064     lua_pushlstring(L, (const char*)plaintext, plaintext_len);
   1065     free(plaintext);
   1066     return 1;
   1067 }
   1068 
   1069 /* ============================================================================
   1070  * Library Registration
   1071  * ========================================================================= */
   1072 
   1073 static const luaL_Reg crypto_functions[] = {
   1074     /* Key management */
   1075     {"generateKey", l_generateKey},
   1076     {"generateKeyString", l_generateKeyString},
   1077 
   1078     /* AES-256-GCM (default) */
   1079     {"encrypt", l_encrypt},
   1080     {"decrypt", l_decrypt},
   1081     {"encryptAsBase64", l_encryptAsBase64},
   1082     {"decryptFromBase64", l_decryptFromBase64},
   1083 
   1084     /* ChaCha20-Poly1305 */
   1085     {"encryptChaCha", l_encryptChaCha},
   1086     {"decryptChaCha", l_decryptChaCha},
   1087     {"encryptChaChaString", l_encryptChaChaString},
   1088     {"decryptChaChaString", l_decryptChaChaString},
   1089 
   1090     /* Serpent-256-GCM */
   1091     {"encryptSerpent", l_encryptSerpent},
   1092     {"decryptSerpent", l_decryptSerpent},
   1093     {"encryptSerpentString", l_encryptSerpentString},
   1094     {"decryptSerpentString", l_decryptSerpentString},
   1095 
   1096     /* Twofish-256-GCM */
   1097     {"encryptTwofish", l_encryptTwofish},
   1098     {"decryptTwofish", l_decryptTwofish},
   1099     {"encryptTwofishString", l_encryptTwofishString},
   1100     {"decryptTwofishString", l_decryptTwofishString},
   1101 
   1102     /* Salsa20-Poly1305 */
   1103     {"encryptSalsa", l_encryptSalsa},
   1104     {"decryptSalsa", l_decryptSalsa},
   1105     {"encryptSalsaString", l_encryptSalsaString},
   1106     {"decryptSalsaString", l_decryptSalsaString},
   1107 
   1108     /* PBKDF2 Key Derivation */
   1109     {"deriveKey", l_deriveKey},
   1110     {"deriveKeyString", l_deriveKeyString},
   1111     {"generateSalt", l_generateSalt},
   1112 
   1113     {NULL, NULL}
   1114 };
   1115 
   1116 /* Module initialization */
   1117 int luaopen_crypto(lua_State *L) {
   1118     /* Initialize CSPRNG */
   1119     csprng_global_init();
   1120 
   1121     /* Register CSPRNG metatable for instances */
   1122     register_csprng_metatable(L);
   1123 
   1124     /* Create module table */
   1125     luaL_newlib(L, crypto_functions);
   1126 
   1127     /* Create AES subtable - crypto.AES.encrypt/encryptAsBase64/decrypt/decryptFromBase64 (AES-256-GCM) */
   1128     lua_newtable(L);
   1129     lua_pushcfunction(L, l_encrypt);
   1130     lua_setfield(L, -2, "encrypt");
   1131     lua_pushcfunction(L, l_encryptAsBase64);
   1132     lua_setfield(L, -2, "encryptAsBase64");
   1133     lua_pushcfunction(L, l_decrypt);
   1134     lua_setfield(L, -2, "decrypt");
   1135     lua_pushcfunction(L, l_decryptFromBase64);
   1136     lua_setfield(L, -2, "decryptFromBase64");
   1137     lua_setfield(L, -2, "AES");
   1138 
   1139     /* Create AES128 subtable - crypto.AES128.encrypt/encryptAsBase64/decrypt/decryptFromBase64 (AES-128-GCM) */
   1140     lua_newtable(L);
   1141     lua_pushcfunction(L, l_encryptAES128);
   1142     lua_setfield(L, -2, "encrypt");
   1143     lua_pushcfunction(L, l_encryptAES128String);
   1144     lua_setfield(L, -2, "encryptAsBase64");
   1145     lua_pushcfunction(L, l_decryptAES128);
   1146     lua_setfield(L, -2, "decrypt");
   1147     lua_pushcfunction(L, l_decryptAES128String);
   1148     lua_setfield(L, -2, "decryptFromBase64");
   1149     lua_setfield(L, -2, "AES128");
   1150 
   1151     /* Create ChaCha20 subtable */
   1152     lua_newtable(L);
   1153     lua_pushcfunction(L, l_encryptChaCha);
   1154     lua_setfield(L, -2, "encrypt");
   1155     lua_pushcfunction(L, l_encryptChaChaString);
   1156     lua_setfield(L, -2, "encryptAsBase64");
   1157     lua_pushcfunction(L, l_decryptChaCha);
   1158     lua_setfield(L, -2, "decrypt");
   1159     lua_pushcfunction(L, l_decryptChaChaString);
   1160     lua_setfield(L, -2, "decryptFromBase64");
   1161     lua_setfield(L, -2, "ChaCha20");
   1162 
   1163     /* Create XChaCha20 subtable */
   1164     lua_newtable(L);
   1165     lua_pushcfunction(L, l_encryptXChaCha);
   1166     lua_setfield(L, -2, "encrypt");
   1167     lua_pushcfunction(L, l_encryptXChaChaString);
   1168     lua_setfield(L, -2, "encryptAsBase64");
   1169     lua_pushcfunction(L, l_decryptXChaCha);
   1170     lua_setfield(L, -2, "decrypt");
   1171     lua_pushcfunction(L, l_decryptXChaChaString);
   1172     lua_setfield(L, -2, "decryptFromBase64");
   1173     lua_setfield(L, -2, "XChaCha20");
   1174 
   1175     /* Create Serpent subtable */
   1176     lua_newtable(L);
   1177     lua_pushcfunction(L, l_encryptSerpent);
   1178     lua_setfield(L, -2, "encrypt");
   1179     lua_pushcfunction(L, l_encryptSerpentString);
   1180     lua_setfield(L, -2, "encryptAsBase64");
   1181     lua_pushcfunction(L, l_decryptSerpent);
   1182     lua_setfield(L, -2, "decrypt");
   1183     lua_pushcfunction(L, l_decryptSerpentString);
   1184     lua_setfield(L, -2, "decryptFromBase64");
   1185     lua_setfield(L, -2, "Serpent");
   1186 
   1187     /* Create Twofish subtable */
   1188     lua_newtable(L);
   1189     lua_pushcfunction(L, l_encryptTwofish);
   1190     lua_setfield(L, -2, "encrypt");
   1191     lua_pushcfunction(L, l_encryptTwofishString);
   1192     lua_setfield(L, -2, "encryptAsBase64");
   1193     lua_pushcfunction(L, l_decryptTwofish);
   1194     lua_setfield(L, -2, "decrypt");
   1195     lua_pushcfunction(L, l_decryptTwofishString);
   1196     lua_setfield(L, -2, "decryptFromBase64");
   1197     lua_setfield(L, -2, "Twofish");
   1198 
   1199     /* Create Salsa20 subtable */
   1200     lua_newtable(L);
   1201     lua_pushcfunction(L, l_encryptSalsa);
   1202     lua_setfield(L, -2, "encrypt");
   1203     lua_pushcfunction(L, l_encryptSalsaString);
   1204     lua_setfield(L, -2, "encryptAsBase64");
   1205     lua_pushcfunction(L, l_decryptSalsa);
   1206     lua_setfield(L, -2, "decrypt");
   1207     lua_pushcfunction(L, l_decryptSalsaString);
   1208     lua_setfield(L, -2, "decryptFromBase64");
   1209     lua_setfield(L, -2, "Salsa20");
   1210 
   1211     /* Register hash functions directly on crypto table */
   1212     lua_pushcfunction(L, l_hash);
   1213     lua_setfield(L, -2, "SHA256");
   1214 
   1215     lua_pushcfunction(L, l_hash_sha512);
   1216     lua_setfield(L, -2, "SHA512");
   1217 
   1218     lua_pushcfunction(L, l_hash_sha1);
   1219     lua_setfield(L, -2, "SHA1");
   1220 
   1221     lua_pushcfunction(L, l_hash_md5);
   1222     lua_setfield(L, -2, "MD5");
   1223 
   1224     lua_pushcfunction(L, l_hash_crc32);
   1225     lua_setfield(L, -2, "CRC32");
   1226 
   1227     lua_pushcfunction(L, l_hash_sha3);
   1228     lua_setfield(L, -2, "SHA3-256");
   1229     lua_pushcfunction(L, l_hash_sha3_512);
   1230     lua_setfield(L, -2, "SHA3-512");
   1231 
   1232     lua_pushcfunction(L, l_hash_blake2b);
   1233     lua_setfield(L, -2, "BLAKE2b-256");
   1234     lua_pushcfunction(L, l_hash_blake2b_512);
   1235     lua_setfield(L, -2, "BLAKE2b-512");
   1236 
   1237     /* Register KDF functions directly on crypto table */
   1238     lua_pushcfunction(L, l_deriveKey);
   1239     lua_setfield(L, -2, "PBKDF2");
   1240 
   1241     lua_pushcfunction(L, l_argon2id_derive);
   1242     lua_setfield(L, -2, "Argon2id");
   1243 
   1244     lua_pushcfunction(L, l_hkdf_derive);
   1245     lua_setfield(L, -2, "HKDF");
   1246 
   1247     lua_pushcfunction(L, l_generateSalt);
   1248     lua_setfield(L, -2, "generateSalt");
   1249 
   1250     /* Add simple deriveKey function at top level - crypto.deriveKey(password) uses Argon2id */
   1251     lua_pushcfunction(L, l_deriveKeySimple);
   1252     lua_setfield(L, -2, "deriveKey");
   1253 
   1254     /* Create X25519 subtable - crypto.X25519.keypair/publicKey/sharedSecret */
   1255     lua_newtable(L);
   1256     lua_pushcfunction(L, l_x25519_keypair);
   1257     lua_setfield(L, -2, "keypair");
   1258     lua_pushcfunction(L, l_x25519_public_key);
   1259     lua_setfield(L, -2, "publicKey");
   1260     lua_pushcfunction(L, l_x25519_shared_secret);
   1261     lua_setfield(L, -2, "sharedSecret");
   1262     lua_setfield(L, -2, "X25519");
   1263 
   1264     /* Create Ed25519 subtable - crypto.Ed25519.keypair/sign/verify */
   1265     lua_newtable(L);
   1266     lua_pushcfunction(L, l_ed25519_keypair);
   1267     lua_setfield(L, -2, "keypair");
   1268     lua_pushcfunction(L, l_ed25519_sign);
   1269     lua_setfield(L, -2, "sign");
   1270     lua_pushcfunction(L, l_ed25519_verify);
   1271     lua_setfield(L, -2, "verify");
   1272     lua_setfield(L, -2, "Ed25519");
   1273 
   1274     /* Create RSA subtable - crypto.RSA.generateKeypair/encrypt/decrypt/sign/verify/signPSS/verifyPSS */
   1275     lua_newtable(L);
   1276     lua_pushcfunction(L, l_rsa_generate_keypair);
   1277     lua_setfield(L, -2, "generateKeypair");
   1278     lua_pushcfunction(L, l_rsa_encrypt);
   1279     lua_setfield(L, -2, "encrypt");
   1280     lua_pushcfunction(L, l_rsa_decrypt);
   1281     lua_setfield(L, -2, "decrypt");
   1282     lua_pushcfunction(L, l_rsa_sign);
   1283     lua_setfield(L, -2, "sign");
   1284     lua_pushcfunction(L, l_rsa_verify);
   1285     lua_setfield(L, -2, "verify");
   1286     lua_pushcfunction(L, l_rsa_sign_pss);
   1287     lua_setfield(L, -2, "signPSS");
   1288     lua_pushcfunction(L, l_rsa_verify_pss);
   1289     lua_setfield(L, -2, "verifyPSS");
   1290     lua_setfield(L, -2, "RSA");
   1291 
   1292     /* Create CSPRNG subtable - crypto.CSPRNG.newKey/randomBytes/new */
   1293     lua_newtable(L);
   1294     lua_pushcfunction(L, l_csprng_new_key);
   1295     lua_setfield(L, -2, "newKey");
   1296     lua_pushcfunction(L, l_csprng_random_bytes);
   1297     lua_setfield(L, -2, "randomBytes");
   1298     lua_pushcfunction(L, l_csprng_new_instance);
   1299     lua_setfield(L, -2, "new");
   1300     lua_setfield(L, -2, "CSPRNG");
   1301 
   1302     /* Create P256 subtable - crypto.P256.ecdhKeypair/ecdhPublicKey/ecdhSharedSecret/ecdsaKeypair/ecdsaSign/ecdsaVerify */
   1303     lua_newtable(L);
   1304     lua_pushcfunction(L, l_p256_ecdh_keypair);
   1305     lua_setfield(L, -2, "ecdhKeypair");
   1306     lua_pushcfunction(L, l_p256_ecdh_public_key);
   1307     lua_setfield(L, -2, "ecdhPublicKey");
   1308     lua_pushcfunction(L, l_p256_ecdh_shared_secret);
   1309     lua_setfield(L, -2, "ecdhSharedSecret");
   1310     lua_pushcfunction(L, l_p256_ecdsa_keypair);
   1311     lua_setfield(L, -2, "ecdsaKeypair");
   1312     lua_pushcfunction(L, l_p256_ecdsa_sign);
   1313     lua_setfield(L, -2, "ecdsaSign");
   1314     lua_pushcfunction(L, l_p256_ecdsa_verify);
   1315     lua_setfield(L, -2, "ecdsaVerify");
   1316     lua_setfield(L, -2, "P256");
   1317 
   1318     /* Create Kyber subtable - Post-quantum key encapsulation (CRYSTALS-Kyber) */
   1319     lua_newtable(L);
   1320     /* Kyber512 - NIST Level 1 security */
   1321     lua_pushcfunction(L, l_kyber512_keypair);
   1322     lua_setfield(L, -2, "keypair512");
   1323     lua_pushcfunction(L, l_kyber512_encapsulate);
   1324     lua_setfield(L, -2, "encapsulate512");
   1325     lua_pushcfunction(L, l_kyber512_decapsulate);
   1326     lua_setfield(L, -2, "decapsulate512");
   1327     /* Kyber768 - NIST Level 3 security (recommended) */
   1328     lua_pushcfunction(L, l_kyber768_keypair);
   1329     lua_setfield(L, -2, "keypair");
   1330     lua_pushcfunction(L, l_kyber768_keypair);
   1331     lua_setfield(L, -2, "keypair768");
   1332     lua_pushcfunction(L, l_kyber768_encapsulate);
   1333     lua_setfield(L, -2, "encapsulate");
   1334     lua_pushcfunction(L, l_kyber768_encapsulate);
   1335     lua_setfield(L, -2, "encapsulate768");
   1336     lua_pushcfunction(L, l_kyber768_decapsulate);
   1337     lua_setfield(L, -2, "decapsulate");
   1338     lua_pushcfunction(L, l_kyber768_decapsulate);
   1339     lua_setfield(L, -2, "decapsulate768");
   1340     /* Kyber1024 - NIST Level 5 security */
   1341     lua_pushcfunction(L, l_kyber1024_keypair);
   1342     lua_setfield(L, -2, "keypair1024");
   1343     lua_pushcfunction(L, l_kyber1024_encapsulate);
   1344     lua_setfield(L, -2, "encapsulate1024");
   1345     lua_pushcfunction(L, l_kyber1024_decapsulate);
   1346     lua_setfield(L, -2, "decapsulate1024");
   1347     lua_setfield(L, -2, "Kyber");
   1348 
   1349     /* Create Dilithium subtable - Post-quantum digital signatures (CRYSTALS-Dilithium) */
   1350     lua_newtable(L);
   1351     /* Dilithium2 - NIST Level 2 security */
   1352     lua_pushcfunction(L, l_dilithium2_keypair);
   1353     lua_setfield(L, -2, "keypair2");
   1354     lua_pushcfunction(L, l_dilithium2_sign);
   1355     lua_setfield(L, -2, "sign2");
   1356     lua_pushcfunction(L, l_dilithium2_verify);
   1357     lua_setfield(L, -2, "verify2");
   1358     /* Dilithium3 - NIST Level 3 security (recommended) */
   1359     lua_pushcfunction(L, l_dilithium3_keypair);
   1360     lua_setfield(L, -2, "keypair");
   1361     lua_pushcfunction(L, l_dilithium3_keypair);
   1362     lua_setfield(L, -2, "keypair3");
   1363     lua_pushcfunction(L, l_dilithium3_sign);
   1364     lua_setfield(L, -2, "sign");
   1365     lua_pushcfunction(L, l_dilithium3_sign);
   1366     lua_setfield(L, -2, "sign3");
   1367     lua_pushcfunction(L, l_dilithium3_verify);
   1368     lua_setfield(L, -2, "verify");
   1369     lua_pushcfunction(L, l_dilithium3_verify);
   1370     lua_setfield(L, -2, "verify3");
   1371     /* Dilithium5 - NIST Level 5 security */
   1372     lua_pushcfunction(L, l_dilithium5_keypair);
   1373     lua_setfield(L, -2, "keypair5");
   1374     lua_pushcfunction(L, l_dilithium5_sign);
   1375     lua_setfield(L, -2, "sign5");
   1376     lua_pushcfunction(L, l_dilithium5_verify);
   1377     lua_setfield(L, -2, "verify5");
   1378     lua_setfield(L, -2, "Dilithium");
   1379 
   1380     /* Keep default encrypt/decrypt at top level (AES) for convenience */
   1381     lua_pushcfunction(L, l_encrypt);
   1382     lua_setfield(L, -2, "encrypt");
   1383     lua_pushcfunction(L, l_encryptAsBase64);
   1384     lua_setfield(L, -2, "encryptAsBase64");
   1385     lua_pushcfunction(L, l_decrypt);
   1386     lua_setfield(L, -2, "decrypt");
   1387     lua_pushcfunction(L, l_decryptFromBase64);
   1388     lua_setfield(L, -2, "decryptFromBase64");
   1389 
   1390     return 1;
   1391 }