From b5921574d7ed12ff9ac3015aa919f7a992c14346 Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Sun, 21 Jun 2020 00:55:05 +0200 Subject: [PATCH] Nettle module: Various additions --- modules/nettle/module.cpp | 435 ++++++++++++++++++++++++++++++++++++-- modules/nettle/module.h | 1 + 2 files changed, 420 insertions(+), 16 deletions(-) diff --git a/modules/nettle/module.cpp b/modules/nettle/module.cpp index 7453e94fd..04f1fc678 100644 --- a/modules/nettle/module.cpp +++ b/modules/nettle/module.cpp @@ -1,18 +1,24 @@ #include "module.h" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include #include #include #include -#include -#include -#include -#include -#include +#include #include -#include namespace cryptofuzz { namespace module { @@ -183,12 +189,17 @@ namespace Nettle_detail { Digest sha3_256(sha3_256_init, sha3_256_update, sha3_256_digest); Digest sha3_384(sha3_384_init, sha3_384_update, sha3_384_digest); Digest sha3_512(sha3_512_init, sha3_512_update, sha3_512_digest); + Digest streebog_256(streebog256_init, streebog256_update, streebog256_digest); + Digest streebog_512(streebog512_init, streebog512_update, streebog512_digest); HMAC hmac_md5(hmac_md5_set_key, hmac_md5_update, hmac_md5_digest); HMAC hmac_ripemd160(hmac_ripemd160_set_key, hmac_ripemd160_update, hmac_ripemd160_digest); HMAC hmac_sha1(hmac_sha1_set_key, hmac_sha1_update, hmac_sha1_digest); + HMAC hmac_sha224(hmac_sha224_set_key, hmac_sha224_update, hmac_sha224_digest); HMAC hmac_sha256(hmac_sha256_set_key, hmac_sha256_update, hmac_sha256_digest); HMAC hmac_sha512(hmac_sha512_set_key, hmac_sha512_update, hmac_sha512_digest); + HMAC hmac_streebog256(hmac_streebog256_set_key, hmac_streebog256_update, hmac_streebog256_digest); + HMAC hmac_streebog512(hmac_streebog512_set_key, hmac_streebog512_update, hmac_streebog512_digest); CMAC cmac_aes128(cmac_aes128_set_key, cmac_aes128_update, cmac_aes128_digest); CMAC cmac_aes256(cmac_aes256_set_key, cmac_aes256_update, cmac_aes256_digest); @@ -247,6 +258,12 @@ std::optional Nettle::OpDigest(operation::Digest& op) { case CF_DIGEST("GOST-R-34.11-94-NO-CRYPTOPRO"): ret = Nettle_detail::gosthash94.Run(op); break; + case CF_DIGEST("STREEBOG-256"): + ret = Nettle_detail::streebog_256.Run(op); + break; + case CF_DIGEST("STREEBOG-512"): + ret = Nettle_detail::streebog_512.Run(op); + break; } return ret; @@ -271,6 +288,12 @@ std::optional Nettle::OpHMAC(operation::HMAC& op) { case CF_DIGEST("SHA512"): ret = Nettle_detail::hmac_sha512.Run(op); break; + case CF_DIGEST("STREEBOG-256"): + ret = Nettle_detail::hmac_streebog256.Run(op); + break; + case CF_DIGEST("STREEBOG-512"): + ret = Nettle_detail::hmac_streebog512.Run(op); + break; } return ret; @@ -302,18 +325,19 @@ std::optional Nettle::OpSymmetricEncrypt(operation::Symme { struct gcm_aes128_ctx ctx; + CF_CHECK_NE(op.cipher.iv.GetSize(), 0); CF_CHECK_EQ(op.cipher.key.GetSize(), 128 / 8); CF_CHECK_NE(op.tagSize, std::nullopt); - CF_CHECK_NE(op.aad, std::nullopt); CF_CHECK_LTE(*op.tagSize, GCM_DIGEST_SIZE); - CF_CHECK_EQ(op.cleartext.GetSize() % 16, 0); out = util::malloc(op.cleartext.GetSize()); outTag = util::malloc(*op.tagSize); /* noret */ gcm_aes128_set_key(&ctx, op.cipher.key.GetPtr()); /* noret */ gcm_aes128_set_iv(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr()); - /* noret */ gcm_aes128_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + if ( op.aad != std::nullopt ) { + /* noret */ gcm_aes128_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } /* noret */ gcm_aes128_encrypt(&ctx, op.cleartext.GetSize(), out, op.cleartext.GetPtr()); /* noret */ gcm_aes128_digest(&ctx, *op.tagSize, outTag); @@ -325,18 +349,19 @@ std::optional Nettle::OpSymmetricEncrypt(operation::Symme { struct gcm_aes256_ctx ctx; + CF_CHECK_NE(op.cipher.iv.GetSize(), 0); CF_CHECK_EQ(op.cipher.key.GetSize(), 256 / 8); CF_CHECK_NE(op.tagSize, std::nullopt); - CF_CHECK_NE(op.aad, std::nullopt); CF_CHECK_LTE(*op.tagSize, GCM_DIGEST_SIZE); - CF_CHECK_EQ(op.cleartext.GetSize() % 16, 0); out = util::malloc(op.cleartext.GetSize()); outTag = util::malloc(*op.tagSize); /* noret */ gcm_aes256_set_key(&ctx, op.cipher.key.GetPtr()); /* noret */ gcm_aes256_set_iv(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr()); - /* noret */ gcm_aes256_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + if ( op.aad != std::nullopt ) { + /* noret */ gcm_aes256_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } /* noret */ gcm_aes256_encrypt(&ctx, op.cleartext.GetSize(), out, op.cleartext.GetPtr()); /* noret */ gcm_aes256_digest(&ctx, *op.tagSize, outTag); @@ -344,13 +369,138 @@ std::optional Nettle::OpSymmetricEncrypt(operation::Symme } break; + case CF_CIPHER("AES_128_EAX"): + { + struct eax_aes128_ctx ctx; + + CF_CHECK_NE(op.cipher.iv.GetSize(), 0); + CF_CHECK_EQ(op.cipher.key.GetSize(), 128 / 8); + CF_CHECK_NE(op.tagSize, std::nullopt); + CF_CHECK_LTE(*op.tagSize, EAX_DIGEST_SIZE); + CF_CHECK_GT(*op.tagSize, 0); /* XXX crashes without this check. This is probably a bug in Nettle */ + + out = util::malloc(op.cleartext.GetSize()); + outTag = util::malloc(*op.tagSize); + + /* noret */ eax_aes128_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ eax_aes128_set_nonce(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr()); + if ( op.aad != std::nullopt ) { + /* noret */ eax_aes128_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ eax_aes128_encrypt(&ctx, op.cleartext.GetSize(), out, op.cleartext.GetPtr()); + /* noret */ eax_aes128_digest(&ctx, *op.tagSize, outTag); + + ret = component::Ciphertext(Buffer(out, op.cleartext.GetSize()), Buffer(outTag, *op.tagSize)); + } + break; + + case CF_CIPHER("AES_128_CCM"): + { + struct ccm_aes128_ctx ctx; + + CF_CHECK_GTE(op.cipher.iv.GetSize(), 7); + CF_CHECK_LTE(op.cipher.iv.GetSize(), 13); + CF_CHECK_EQ(op.cipher.key.GetSize(), 128 / 8); + CF_CHECK_NE(op.tagSize, std::nullopt); + { + static const std::vector validTagSizes = {4, 6, 8, 10, 12, 14, 16}; + if ( std::find(validTagSizes.begin(), validTagSizes.end(), *op.tagSize) == validTagSizes.end() ) { + goto end; + } + } + + out = util::malloc(op.cleartext.GetSize()); + outTag = util::malloc(*op.tagSize); + + /* noret */ ccm_aes128_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ ccm_aes128_set_nonce(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr(), op.aad == std::nullopt ? 0 : op.aad->GetSize(), op.cleartext.GetSize(), *op.tagSize); + if ( op.aad != std::nullopt ) { + /* noret */ ccm_aes128_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ ccm_aes128_encrypt(&ctx, op.cleartext.GetSize(), out, op.cleartext.GetPtr()); + /* noret */ ccm_aes128_digest(&ctx, *op.tagSize, outTag); + + ret = component::Ciphertext(Buffer(out, op.cleartext.GetSize()), Buffer(outTag, *op.tagSize)); + } + break; + + case CF_CIPHER("AES_256_CCM"): + { + struct ccm_aes256_ctx ctx; + + CF_CHECK_GTE(op.cipher.iv.GetSize(), 7); + CF_CHECK_LTE(op.cipher.iv.GetSize(), 13); + CF_CHECK_EQ(op.cipher.key.GetSize(), 256 / 8); + CF_CHECK_NE(op.tagSize, std::nullopt); + { + static const std::vector validTagSizes = {4, 6, 8, 10, 12, 14, 16}; + if ( std::find(validTagSizes.begin(), validTagSizes.end(), *op.tagSize) == validTagSizes.end() ) { + goto end; + } + } + + out = util::malloc(op.cleartext.GetSize()); + outTag = util::malloc(*op.tagSize); + + /* noret */ ccm_aes256_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ ccm_aes256_set_nonce(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr(), op.aad == std::nullopt ? 0 : op.aad->GetSize(), op.cleartext.GetSize(), *op.tagSize); + if ( op.aad != std::nullopt ) { + /* noret */ ccm_aes256_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ ccm_aes256_encrypt(&ctx, op.cleartext.GetSize(), out, op.cleartext.GetPtr()); + /* noret */ ccm_aes256_digest(&ctx, *op.tagSize, outTag); + + ret = component::Ciphertext(Buffer(out, op.cleartext.GetSize()), Buffer(outTag, *op.tagSize)); + } + break; + + + case CF_CIPHER("CHACHA20"): + { + struct chacha_ctx ctx; + CF_CHECK_EQ(op.cipher.iv.GetSize(), CHACHA_NONCE_SIZE); + CF_CHECK_EQ(op.cipher.key.GetSize(), CHACHA_KEY_SIZE); + out = util::malloc(op.cleartext.GetSize()); + + /* noret */ chacha_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ chacha_set_nonce(&ctx, op.cipher.iv.GetPtr()); + /* noret */ chacha_crypt(&ctx, op.cleartext.GetSize(), out, op.cleartext.GetPtr()); + + ret = component::Ciphertext(Buffer(out, op.cleartext.GetSize())); + } + break; + + case CF_CIPHER("CHACHA20_POLY1305"): + { + struct chacha_poly1305_ctx ctx; + + CF_CHECK_EQ(op.cipher.iv.GetSize(), CHACHA_POLY1305_NONCE_SIZE); + CF_CHECK_EQ(op.cipher.key.GetSize(), CHACHA_POLY1305_KEY_SIZE); + CF_CHECK_NE(op.tagSize, std::nullopt); + CF_CHECK_LTE(*op.tagSize, CHACHA_POLY1305_DIGEST_SIZE); + + out = util::malloc(op.cleartext.GetSize()); + outTag = util::malloc(*op.tagSize); + + /* noret */ chacha_poly1305_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ chacha_poly1305_set_nonce(&ctx, op.cipher.iv.GetPtr()); + if ( op.aad != std::nullopt ) { + /* noret */ chacha_poly1305_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ chacha_poly1305_encrypt(&ctx, op.cleartext.GetSize(), out, op.cleartext.GetPtr()); + /* noret */ chacha_poly1305_digest(&ctx, *op.tagSize, outTag); + + ret = component::Ciphertext(Buffer(out, op.cleartext.GetSize()), Buffer(outTag, *op.tagSize)); + } + break; + case CF_CIPHER("AES_128_XTS"): { struct xts_aes128_key ctx; CF_CHECK_EQ(op.cipher.key.GetSize(), 256 / 8); CF_CHECK_GT(op.cleartext.GetSize(), 0); CF_CHECK_EQ(op.cleartext.GetSize() % 16, 0); - CF_CHECK_GT(op.cipher.iv.GetSize(), 0); /* XXX crashes without this check */ + CF_CHECK_EQ(op.cipher.iv.GetSize(), XTS_BLOCK_SIZE); out = util::malloc(op.cleartext.GetSize()); @@ -367,13 +517,14 @@ std::optional Nettle::OpSymmetricEncrypt(operation::Symme CF_CHECK_EQ(op.cipher.key.GetSize(), 512 / 8); CF_CHECK_GT(op.cleartext.GetSize(), 0); CF_CHECK_EQ(op.cleartext.GetSize() % 16, 0); - CF_CHECK_GT(op.cipher.iv.GetSize(), 0); /* XXX crashes without this check */ + CF_CHECK_EQ(op.cipher.iv.GetSize(), XTS_BLOCK_SIZE); out = util::malloc(op.cleartext.GetSize()); /* noret */ xts_aes256_set_encrypt_key(&ctx, op.cipher.key.GetPtr()); /* noret */ xts_aes256_encrypt_message(&ctx, op.cipher.iv.GetPtr(), op.cleartext.GetSize(), out, op.cleartext.GetPtr()); + if ( op.cleartext.GetSize() ) out[0]++; ret = component::Ciphertext(Buffer(out, op.cleartext.GetSize())); } break; @@ -407,15 +558,200 @@ std::optional Nettle::OpSymmetricDecrypt(operation::Symmet std::optional ret = std::nullopt; uint8_t* out = nullptr; + uint8_t* outTag = nullptr; switch ( op.cipher.cipherType.Get() ) { + case CF_CIPHER("AES_128_GCM"): + { + struct gcm_aes128_ctx ctx; + + CF_CHECK_NE(op.cipher.iv.GetSize(), 0); + CF_CHECK_EQ(op.cipher.key.GetSize(), 128 / 8); + CF_CHECK_NE(op.tag, std::nullopt); + CF_CHECK_LTE(op.tag->GetSize(), GCM_DIGEST_SIZE); + + out = util::malloc(op.ciphertext.GetSize()); + outTag = util::malloc(op.tag->GetSize()); + + /* noret */ gcm_aes128_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ gcm_aes128_set_iv(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr()); + if ( op.aad != std::nullopt ) { + /* noret */ gcm_aes128_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ gcm_aes128_decrypt(&ctx, op.ciphertext.GetSize(), out, op.ciphertext.GetPtr()); + /* noret */ gcm_aes128_digest(&ctx, op.tag->GetSize(), outTag); + + CF_CHECK_EQ(memcmp(op.tag->GetPtr(), outTag, op.tag->GetSize()), 0); + + ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize())); + } + break; + + case CF_CIPHER("AES_256_GCM"): + { + struct gcm_aes256_ctx ctx; + + CF_CHECK_NE(op.cipher.iv.GetSize(), 0); + CF_CHECK_EQ(op.cipher.key.GetSize(), 256 / 8); + CF_CHECK_NE(op.tag, std::nullopt); + CF_CHECK_LTE(op.tag->GetSize(), GCM_DIGEST_SIZE); + + out = util::malloc(op.ciphertext.GetSize()); + outTag = util::malloc(op.tag->GetSize()); + + /* noret */ gcm_aes256_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ gcm_aes256_set_iv(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr()); + if ( op.aad != std::nullopt ) { + /* noret */ gcm_aes256_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ gcm_aes256_decrypt(&ctx, op.ciphertext.GetSize(), out, op.ciphertext.GetPtr()); + /* noret */ gcm_aes256_digest(&ctx, op.tag->GetSize(), outTag); + + CF_CHECK_EQ(memcmp(op.tag->GetPtr(), outTag, op.tag->GetSize()), 0); + + ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize())); + } + break; + + case CF_CIPHER("AES_128_EAX"): + { + struct eax_aes128_ctx ctx; + + CF_CHECK_NE(op.cipher.iv.GetSize(), 0); + CF_CHECK_EQ(op.cipher.key.GetSize(), 128 / 8); + CF_CHECK_NE(op.tag, std::nullopt); + CF_CHECK_LTE(op.tag->GetSize(), EAX_DIGEST_SIZE); + CF_CHECK_GT(op.tag->GetSize(), 0); /* XXX crashes without this check. This is probably a bug in Nettle */ + + out = util::malloc(op.ciphertext.GetSize()); + outTag = util::malloc(op.tag->GetSize()); + + /* noret */ eax_aes128_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ eax_aes128_set_nonce(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr()); + if ( op.aad != std::nullopt ) { + /* noret */ eax_aes128_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ eax_aes128_decrypt(&ctx, op.ciphertext.GetSize(), out, op.ciphertext.GetPtr()); + /* noret */ eax_aes128_digest(&ctx, op.tag->GetSize(), outTag); + + CF_CHECK_EQ(memcmp(op.tag->GetPtr(), outTag, op.tag->GetSize()), 0); + + ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize())); + } + break; + + case CF_CIPHER("AES_128_CCM"): + { + struct ccm_aes128_ctx ctx; + + CF_CHECK_GTE(op.cipher.iv.GetSize(), 7); + CF_CHECK_LTE(op.cipher.iv.GetSize(), 13); + CF_CHECK_EQ(op.cipher.key.GetSize(), 128 / 8); + CF_CHECK_NE(op.tag, std::nullopt); + { + static const std::vector validTagSizes = {4, 6, 8, 10, 12, 14, 16}; + if ( std::find(validTagSizes.begin(), validTagSizes.end(), op.tag->GetSize()) == validTagSizes.end() ) { + goto end; + } + } + + out = util::malloc(op.ciphertext.GetSize()); + outTag = util::malloc(op.tag->GetSize()); + + /* noret */ ccm_aes128_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ ccm_aes128_set_nonce(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr(), op.aad == std::nullopt ? 0 : op.aad->GetSize(), op.ciphertext.GetSize(), op.tag->GetSize()); + if ( op.aad != std::nullopt ) { + /* noret */ ccm_aes128_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ ccm_aes128_decrypt(&ctx, op.ciphertext.GetSize(), out, op.ciphertext.GetPtr()); + /* noret */ ccm_aes128_digest(&ctx, op.tag->GetSize(), outTag); + + CF_CHECK_EQ(memcmp(op.tag->GetPtr(), outTag, op.tag->GetSize()), 0); + + ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize())); + } + break; + + case CF_CIPHER("AES_256_CCM"): + { + struct ccm_aes256_ctx ctx; + + CF_CHECK_GTE(op.cipher.iv.GetSize(), 7); + CF_CHECK_LTE(op.cipher.iv.GetSize(), 13); + CF_CHECK_EQ(op.cipher.key.GetSize(), 256 / 8); + CF_CHECK_NE(op.tag, std::nullopt); + { + static const std::vector validTagSizes = {4, 6, 8, 10, 12, 14, 16}; + if ( std::find(validTagSizes.begin(), validTagSizes.end(), op.tag->GetSize()) == validTagSizes.end() ) { + goto end; + } + } + + out = util::malloc(op.ciphertext.GetSize()); + outTag = util::malloc(op.tag->GetSize()); + + /* noret */ ccm_aes256_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ ccm_aes256_set_nonce(&ctx, op.cipher.iv.GetSize(), op.cipher.iv.GetPtr(), op.aad == std::nullopt ? 0 : op.aad->GetSize(), op.ciphertext.GetSize(), op.tag->GetSize()); + if ( op.aad != std::nullopt ) { + /* noret */ ccm_aes256_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ ccm_aes256_decrypt(&ctx, op.ciphertext.GetSize(), out, op.ciphertext.GetPtr()); + /* noret */ ccm_aes256_digest(&ctx, op.tag->GetSize(), outTag); + + CF_CHECK_EQ(memcmp(op.tag->GetPtr(), outTag, op.tag->GetSize()), 0); + + ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize())); + } + break; + + case CF_CIPHER("CHACHA20"): + { + struct chacha_ctx ctx; + CF_CHECK_EQ(op.cipher.iv.GetSize(), CHACHA_NONCE_SIZE); + CF_CHECK_EQ(op.cipher.key.GetSize(), CHACHA_KEY_SIZE); + out = util::malloc(op.ciphertext.GetSize()); + + /* noret */ chacha_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ chacha_set_nonce(&ctx, op.cipher.iv.GetPtr()); + /* noret */ chacha_crypt(&ctx, op.ciphertext.GetSize(), out, op.ciphertext.GetPtr()); + + ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize())); + } + break; + + case CF_CIPHER("CHACHA20_POLY1305"): + { + struct chacha_poly1305_ctx ctx; + + CF_CHECK_EQ(op.cipher.iv.GetSize(), CHACHA_POLY1305_NONCE_SIZE); + CF_CHECK_EQ(op.cipher.key.GetSize(), CHACHA_POLY1305_KEY_SIZE); + CF_CHECK_NE(op.tag, std::nullopt); + CF_CHECK_LTE(op.tag->GetSize(), CHACHA_POLY1305_DIGEST_SIZE); + + out = util::malloc(op.ciphertext.GetSize()); + outTag = util::malloc(op.tag->GetSize()); + + /* noret */ chacha_poly1305_set_key(&ctx, op.cipher.key.GetPtr()); + /* noret */ chacha_poly1305_set_nonce(&ctx, op.cipher.iv.GetPtr()); + if ( op.aad != std::nullopt ) { + /* noret */ chacha_poly1305_update(&ctx, op.aad->GetSize(), op.aad->GetPtr()); + } + /* noret */ chacha_poly1305_decrypt(&ctx, op.ciphertext.GetSize(), out, op.ciphertext.GetPtr()); + /* noret */ chacha_poly1305_digest(&ctx, op.tag->GetSize(), outTag); + + CF_CHECK_EQ(memcmp(op.tag->GetPtr(), outTag, op.tag->GetSize()), 0); + + ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize())); + } + break; + case CF_CIPHER("AES_128_XTS"): { struct xts_aes128_key ctx; CF_CHECK_EQ(op.cipher.key.GetSize(), 256 / 8); CF_CHECK_GT(op.ciphertext.GetSize(), 0); CF_CHECK_EQ(op.ciphertext.GetSize() % 16, 0); - CF_CHECK_GT(op.cipher.iv.GetSize(), 0); /* XXX crashes without this check */ + CF_CHECK_EQ(op.cipher.iv.GetSize(), XTS_BLOCK_SIZE); out = util::malloc(op.ciphertext.GetSize()); @@ -432,7 +768,7 @@ std::optional Nettle::OpSymmetricDecrypt(operation::Symmet CF_CHECK_EQ(op.cipher.key.GetSize(), 512 / 8); CF_CHECK_GT(op.ciphertext.GetSize(), 0); CF_CHECK_EQ(op.ciphertext.GetSize() % 16, 0); - CF_CHECK_GT(op.cipher.iv.GetSize(), 0); /* XXX crashes without this check */ + CF_CHECK_EQ(op.cipher.iv.GetSize(), XTS_BLOCK_SIZE); out = util::malloc(op.ciphertext.GetSize()); @@ -462,6 +798,73 @@ std::optional Nettle::OpSymmetricDecrypt(operation::Symmet end: util::free(out); + util::free(outTag); + + return ret; +} + +std::optional Nettle::OpKDF_HKDF(operation::KDF_HKDF& op) { + std::optional ret = std::nullopt; + + uint8_t* out = util::malloc(op.keySize); + + switch ( op.digestType.Get() ) { + case CF_DIGEST("SHA1"): + { + struct hmac_sha1_ctx ctx; + uint8_t prk[SHA1_DIGEST_SIZE]; + + CF_CHECK_LTE(op.keySize, 255 * SHA1_DIGEST_SIZE); + + hmac_sha1_set_key(&ctx, op.salt.GetSize(), op.salt.GetPtr()); + hkdf_extract(&ctx, + (nettle_hash_update_func*) hmac_sha1_update, + (nettle_hash_digest_func*) hmac_sha1_digest, + SHA1_DIGEST_SIZE, + op.password.GetSize(), op.password.GetPtr(), prk); + hmac_sha1_set_key(&ctx, SHA1_DIGEST_SIZE, prk); + hkdf_expand(&ctx, + (nettle_hash_update_func*) hmac_sha1_update, + (nettle_hash_digest_func*) hmac_sha1_digest, + SHA1_DIGEST_SIZE, + op.info.GetSize(), + op.info.GetPtr(), + op.keySize, + out); + ret = component::Key(out, op.keySize); + } + break; + case CF_DIGEST("SHA256"): + { + struct hmac_sha256_ctx ctx; + uint8_t prk[SHA256_DIGEST_SIZE]; + + CF_CHECK_LTE(op.keySize, 255 * SHA256_DIGEST_SIZE); + + hmac_sha256_set_key(&ctx, op.salt.GetSize(), op.salt.GetPtr()); + hkdf_extract(&ctx, + (nettle_hash_update_func*) hmac_sha256_update, + (nettle_hash_digest_func*) hmac_sha256_digest, + SHA256_DIGEST_SIZE, + op.password.GetSize(), op.password.GetPtr(), prk); + hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, prk); + hkdf_expand(&ctx, + (nettle_hash_update_func*) hmac_sha256_update, + (nettle_hash_digest_func*) hmac_sha256_digest, + SHA256_DIGEST_SIZE, + op.info.GetSize(), + op.info.GetPtr(), + op.keySize, + out); + ret = component::Key(out, op.keySize); + } + break; + } + +end: + + util::free(out); + return ret; } diff --git a/modules/nettle/module.h b/modules/nettle/module.h index 5cb047917..73131b6eb 100644 --- a/modules/nettle/module.h +++ b/modules/nettle/module.h @@ -15,6 +15,7 @@ class Nettle : public Module { std::optional OpCMAC(operation::CMAC& op) override; std::optional OpSymmetricEncrypt(operation::SymmetricEncrypt& op) override; std::optional OpSymmetricDecrypt(operation::SymmetricDecrypt& op) override; + std::optional OpKDF_HKDF(operation::KDF_HKDF& op) override; std::optional OpKDF_PBKDF2(operation::KDF_PBKDF2& op) override; };