1 #include <Rinternals.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <openssl/crypto.h>
5 #include <openssl/evp.h>
6 #include "utils.h"
7
8 /*
9 * Adapted from example at: https://www.openssl.org/docs/crypto/EVP_EncryptInit.html
10 */
11
R_aes_any(SEXP x,SEXP key,SEXP iv,SEXP encrypt,SEXP cipher)12 SEXP R_aes_any(SEXP x, SEXP key, SEXP iv, SEXP encrypt, SEXP cipher) {
13 int strength = LENGTH(key);
14 if(strength != 16 && strength != 24 && strength != 32)
15 error("key must be of length 16 (aes-128), 24 (aes-192) or 32 (aes-256)");
16
17 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
18 const EVP_CIPHER *cph = EVP_get_cipherbyname(CHAR(STRING_ELT(cipher, 0)));
19 if(!cph)
20 Rf_error("Invalid cipher: %s", CHAR(STRING_ELT(cipher, 0)));
21
22 #ifdef EVP_CIPH_GCM_MODE //openssl 1.0.0 does not have GCM
23 if(EVP_CIPHER_mode(cph) == EVP_CIPH_GCM_MODE){
24 if(LENGTH(iv) != 12){
25 Rf_error("aes-gcm requires an iv of length 12");
26 }
27 //GCM mode has shorter IV from the others
28 bail(EVP_CipherInit_ex(ctx, cph, NULL, NULL, NULL, asLogical(encrypt)));
29 bail(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, LENGTH(iv), NULL));
30 } else
31 #endif //EVP_CIPH_GCM_MODE
32 if(LENGTH(iv) != 16){
33 Rf_error("aes requires an iv of length 16");
34 }
35 bail(EVP_CipherInit_ex(ctx, cph, NULL, RAW(key), RAW(iv), asLogical(encrypt)));
36
37 int blocksize = EVP_CIPHER_CTX_block_size(ctx);
38 int remainder = LENGTH(x) % blocksize;
39 int outlen = LENGTH(x) + blocksize - remainder;
40 unsigned char *buf = OPENSSL_malloc(outlen);
41 unsigned char *cur = buf;
42
43 int tmp;
44 bail(EVP_CipherUpdate(ctx, cur, &tmp, RAW(x), LENGTH(x)));
45 cur += tmp;
46
47
48 #ifdef EVP_CIPH_GCM_MODE //openssl 1.0.0
49 //in GCM mode, res indicates if the security tag was verified successfully.
50 int res = EVP_CipherFinal_ex(ctx, cur, &tmp);
51 if(EVP_CIPHER_mode(cph) != EVP_CIPH_GCM_MODE)
52 bail(res);
53 #else
54 EVP_CipherFinal_ex(ctx, cur, &tmp);
55 #endif //EVP_CIPH_GCM_MODE
56 cur += tmp;
57
58 int total = cur - buf;
59 EVP_CIPHER_CTX_cleanup(ctx);
60 EVP_CIPHER_CTX_free(ctx);
61 SEXP out = allocVector(RAWSXP, total);
62 memcpy(RAW(out), buf, total);
63 OPENSSL_free(buf);
64 return out;
65 }
66