30
30
31
31
#include "sys-core.h"
32
32
#include "sys-rc4.h"
33
+ #include "sys-aes.h"
33
34
34
35
const REBYTE rc4_name [] = "RC4-context" ; //Used as a context handle name
36
+ const REBYTE aes_name [] = "AES-context" ;
35
37
36
38
/**********************************************************************/
37
39
//
@@ -82,4 +84,126 @@ REBNATIVE(rc4)
82
84
VAL_HANDLE_NAME (ret ) = rc4_name ;
83
85
}
84
86
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 ;
85
209
}
0 commit comments