Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for A128GCM and A192GCM encryption #85

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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