Skip to content

Commit

Permalink
Merge pull request cisco#4 from zmartzone/add-aesgcm128-and-aesgcm192
Browse files Browse the repository at this point in the history
add support for A128GCM and A192GCM encryption
  • Loading branch information
zandbelt authored Apr 5, 2022
2 parents 86d604b + 532b911 commit 0d5e830
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 33 deletions.
4 changes: 3 additions & 1 deletion include/cjose/header.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
2 changes: 2 additions & 0 deletions src/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
117 changes: 85 additions & 32 deletions src/jwe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -1197,39 +1233,56 @@ 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 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);
goto _cjose_jwe_decrypt_dat_a256gcm_fail;
goto _cjose_jwe_decrypt_dat_aes_gcm_fail;
}

// instantiate and initialize a new openssl cipher context
ctx = EVP_CIPHER_CTX_new();
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);

// 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);
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
Expand All @@ -1238,36 +1291,36 @@ 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
cjose_get_dealloc()(jwe->dat);
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;

// finalize the decryption
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);
Expand Down
20 changes: 20 additions & 0 deletions test/check_jwe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 0d5e830

Please sign in to comment.