summaryrefslogtreecommitdiff
path: root/source/luametatex/source/luarest/lmtaeslib.c
blob: 5dbd3556a7aecee8920c24ddf608b200ce9331e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
    See license.txt in the root of this project.
*/

# include "luametatex.h"

# include <utilcrypt.h>

// AES_HAS_IV AES_INLINE_IV AES_CONTINUE AES_NULL_PADDING

static const uint8_t nulliv[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

typedef size_t aes_coder (
    const void *input,
    size_t      length,
    void       *output,
    const void *key,
    size_t      keylength,
    const void *iv,
    int         flags
);

/* data key [block] [inline] [padding] */ /* key : 16 24 32 */

/* random_bytes is taken from pplib */

static int aeslib_aux_code(lua_State *L, aes_coder code) {
    size_t inputlength = 0;
    const char *input = lua_tolstring(L, 1, &inputlength);
    if (inputlength) {
        size_t keylength = 0;
        const char *key = lua_tolstring(L, 2, &keylength);
        if (keylength == 16 || keylength == 24 || keylength == 32) {
            luaL_Buffer buffer;
            /* always */
            int flags = 0;
            /* the same length as input plus optional 16 from iv */
            char *output = NULL;
            size_t outputlength = 0;
            /* this is optional, iv get copied in aes */
            const uint8_t *iv = NULL;
            switch (lua_type(L, 3)) {
                case LUA_TSTRING:
                    {
                        size_t ivlength = 0;
                        iv = (const uint8_t *) lua_tolstring(L, 3, &ivlength);
                        if (ivlength != 16) {
                            iv = nulliv;
                        }
                        break;
                    }
                case LUA_TBOOLEAN:
                    if (lua_toboolean(L, 3)) {
                        uint8_t randiv[16];
                        random_bytes(randiv, 16);
                        iv = (const uint8_t *) randiv;
                        break;
                    }
                    // fall through
                default:
                    iv = nulliv;
            }
            if (lua_toboolean(L, 4)) {
               flags |= AES_INLINE_IV;
            }
            if (! lua_toboolean(L, 5)) {
               flags |= AES_NULL_PADDING;
            }
            /* always multiples of 16 and we might have the iv too */
            output = luaL_buffinitsize(L, &buffer, inputlength + 32);
            outputlength = code(input, inputlength, output, key, keylength, iv, flags);
            if (outputlength) {
                luaL_pushresultsize(&buffer, outputlength);
                return 1;
            }
        } else {
            luaL_error(L, "aeslib: key of length 16, 24 or 32 expected");
        }
    }
    lua_pushnil(L);
    return 1;
}

static int aeslib_encode(lua_State *L) {
    return aeslib_aux_code(L, &aes_encode_data);
}

static int aeslib_decode(lua_State *L) {
    return aeslib_aux_code(L, &aes_decode_data);
}

static int aeslib_random(lua_State *L) {
    uint8_t iv[32];
    int n = (int) luaL_optinteger(L, 1, 16);
    if (n > 32) {
        n = 32;
    }
    random_bytes(iv, n);
    lua_pushlstring(L, (const char *) iv, n);
    return 1;
}

static struct luaL_Reg aeslib_function_list[] = {
    /*tex We started out with this: */
    { "encode", aeslib_encode },
    { "decode", aeslib_decode },
    { "random", aeslib_random },
    { NULL,     NULL          },
};

int luaopen_aes(lua_State *L) {
    lua_newtable(L);
    luaL_setfuncs(L, aeslib_function_list, 0);
    return 1;
}