Skip to content

Commit 834a11f

Browse files
committed
FEAT: AES encryption native function
1 parent 102a5d6 commit 834a11f

File tree

4 files changed

+650
-0
lines changed

4 files changed

+650
-0
lines changed

src/core/n-crypt.c

+124
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030

3131
#include "sys-core.h"
3232
#include "sys-rc4.h"
33+
#include "sys-aes.h"
3334

3435
const REBYTE rc4_name[] = "RC4-context"; //Used as a context handle name
36+
const REBYTE aes_name[] = "AES-context";
3537

3638
/**********************************************************************/
3739
//
@@ -82,4 +84,126 @@ REBNATIVE(rc4)
8284
VAL_HANDLE_NAME(ret) = rc4_name;
8385
}
8486
return R_RET;
87+
}
88+
89+
90+
/**********************************************************************/
91+
//
92+
// aes: native [
93+
//
94+
// "Encrypt/decrypt data using AES algorithm. Returns stream cipher context handle or encrypted/decrypted data."
95+
//
96+
// /key "Provided only for the first time to get stream HANDLE!."
97+
// crypt-key [binary!] "Crypt key (16 or 32 bytes)."
98+
// iv [binary! none!] "Optional initialization vector (16 bytes)."
99+
// /decrypt "Use the crypt-key for decryption (default is to encrypt)"
100+
// /stream
101+
// ctx [handle!] "Stream cipher context."
102+
// data [binary!] "Data to encrypt/decrypt. Or NONE to close the cipher stream."
103+
104+
// ]
105+
REBNATIVE(aes)
106+
{
107+
REBOOL ref_key = D_REF(1);
108+
REBVAL *val_crypt_key = D_ARG(2);
109+
REBVAL *val_iv = D_ARG(3);
110+
REBOOL ref_decrypt = D_REF(4);
111+
REBOOL ref_stream = D_REF(5);
112+
REBVAL *val_ctx = D_ARG(6);
113+
REBVAL *val_data = D_ARG(7);
114+
115+
REBVAL *ret = D_RET;
116+
REBSER *ctx;
117+
REBINT len, pad_len;
118+
REBYTE *data;
119+
120+
if (ref_key) {
121+
//key defined - setup new context
122+
123+
uint8_t iv[AES_IV_SIZE];
124+
125+
if (IS_BINARY(val_iv)) {
126+
if (VAL_LEN(val_iv) < AES_IV_SIZE) {
127+
return R_NONE;
128+
}
129+
memcpy(iv, VAL_BIN_AT(val_iv), AES_IV_SIZE);
130+
} else {
131+
//TODO: provide some random IV or use ECB encryption if IV is not specified
132+
memset(iv, 0, AES_IV_SIZE);
133+
}
134+
135+
len = VAL_LEN(val_crypt_key) << 3;
136+
137+
if (len != 128 && len != 256) {
138+
return R_NONE;
139+
}
140+
141+
//making series from POOL so it will be GCed automaticaly
142+
ctx = Make_Series(sizeof(AES_CTX), (REBCNT)1, FALSE);
143+
144+
AES_set_key(
145+
(AES_CTX*)ctx->data,
146+
VAL_BIN_AT(val_crypt_key),
147+
(const uint8_t *)iv,
148+
(len == 128) ? AES_MODE_128 : AES_MODE_256
149+
);
150+
151+
if (ref_decrypt) AES_convert_key((AES_CTX*)ctx->data);
152+
153+
SET_HANDLE(ret, ctx);
154+
VAL_HANDLE_NAME(ret) = aes_name;
155+
156+
} else if(ref_stream) {
157+
158+
if (VAL_HANDLE_NAME(val_ctx) != aes_name) {
159+
Trap0(RE_INVALID_HANDLE);
160+
}
161+
162+
ctx = (REBSER*)VAL_HANDLE(val_ctx);
163+
164+
len = VAL_LEN(val_data);
165+
if (len == 0) return R_NONE;
166+
167+
pad_len = (((len - 1) >> 4) << 4) + AES_BLOCKSIZE;
168+
169+
REBYTE *data = VAL_BIN_AT(val_data);
170+
REBYTE *pad_data;
171+
172+
if (len < pad_len) {
173+
// make new data input with zero-padding
174+
//TODO: instead of making new data, the original could be extended with padding.
175+
pad_data = (REBYTE*)MAKE_MEM(pad_len);
176+
memset(pad_data, 0, pad_len);
177+
memcpy(pad_data, data, len);
178+
data = pad_data;
179+
}
180+
else {
181+
pad_data = NULL;
182+
}
183+
184+
REBSER *binaryOut = Make_Binary(pad_len);
185+
AES_CTX *aes_ctx = (AES_CTX *)ctx->data;
186+
if (aes_ctx->key_mode == AES_MODE_DECRYPT) {
187+
AES_cbc_decrypt(
188+
aes_ctx,
189+
(const uint8_t*)data,
190+
BIN_HEAD(binaryOut),
191+
pad_len
192+
);
193+
}
194+
else {
195+
AES_cbc_encrypt(
196+
aes_ctx,
197+
(const uint8_t*)data,
198+
BIN_HEAD(binaryOut),
199+
pad_len
200+
);
201+
}
202+
if (pad_data) FREE_MEM(pad_data);
203+
204+
SET_BINARY(ret, binaryOut);
205+
VAL_TAIL(ret) = pad_len;
206+
207+
}
208+
return R_RET;
85209
}

0 commit comments

Comments
 (0)