1
+ /***********************************************************************
2
+ **
3
+ ** REBOL [R3] Language Interpreter and Run-time Environment
4
+ **
5
+ ** Copyright 2012 REBOL Technologies
6
+ ** Copyright 2012-2021 Rebol Open Source Contributors
7
+ ** REBOL is a trademark of REBOL Technologies
8
+ **
9
+ ** Licensed under the Apache License, Version 2.0 (the "License");
10
+ ** you may not use this file except in compliance with the License.
11
+ ** You may obtain a copy of the License at
12
+ **
13
+ ** http://www.apache.org/licenses/LICENSE-2.0
14
+ **
15
+ ** Unless required by applicable law or agreed to in writing, software
16
+ ** distributed under the License is distributed on an "AS IS" BASIS,
17
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ ** See the License for the specific language governing permissions and
19
+ ** limitations under the License.
20
+ **
21
+ ************************************************************************
22
+ **
23
+ ** Module: n-crypt-aes.c
24
+ ** Summary: native functions for old AES code
25
+ ** Section: natives
26
+ ** Author: Oldes, Cyphre
27
+ ** Notes:
28
+ **
29
+ ***********************************************************************/
30
+
31
+ #include "sys-core.h"
32
+
33
+ #ifdef INCLUDE_CHACHA20POLY1305_DEPRECATED
34
+ #include "sys-chacha20.h"
35
+ #include "sys-poly1305.h"
36
+ #endif
37
+
38
+
39
+ /***********************************************************************
40
+ **
41
+ */ REBNATIVE (chacha20 )
42
+ /*
43
+ // chacha20: native [
44
+ // "Encrypt/decrypt data using ChaCha20 algorithm. Returns stream cipher context handle or encrypted/decrypted data."
45
+ // ctx [handle! binary!] "ChaCha20 handle and or binary key for initialization (16 or 32 bytes)"
46
+ // /init
47
+ // nonce [binary!] "Initialization nonce (IV) - 8 or 12 bytes."
48
+ // count [integer!] "A 32-bit block count parameter"
49
+ // /aad sequence [integer!] "Sequence number used with /init to modify nonce"
50
+ // /stream
51
+ // data [binary!] "Data to encrypt/decrypt."
52
+ // /into
53
+ // out [binary!] "Output buffer (NOT YET IMPLEMENTED)"
54
+ // ]
55
+ ***********************************************************************/
56
+ {
57
+ #ifndef INCLUDE_CHACHA20POLY1305_DEPRECATED
58
+ Trap0 (RE_FEATURE_NA );
59
+ #else
60
+ REBVAL * val_ctx = D_ARG (1 );
61
+ REBOOL ref_init = D_REF (2 );
62
+ REBVAL * val_nonce = D_ARG (3 );
63
+ REBVAL * val_counter = D_ARG (4 );
64
+ REBOOL ref_aad = D_REF (5 );
65
+ REBVAL * val_sequence = D_ARG (6 );
66
+ REBOOL ref_stream = D_REF (7 );
67
+ REBVAL * val_data = D_ARG (8 );
68
+ REBOOL ref_into = D_REF (9 );
69
+
70
+ if (ref_into )
71
+ Trap0 (RE_FEATURE_NA );
72
+
73
+ REBINT len ;
74
+ REBU64 sequence ;
75
+
76
+ if (IS_BINARY (val_ctx )) {
77
+ len = VAL_LEN (val_ctx );
78
+ if (!(len == 32 || len == 16 )) {
79
+ //printf("ChaCha20 key must be of size 32 or 16 bytes! Is: %i\n", len);
80
+ Trap1 (RE_INVALID_DATA , val_ctx );
81
+ return R_NONE ;
82
+ }
83
+ REBYTE * bin_key = VAL_BIN_AT (val_ctx );
84
+
85
+ MAKE_HANDLE (val_ctx , SYM_CHACHA20 );
86
+ chacha20_keysetup ((chacha20_ctx * )VAL_HANDLE_CONTEXT_DATA (val_ctx ), bin_key , len );
87
+ }
88
+ else {
89
+ if (NOT_VALID_CONTEXT_HANDLE (val_ctx , SYM_CHACHA20 )) {
90
+ Trap0 (RE_INVALID_HANDLE );
91
+ return R_NONE ; // avoid wornings later
92
+ }
93
+ }
94
+
95
+ if (ref_init ) {
96
+ // initialize nonce with counter
97
+
98
+ len = VAL_LEN (val_nonce );
99
+
100
+ if (!(len == 12 || len == 8 )) {
101
+ Trap1 (RE_INVALID_DATA , val_nonce );
102
+ return R_NONE ;
103
+ }
104
+
105
+ sequence = (ref_aad ) ? VAL_INT64 (val_sequence ) : 0 ;
106
+ chacha20_ivsetup ((chacha20_ctx * )VAL_HANDLE_CONTEXT_DATA (val_ctx ), VAL_BIN_AT (val_nonce ), len , VAL_INT64 (val_counter ), (u8 * )& sequence );
107
+ }
108
+
109
+ if (ref_stream ) {
110
+
111
+ len = VAL_LEN (val_data );
112
+ if (len == 0 ) return R_NONE ;
113
+
114
+ REBYTE * data = VAL_BIN_AT (val_data );
115
+ REBSER * binaryOut = Make_Binary (len );
116
+
117
+ chacha20_encrypt (
118
+ (chacha20_ctx * )VAL_HANDLE_CONTEXT_DATA (val_ctx ),
119
+ (const uint8_t * )data ,
120
+ ( uint8_t * )BIN_DATA (binaryOut ),
121
+ len
122
+ );
123
+
124
+ SET_BINARY (val_ctx , binaryOut );
125
+ VAL_TAIL (val_ctx ) = len ;
126
+
127
+ }
128
+ #endif // EXCLUDE_CHACHA20POLY1305
129
+ return R_ARG1 ;
130
+ }
131
+
132
+
133
+
134
+ /***********************************************************************
135
+ **
136
+ */ REBNATIVE (poly1305 )
137
+ /*
138
+ // poly1305: native [
139
+ // "poly1305 message-authentication"
140
+ // ctx [handle! binary!] "poly1305 handle and or binary key for initialization (32 bytes)"
141
+ // /update data [binary!] "data to authenticate"
142
+ // /finish "finish data stream and return raw result as a binary"
143
+ // /verify "finish data stream and compare result with expected result (MAC)"
144
+ // mac [binary!] "16 bytes of verification MAC"
145
+ // ]
146
+ ***********************************************************************/
147
+ {
148
+ #ifndef INCLUDE_CHACHA20POLY1305_DEPRECATED
149
+ Trap0 (RE_FEATURE_NA );
150
+ #else
151
+ REBVAL * val_ctx = D_ARG (1 );
152
+ REBOOL ref_update = D_REF (2 );
153
+ REBVAL * val_data = D_ARG (3 );
154
+ REBOOL ref_finish = D_REF (4 );
155
+ REBOOL ref_verify = D_REF (5 );
156
+ REBVAL * val_mac = D_ARG (6 );
157
+
158
+ REBVAL * ret = D_RET ;
159
+ // REBSER *ctx_ser;
160
+ REBINT len ;
161
+ // REBCNT i;
162
+ REBYTE mac [16 ];
163
+
164
+ if (IS_BINARY (val_ctx )) {
165
+ len = VAL_LEN (val_ctx );
166
+ if (len < POLY1305_KEYLEN ) {
167
+ Trap1 (RE_INVALID_DATA , val_ctx );
168
+ return R_NONE ;
169
+ }
170
+
171
+ REBYTE * bin_key = VAL_BIN_AT (val_ctx );
172
+
173
+ MAKE_HANDLE (val_ctx , SYM_POLY1305 );
174
+ poly1305_init ((poly1305_context * )VAL_HANDLE_CONTEXT_DATA (val_ctx ), bin_key );
175
+ }
176
+ else {
177
+ if (NOT_VALID_CONTEXT_HANDLE (val_ctx , SYM_POLY1305 )) {
178
+ Trap0 (RE_INVALID_HANDLE );
179
+ }
180
+ }
181
+
182
+ if (ref_update ) {
183
+ poly1305_update ((poly1305_context * )VAL_HANDLE_CONTEXT_DATA (val_ctx ), VAL_BIN_AT (val_data ), VAL_LEN (val_data ));
184
+ }
185
+
186
+ if (ref_finish ) {
187
+ SET_BINARY (ret , Make_Series (16 , 1 , FALSE));
188
+ VAL_TAIL (ret ) = 16 ;
189
+ poly1305_finish ((poly1305_context * )VAL_HANDLE_CONTEXT_DATA (val_ctx ), VAL_BIN (ret ));
190
+ return R_RET ;
191
+ }
192
+
193
+ if (ref_verify ) {
194
+ if (VAL_LEN (val_mac ) != POLY1305_TAGLEN )
195
+ return R_FALSE ; // or error?
196
+ CLEARS (mac );
197
+ poly1305_finish ((poly1305_context * )VAL_HANDLE_CONTEXT_DATA (val_ctx ), mac );
198
+ return (poly1305_verify (VAL_BIN_AT (val_mac ), mac )) ? R_TRUE : R_FALSE ;
199
+ }
200
+
201
+ #endif // EXCLUDE_CHACHA20POLY1305
202
+ return R_ARG1 ;
203
+ }
204
+
205
+ /***********************************************************************
206
+ **
207
+ */ REBNATIVE (chacha20poly1305 )
208
+ /*
209
+ // chacha20poly1305: native [
210
+ // "..."
211
+ // ctx [none! handle!]
212
+ // /init
213
+ // local-key [binary!]
214
+ // local-iv [binary!]
215
+ // remote-key [binary!]
216
+ // remote-iv [binary!]
217
+ // /encrypt
218
+ // data-out [binary!]
219
+ // aad-out [binary!]
220
+ // /decrypt
221
+ // data-in [binary!]
222
+ // aad-in [binary!]
223
+ // ]
224
+ ***********************************************************************/
225
+ {
226
+ #ifndef INCLUDE_CHACHA20POLY1305_DEPRECATED
227
+ Trap0 (RE_FEATURE_NA );
228
+ #else
229
+ REBVAL * val_ctx = D_ARG (1 );
230
+ REBOOL ref_init = D_REF (2 );
231
+ REBVAL * val_local_key = D_ARG (3 );
232
+ REBVAL * val_local_iv = D_ARG (4 );
233
+ REBVAL * val_remote_key = D_ARG (5 );
234
+ REBVAL * val_remote_iv = D_ARG (6 );
235
+ REBOOL ref_encrypt = D_REF (7 );
236
+ REBVAL * val_plain = D_ARG (8 );
237
+ REBVAL * val_local_aad = D_ARG (9 );
238
+ REBOOL ref_decrypt = D_REF (10 );
239
+ REBVAL * val_cipher = D_ARG (11 );
240
+ REBVAL * val_remote_aad = D_ARG (12 );
241
+
242
+ REBSER * ctx_ser ;
243
+ REBINT len ;
244
+ chacha20poly1305_ctx * chacha ;
245
+ unsigned char poly1305_key [POLY1305_KEYLEN ];
246
+ size_t aad_size ;
247
+ REBU64 sequence = 0 ;
248
+
249
+ if (ref_init ) {
250
+ MAKE_HANDLE (val_ctx , SYM_CHACHA20POLY1305 );
251
+
252
+ chacha = (chacha20poly1305_ctx * )VAL_HANDLE_CONTEXT_DATA (val_ctx );
253
+ len = VAL_LEN (val_local_key );
254
+ if (!(len == 32 || len == 16 ))
255
+ Trap1 (RE_INVALID_DATA , val_local_key );
256
+ chacha20_keysetup (& chacha -> local_chacha , VAL_BIN_AT (val_local_key ), len );
257
+ len = VAL_LEN (val_remote_key );
258
+ if (!(len == 32 || len == 16 ))
259
+ Trap1 (RE_INVALID_DATA , val_remote_key );
260
+ chacha20_keysetup (& chacha -> remote_chacha , VAL_BIN_AT (val_remote_key ), len );
261
+
262
+ len = VAL_LEN (val_local_iv );
263
+ if (!(len == 12 || len == 8 ))
264
+ Trap1 (RE_INVALID_DATA , val_local_iv );
265
+ chacha20_ivsetup (& chacha -> local_chacha , VAL_BIN_AT (val_local_iv ), len , 1 , (u8 * )& sequence );
266
+ memcpy (chacha -> local_iv , VAL_BIN_AT (val_local_iv ), len );
267
+
268
+ len = VAL_LEN (val_remote_iv );
269
+ if (!(len == 12 || len == 8 ))
270
+ Trap1 (RE_INVALID_DATA , val_remote_iv );
271
+ chacha20_ivsetup (& chacha -> remote_chacha , VAL_BIN_AT (val_remote_iv ), len , 1 , (u8 * )& sequence );
272
+ memcpy (chacha -> remote_iv , VAL_BIN_AT (val_remote_iv ), len );
273
+ return R_ARG1 ;
274
+ }
275
+
276
+ if (NOT_VALID_CONTEXT_HANDLE (val_ctx , SYM_CHACHA20POLY1305 )) {
277
+ Trap0 (RE_INVALID_HANDLE );
278
+ return R_NONE ;
279
+ }
280
+ chacha = (chacha20poly1305_ctx * )VAL_HANDLE_CONTEXT_DATA (val_ctx );
281
+
282
+ if (ref_encrypt ) {
283
+ chacha20_ivsetup (& chacha -> local_chacha , chacha -> local_iv , 12 , 1 , VAL_BIN_AT (val_local_aad ));
284
+ chacha20_poly1305_key (& chacha -> local_chacha , poly1305_key );
285
+ //puts("poly1305_key:"); Dump_Bytes(poly1305_key, POLY1305_KEYLEN);
286
+
287
+ len = VAL_LEN (val_plain ) + POLY1305_TAGLEN ;
288
+ ctx_ser = Make_Series (len , (REBCNT )1 , FALSE);
289
+
290
+ // AEAD
291
+ // sequence number (8 bytes)
292
+ // content type (1 byte)
293
+ // version (2 bytes)
294
+ // length (2 bytes)
295
+ unsigned char aad [13 ];
296
+ aad_size = sizeof (aad );
297
+ // unsigned char *sequence = aad;
298
+
299
+ chacha20_poly1305_aead (& chacha -> local_chacha , VAL_BIN_AT (val_plain ), (REBCNT )len - POLY1305_TAGLEN , VAL_BIN_AT (val_local_aad ), VAL_LEN (val_local_aad ), poly1305_key , ctx_ser -> data );
300
+
301
+ //chacha->local_sequence++;
302
+
303
+ SERIES_TAIL (ctx_ser ) = len ;
304
+ SET_BINARY (val_ctx , ctx_ser );
305
+ return R_ARG1 ;
306
+ }
307
+
308
+ if (ref_decrypt ) {
309
+ static unsigned char zeropad [] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
310
+ unsigned char trail [16 ];
311
+ unsigned char mac_tag [POLY1305_TAGLEN ];
312
+
313
+ chacha20_ivsetup (& chacha -> remote_chacha , chacha -> remote_iv , 12 , 1 , VAL_BIN_AT (val_remote_aad ));
314
+
315
+ len = VAL_LEN (val_cipher ) - POLY1305_TAGLEN ;
316
+ if (len <= 0 )
317
+ return R_NONE ;
318
+
319
+ ctx_ser = Make_Series (len , (REBCNT )1 , FALSE);
320
+
321
+ //puts("\nDECRYPT:");
322
+
323
+ chacha20_encrypt (& chacha -> remote_chacha , VAL_BIN_AT (val_cipher ), ctx_ser -> data , len );
324
+ //chacha_encrypt_bytes(&chacha->remote_chacha, VAL_BIN_AT(val_cipher), ctx_ser->data, len);
325
+ chacha20_poly1305_key (& chacha -> remote_chacha , poly1305_key );
326
+ //puts("poly1305_key:"); Dump_Bytes(poly1305_key, POLY1305_KEYLEN);
327
+
328
+ poly1305_context aead_ctx ;
329
+ poly1305_init (& aead_ctx , poly1305_key );
330
+
331
+ aad_size = VAL_LEN (val_remote_aad );
332
+ poly1305_update (& aead_ctx , VAL_BIN_AT (val_remote_aad ), aad_size );
333
+ int rem = aad_size % 16 ;
334
+ if (rem )
335
+ poly1305_update (& aead_ctx , zeropad , 16 - rem );
336
+ //puts("update:"); Dump_Bytes(VAL_BIN_AT(val_cipher), len);
337
+ poly1305_update (& aead_ctx , VAL_BIN_AT (val_cipher ), len );
338
+ rem = len % 16 ;
339
+ if (rem )
340
+ poly1305_update (& aead_ctx , zeropad , 16 - rem );
341
+
342
+ U32TO8_LE (& trail [0 ], aad_size == 5 ? 5 : 13 );
343
+ * (int * )& trail [4 ] = 0 ;
344
+ U32TO8_LE (& trail [8 ], len );
345
+ * (int * )& trail [12 ] = 0 ;
346
+
347
+ //puts("trail:"); Dump_Bytes(trail, 16);
348
+
349
+ poly1305_update (& aead_ctx , trail , 16 );
350
+ poly1305_finish (& aead_ctx , mac_tag );
351
+
352
+ if (!poly1305_verify (mac_tag , VAL_BIN_TAIL (val_cipher ) - POLY1305_TAGLEN )) {
353
+ //puts("MAC verification failed!");
354
+ return R_NONE ;
355
+ }
356
+
357
+ //puts("mac result:"); Dump_Bytes(mac_tag, POLY1305_TAGLEN);
358
+
359
+ SERIES_TAIL (ctx_ser ) = len ;
360
+ SET_BINARY (val_ctx , ctx_ser );
361
+ }
362
+ #endif // EXCLUDE_CHACHA20POLY1305
363
+ return R_ARG1 ;
364
+ }
0 commit comments