From 3d1ff2544652f7ca310238d9572544d4cf4b53fc Mon Sep 17 00:00:00 2001 From: Hans Zandbelt Date: Fri, 15 Mar 2019 11:13:04 +0100 Subject: [PATCH 1/3] first pass at supporting A128GCM and A192GCM (needs tests) Signed-off-by: Hans Zandbelt --- include/cjose/header.h | 4 +- src/header.c | 2 + src/jwe.c | 115 ++++++++++++++++++++++++++++++----------- 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/include/cjose/header.h b/include/cjose/header.h index 11e38c1..85f5f4a 100644 --- a/include/cjose/header.h +++ b/include/cjose/header.h @@ -82,7 +82,9 @@ extern const char *CJOSE_HDR_ALG_ES512; /** The JWE algorithm attribute value for "dir". */ extern const char *CJOSE_HDR_ALG_DIR; -/** The JWE content encryption algorithm value for A256GCM. */ +/** The JWE content encryption algorithm value for A128GCM, A192GCM and A256GCM. */ +extern const char *CJOSE_HDR_ENC_A128GCM; +extern const char *CJOSE_HDR_ENC_A192GCM; extern const char *CJOSE_HDR_ENC_A256GCM; /** The JWE content encryption algorithm value for A128CBC-HS256, A192CBC-HS384 and A256CBC-HS512. */ diff --git a/src/header.c b/src/header.c index 5e0dbb6..8f0f0a4 100644 --- a/src/header.c +++ b/src/header.c @@ -33,6 +33,8 @@ const char *CJOSE_HDR_ALG_ES384 = "ES384"; const char *CJOSE_HDR_ALG_ES512 = "ES512"; const char *CJOSE_HDR_ENC = "enc"; +const char *CJOSE_HDR_ENC_A128GCM = "A128GCM"; +const char *CJOSE_HDR_ENC_A192GCM = "A192GCM"; const char *CJOSE_HDR_ENC_A256GCM = "A256GCM"; const char *CJOSE_HDR_ENC_A128CBC_HS256 = "A128CBC-HS256"; const char *CJOSE_HDR_ENC_A192CBC_HS384 = "A192CBC-HS384"; diff --git a/src/jwe.c b/src/jwe.c index 822d408..878d036 100644 --- a/src/jwe.c +++ b/src/jwe.c @@ -28,7 +28,7 @@ //////////////////////////////////////////////////////////////////////////////// -static bool _cjose_jwe_set_cek_a256gcm(cjose_jwe_t *jwe, const cjose_jwk_t *jwk, bool random, cjose_err *err); +static bool _cjose_jwe_set_cek_aes_gcm(cjose_jwe_t *jwe, const cjose_jwk_t *jwk, bool random, cjose_err *err); static bool _cjose_jwe_set_cek_aes_cbc(cjose_jwe_t *jwe, const cjose_jwk_t *jwk, bool random, cjose_err *err); @@ -62,15 +62,15 @@ _cjose_jwe_encrypt_ek_ecdh_es(_jwe_int_recipient_t *recipient, cjose_jwe_t *jwe, static bool _cjose_jwe_decrypt_ek_ecdh_es(_jwe_int_recipient_t *recipient, cjose_jwe_t *jwe, const cjose_jwk_t *jwk, cjose_err *err); -static bool _cjose_jwe_set_iv_a256gcm(cjose_jwe_t *jwe, cjose_err *err); +static bool _cjose_jwe_set_iv_aes_gcm(cjose_jwe_t *jwe, cjose_err *err); static bool _cjose_jwe_set_iv_aes_cbc(cjose_jwe_t *jwe, cjose_err *err); -static bool _cjose_jwe_encrypt_dat_a256gcm(cjose_jwe_t *jwe, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err); +static bool _cjose_jwe_encrypt_dat_aes_gcm(cjose_jwe_t *jwe, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err); static bool _cjose_jwe_encrypt_dat_aes_cbc(cjose_jwe_t *jwe, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err); -static bool _cjose_jwe_decrypt_dat_a256gcm(cjose_jwe_t *jwe, cjose_err *err); +static bool _cjose_jwe_decrypt_dat_aes_gcm(cjose_jwe_t *jwe, cjose_err *err); static bool _cjose_jwe_decrypt_dat_aes_cbc(cjose_jwe_t *jwe, cjose_err *err); @@ -164,7 +164,11 @@ static size_t _keylen_from_enc(const char *alg) { size_t keylen = 0; - if (0 == strcmp(alg, CJOSE_HDR_ENC_A256GCM)) { + if (0 == strcmp(alg, CJOSE_HDR_ENC_A128GCM)) { + keylen = 128; + } else if (0 == strcmp(alg, CJOSE_HDR_ENC_A192GCM)) { + keylen = 192; + } else if (0 == strcmp(alg, CJOSE_HDR_ENC_A256GCM)) { keylen = 256; } else if (0 == strcmp(alg, CJOSE_HDR_ENC_A128CBC_HS256)) { keylen = 256; @@ -270,12 +274,12 @@ static bool _cjose_jwe_validate_enc(cjose_jwe_t *jwe, cjose_header_t *protected_ return false; } - if (strcmp(enc, CJOSE_HDR_ENC_A256GCM) == 0) + if ((strcmp(enc, CJOSE_HDR_ENC_A128GCM) == 0) || (strcmp(enc, CJOSE_HDR_ENC_A192GCM) == 0) || (strcmp(enc, CJOSE_HDR_ENC_A256GCM) == 0)) { - jwe->fns.set_cek = _cjose_jwe_set_cek_a256gcm; - jwe->fns.set_iv = _cjose_jwe_set_iv_a256gcm; - jwe->fns.encrypt_dat = _cjose_jwe_encrypt_dat_a256gcm; - jwe->fns.decrypt_dat = _cjose_jwe_decrypt_dat_a256gcm; + jwe->fns.set_cek = _cjose_jwe_set_cek_aes_gcm; + jwe->fns.set_iv = _cjose_jwe_set_iv_aes_gcm; + jwe->fns.encrypt_dat = _cjose_jwe_encrypt_dat_aes_gcm; + jwe->fns.decrypt_dat = _cjose_jwe_decrypt_dat_aes_gcm; } if ((strcmp(enc, CJOSE_HDR_ENC_A128CBC_HS256) == 0) || (strcmp(enc, CJOSE_HDR_ENC_A192CBC_HS384) == 0) || (strcmp(enc, CJOSE_HDR_ENC_A256CBC_HS512) == 0)) @@ -361,16 +365,31 @@ static bool _cjose_jwe_validate_alg(cjose_header_t *protected_header, } //////////////////////////////////////////////////////////////////////////////// -static bool _cjose_jwe_set_cek_a256gcm(cjose_jwe_t *jwe, const cjose_jwk_t *jwk, bool random, cjose_err *err) +static bool _cjose_jwe_set_cek_aes_gcm(cjose_jwe_t *jwe, const cjose_jwk_t *jwk, bool random, cjose_err *err) { - // 256 bits = 32 bytes - static const size_t keysize = 32; - if (NULL != jwe->cek) { return true; } + // make sure we have an enc header + json_t *enc_obj = json_object_get(jwe->hdr, CJOSE_HDR_ENC); + if (NULL == enc_obj) + { + CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); + return false; + } + const char *enc = json_string_value(enc_obj); + + // determine the CEK key size based on the encryption algorithm + size_t keysize = 0; + if (strcmp(enc, CJOSE_HDR_ENC_A128GCM) == 0) + keysize = 16; + if (strcmp(enc, CJOSE_HDR_ENC_A192GCM) == 0) + keysize = 24; + if (strcmp(enc, CJOSE_HDR_ENC_A256GCM) == 0) + keysize = 32; + // if no JWK is provided, generate a random key if (NULL == jwk) { @@ -848,7 +867,7 @@ static bool _cjose_jwe_decrypt_ek_ecdh_es(_jwe_int_recipient_t *recipient, } //////////////////////////////////////////////////////////////////////////////// -static bool _cjose_jwe_set_iv_a256gcm(cjose_jwe_t *jwe, cjose_err *err) +static bool _cjose_jwe_set_iv_aes_gcm(cjose_jwe_t *jwe, cjose_err *err) { // generate IV as random 96 bit value cjose_get_dealloc()(jwe->enc_iv.raw); @@ -907,18 +926,35 @@ static bool _cjose_jwe_set_iv_aes_cbc(cjose_jwe_t *jwe, cjose_err *err) #endif //////////////////////////////////////////////////////////////////////////////// -static bool _cjose_jwe_encrypt_dat_a256gcm(cjose_jwe_t *jwe, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err) +static bool _cjose_jwe_encrypt_dat_aes_gcm(cjose_jwe_t *jwe, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err) { EVP_CIPHER_CTX *ctx = NULL; + // make sure we have an enc header + json_t *enc_obj = json_object_get(jwe->hdr, CJOSE_HDR_ENC); + if (NULL == enc_obj) + { + CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); + return false; + } + const char *enc = json_string_value(enc_obj); + if (NULL == plaintext) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto _cjose_jwe_encrypt_dat_fail; } - // get A256GCM cipher - const EVP_CIPHER *cipher = EVP_aes_256_gcm(); + // get AES GCM cipher + const EVP_CIPHER *cipher = NULL; + + if (strcmp(enc, CJOSE_HDR_ENC_A128GCM) == 0) + cipher = EVP_aes_128_gcm(); + if (strcmp(enc, CJOSE_HDR_ENC_A192GCM) == 0) + cipher = EVP_aes_192_gcm(); + if (strcmp(enc, CJOSE_HDR_ENC_A256GCM) == 0) + cipher = EVP_aes_256_gcm(); + if (NULL == cipher) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); @@ -934,7 +970,7 @@ static bool _cjose_jwe_encrypt_dat_a256gcm(cjose_jwe_t *jwe, const uint8_t *plai } EVP_CIPHER_CTX_init(ctx); - // initialize context for encryption using A256GCM cipher and CEK and IV + // initialize context for encryption using AES GCM cipher and CEK and IV if (EVP_EncryptInit_ex(ctx, cipher, NULL, jwe->cek, jwe->enc_iv.raw) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); @@ -1197,16 +1233,33 @@ static bool _cjose_jwe_encrypt_dat_aes_cbc(cjose_jwe_t *jwe, const uint8_t *plai } //////////////////////////////////////////////////////////////////////////////// -static bool _cjose_jwe_decrypt_dat_a256gcm(cjose_jwe_t *jwe, cjose_err *err) +static bool _cjose_jwe_decrypt_dat_aes_gcm(cjose_jwe_t *jwe, cjose_err *err) { EVP_CIPHER_CTX *ctx = NULL; - // get A256GCM cipher - const EVP_CIPHER *cipher = EVP_aes_256_gcm(); + // make sure we have an enc header + json_t *enc_obj = json_object_get(jwe->hdr, CJOSE_HDR_ENC); + if (NULL == enc_obj) + { + CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); + return false; + } + const char *enc = json_string_value(enc_obj); + + // get AES CM cipher + const EVP_CIPHER *cipher = NULL; + + if (strcmp(enc, CJOSE_HDR_ENC_A128GCM) == 0) + cipher = EVP_aes_128_gcm(); + if (strcmp(enc, CJOSE_HDR_ENC_A192GCM) == 0) + cipher = EVP_aes_192_gcm(); + if (strcmp(enc, CJOSE_HDR_ENC_A256GCM) == 0) + cipher = EVP_aes_256_gcm(); + if (NULL == cipher) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); - goto _cjose_jwe_decrypt_dat_a256gcm_fail; + goto _cjose_jwe_decrypt_dat_aes_gcm_fail; } // instantiate and initialize a new openssl cipher context @@ -1214,7 +1267,7 @@ static bool _cjose_jwe_decrypt_dat_a256gcm(cjose_jwe_t *jwe, cjose_err *err) if (NULL == ctx) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); - goto _cjose_jwe_decrypt_dat_a256gcm_fail; + goto _cjose_jwe_decrypt_dat_aes_gcm_fail; } EVP_CIPHER_CTX_init(ctx); @@ -1222,14 +1275,14 @@ static bool _cjose_jwe_decrypt_dat_a256gcm(cjose_jwe_t *jwe, cjose_err *err) if (EVP_DecryptInit_ex(ctx, cipher, NULL, jwe->cek, jwe->enc_iv.raw) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); - goto _cjose_jwe_decrypt_dat_a256gcm_fail; + goto _cjose_jwe_decrypt_dat_aes_gcm_fail; } // set the expected GCM-mode authentication tag if (EVP_CIPHER_CTX_ctrl(ctx, CJOSE_EVP_CTRL_GCM_SET_TAG, jwe->enc_auth_tag.raw_len, jwe->enc_auth_tag.raw) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); - goto _cjose_jwe_decrypt_dat_a256gcm_fail; + goto _cjose_jwe_decrypt_dat_aes_gcm_fail; } // set GCM mode AAD data (hdr_b64u) by setting "out" to NULL @@ -1238,7 +1291,7 @@ static bool _cjose_jwe_decrypt_dat_a256gcm(cjose_jwe_t *jwe, cjose_err *err) || bytes_decrypted != jwe->enc_header.b64u_len) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); - goto _cjose_jwe_decrypt_dat_a256gcm_fail; + goto _cjose_jwe_decrypt_dat_aes_gcm_fail; } // allocate buffer for the plaintext @@ -1246,14 +1299,14 @@ static bool _cjose_jwe_decrypt_dat_a256gcm(cjose_jwe_t *jwe, cjose_err *err) jwe->dat_len = jwe->enc_ct.raw_len; if (!_cjose_jwe_malloc(jwe->dat_len, false, &jwe->dat, err)) { - goto _cjose_jwe_decrypt_dat_a256gcm_fail; + goto _cjose_jwe_decrypt_dat_aes_gcm_fail; } // decrypt ciphertext to plaintext buffer if (EVP_DecryptUpdate(ctx, jwe->dat, &bytes_decrypted, jwe->enc_ct.raw, jwe->enc_ct.raw_len) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); - goto _cjose_jwe_decrypt_dat_a256gcm_fail; + goto _cjose_jwe_decrypt_dat_aes_gcm_fail; } jwe->dat_len = bytes_decrypted; @@ -1261,13 +1314,13 @@ static bool _cjose_jwe_decrypt_dat_a256gcm(cjose_jwe_t *jwe, cjose_err *err) if (EVP_DecryptFinal_ex(ctx, NULL, &bytes_decrypted) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); - goto _cjose_jwe_decrypt_dat_a256gcm_fail; + goto _cjose_jwe_decrypt_dat_aes_gcm_fail; } EVP_CIPHER_CTX_free(ctx); return true; -_cjose_jwe_decrypt_dat_a256gcm_fail: +_cjose_jwe_decrypt_dat_aes_gcm_fail: if (NULL != ctx) { EVP_CIPHER_CTX_free(ctx); From 04ca7779f5f4469a0d73dac5540c20a97f2d807a Mon Sep 17 00:00:00 2001 From: Hans Zandbelt Date: Fri, 15 Mar 2019 14:49:18 +0100 Subject: [PATCH 2/3] add A128GCM and A192GCM self-encrypt/decrypt tests Signed-off-by: Hans Zandbelt --- test/check_jwe.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/check_jwe.c b/test/check_jwe.c index 459dce1..6d02528 100644 --- a/test/check_jwe.c +++ b/test/check_jwe.c @@ -206,6 +206,18 @@ static void _self_encrypt_self_decrypt_with_key(const char *alg, const char *enc static void _self_encrypt_self_decrypt(const char *plain1) { + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_RSA_OAEP, CJOSE_HDR_ENC_A128GCM, JWK_RSA, plain1); + + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_RSA1_5, CJOSE_HDR_ENC_A128GCM, JWK_RSA, plain1); + + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_DIR, CJOSE_HDR_ENC_A128GCM, JWK_OCT_16, plain1); + + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_RSA_OAEP, CJOSE_HDR_ENC_A192GCM, JWK_RSA, plain1); + + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_RSA1_5, CJOSE_HDR_ENC_A192GCM, JWK_RSA, plain1); + + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_DIR, CJOSE_HDR_ENC_A192GCM, JWK_OCT_24, plain1); + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_RSA_OAEP, CJOSE_HDR_ENC_A256GCM, JWK_RSA, plain1); _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_RSA1_5, CJOSE_HDR_ENC_A256GCM, JWK_RSA, plain1); @@ -224,6 +236,14 @@ static void _self_encrypt_self_decrypt(const char *plain1) _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_A256KW, CJOSE_HDR_ENC_A256CBC_HS512, JWK_OCT_32, plain1); + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_A128KW, CJOSE_HDR_ENC_A128GCM, JWK_OCT_16, plain1); + + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_ECDH_ES, CJOSE_HDR_ENC_A128GCM, JWK_EC, plain1); + + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_A128KW, CJOSE_HDR_ENC_A192GCM, JWK_OCT_16, plain1); + + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_ECDH_ES, CJOSE_HDR_ENC_A192GCM, JWK_EC, plain1); + _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_A128KW, CJOSE_HDR_ENC_A256GCM, JWK_OCT_16, plain1); _self_encrypt_self_decrypt_with_key(CJOSE_HDR_ALG_ECDH_ES, CJOSE_HDR_ENC_A256GCM, JWK_EC, plain1); From 532b911f9e4dc8a74f13ee8cdb07b0fd40ab8e2f Mon Sep 17 00:00:00 2001 From: Hans Zandbelt Date: Wed, 5 Jun 2019 07:56:24 +0200 Subject: [PATCH 3/3] fix mistakes in comments Signed-off-by: Hans Zandbelt --- src/jwe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jwe.c b/src/jwe.c index 878d036..241a3f4 100644 --- a/src/jwe.c +++ b/src/jwe.c @@ -1246,7 +1246,7 @@ static bool _cjose_jwe_decrypt_dat_aes_gcm(cjose_jwe_t *jwe, cjose_err *err) } const char *enc = json_string_value(enc_obj); - // get AES CM cipher + // get AES GCM cipher const EVP_CIPHER *cipher = NULL; if (strcmp(enc, CJOSE_HDR_ENC_A128GCM) == 0) @@ -1271,7 +1271,7 @@ static bool _cjose_jwe_decrypt_dat_aes_gcm(cjose_jwe_t *jwe, cjose_err *err) } EVP_CIPHER_CTX_init(ctx); - // initialize context for decryption using A256GCM cipher and CEK and IV + // initialize context for decryption using AES GCM cipher and CEK and IV if (EVP_DecryptInit_ex(ctx, cipher, NULL, jwe->cek, jwe->enc_iv.raw) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO);