ED_AAD,
ED_TAG_LEN,
ED_LABEL,
+ ED_OAEP_HASH,
// key generation
GEN_KEY_LEN = 201,
CKMC_PARAM_ED_AAD, /**< buffer - Additional Authentication Data for AES GCM */
CKMC_PARAM_ED_TAG_LEN, /**< integer - tag length in bits */
CKMC_PARAM_ED_LABEL, /**< buffer - RSA OAEP label (not supported at the moment) */
+ CKMC_PARAM_ED_OAEP_HASH, /**< integer - function to be used both as Label and MGF hash function
+ in OAEP padding (see #__ckmc_hash_algo). Currently only #CKMC_HASH_SHA1
+ and #CKMC_HASH_SHA256 are supported. If not given, the default
+ #CKMC_HASH_SHA1 is used. (Since 6.0) */
CKMC_PARAM_KDF_PRF = 401, /**< integer - pseudo-random function number (see #ckmc_kdf_prf_e)
(Since 6.0) */
- #CKMC_PARAM_ALGO_TYPE = #CKMC_ALGO_AES_CFB (mandatory),
- #CKMC_PARAM_ED_IV = 16-byte initialization vector (mandatory) */
- CKMC_ALGO_RSA_OAEP, /**< RSA-OAEP algorithm (EME-OAEP as defined in PKCS #1 with SHA-1 and MGF1)
+ CKMC_ALGO_RSA_OAEP, /**< RSA-OAEP algorithm (EME-OAEP as defined in PKCS #1 with MGF1)
Supported parameters:
- #CKMC_PARAM_ALGO_TYPE = #CKMC_ALGO_RSA_OAEP (mandatory),
- #CKMC_PARAM_ED_LABEL = label (encoding parameter) to be associated with
- the message (optional, not supported at the moment) */
+ the message (optional, not supported at the moment)
+ - #CKMC_PARAM_ED_OAEP_HASH = hash algorithm to be used in OAEP padding (see
+ #__ckmc_hash_algo). (optional) */
CKMC_ALGO_KBKDF, /**< Key based key derivation algorithm
Supported parameters:
case ParamName::ALGO_TYPE:
case ParamName::ED_CTR_LEN:
case ParamName::ED_TAG_LEN:
+ case ParamName::ED_OAEP_HASH:
case ParamName::GEN_KEY_LEN:
case ParamName::GEN_EC:
case ParamName::SV_HASH_ALGO:
false,
Type<int>::Equals<0, 8, 16, 24, 32>> KbkdfLlenCheck;
+typedef ParamCheck<ParamName::ED_OAEP_HASH,
+ HashAlgorithm,
+ false,
+ Type<HashAlgorithm>::Equals<HashAlgorithm::SHA1, HashAlgorithm::SHA256>> OaepHashAlgoCheck;
typedef std::map<AlgoType, ValidatorVector> ValidatorMap;
ValidatorMap initValidators()
validators.emplace(AlgoType::AES_CBC, VBuilder<IvSizeCheck>::Build());
validators.emplace(AlgoType::AES_CFB, VBuilder<IvSizeCheck>::Build());
validators.emplace(AlgoType::AES_GCM, VBuilder<GcmIvCheck, GcmTagCheck>::Build());
- validators.emplace(AlgoType::RSA_OAEP, VBuilder<RsaLabelCheck>::Build());
+ validators.emplace(AlgoType::RSA_OAEP, VBuilder<RsaLabelCheck, OaepHashAlgoCheck>::Build());
validators.emplace(AlgoType::ECDH, VBuilder<EcdhPubKeyCheck>::Build());
validators.emplace(AlgoType::KBKDF, VBuilder<KdfPrfCheck,
KbkdfModeCheck,
}
}
-
-RawBuffer asymmetricHelper(int (*cryptoFn)(int, const unsigned char *,
- unsigned char *, RSA *, int),
- const std::string &logPrefix,
- const EvpShPtr &pkey,
- const CryptoAlgorithm &alg,
- const RawBuffer &data)
-{
- validateParams<IsAsymEncryption>(alg);
-
- if (!pkey)
- ThrowErr(Exc::Crypto::InputParam, logPrefix, "no key");
-
- RSA *rsa = EVP_PKEY_get1_RSA(pkey.get());
-
- if (!rsa)
- ThrowErr(Exc::Crypto::InputParam, logPrefix, "invalid key");
-
- /*
- * RSA_padding_add_PKCS1_OAEP supports custom label but RSA_public_encrypt calls it with NULL
- * value so for now label is not supported. Alternative is to rewrite the openssl implementation
- * to support it: openssl-fips/crypto/rsa/rsa_eay.c
- */
- RawBuffer output;
- output.resize(RSA_size(rsa));
- int ret;
- try {
- ERR_clear_error();
- ret = cryptoFn(data.size(),
- data.data(),
- output.data(),
- rsa,
- RSA_PKCS1_OAEP_PADDING);
- if (ret < 0)
- errorHandle(__FILE__, __LINE__, __func__, ret);
- } catch (...) {
- RSA_free(rsa);
- throw;
- }
-
- output.resize(ret);
- return output;
-}
-
const EVP_MD *getMdAlgo(const HashAlgorithm hashAlgo)
{
switch (hashAlgo) {
ThrowErr(Exc::Crypto::InternalError, "Error in EVP_PKEY_CTX_new function");
}
+RawBuffer asymmetricHelper(
+ int (*initFn)(EVP_PKEY_CTX *),
+ int (*cryptFn)(EVP_PKEY_CTX *, unsigned char *, size_t *, const unsigned char *, size_t),
+ const EvpShPtr &pkey,
+ const CryptoAlgorithm &alg,
+ const RawBuffer &data)
+{
+ int ret;
+ size_t outlen;
+
+ validateParams<IsAsymEncryption>(alg);
+
+ HashAlgorithm hash = HashAlgorithm::SHA1;
+ alg.getParam(ParamName::ED_OAEP_HASH, hash);
+
+ if (!pkey)
+ ThrowErr(Exc::Crypto::InputParam, "no key");
+
+ if (EVP_PKEY_base_id(pkey.get()) != EVP_PKEY_RSA)
+ ThrowErr(Exc::Crypto::InputParam, "Wrong key type");
+
+ auto ctx = newCtx(pkey.get());
+
+ ret = (*initFn)(ctx.get());
+ if (ret <= 0)
+ errorHandle(__FILE__, __LINE__, __func__, ret);
+
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0)
+ ThrowErr(Exc::Crypto::InternalError, "EVP_PKEY_CTX_set_rsa_padding failed");
+
+ if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), getMdAlgo(hash)) <= 0)
+ ThrowErr(Exc::Crypto::InternalError, "EVP_PKEY_CTX_set_rsa_oaep_md failed");
+
+ // TODO set label with EVP_PKEY_CTX_set0_rsa_oaep_label
+
+ ret = (*cryptFn)(ctx.get(), NULL, &outlen, data.data(), data.size());
+ if (ret <= 0)
+ errorHandle(__FILE__, __LINE__, __func__, ret);
+
+ RawBuffer output(outlen);
+
+ ret = (*cryptFn)(ctx.get(), output.data(), &outlen, data.data(), data.size());
+ if (ret <= 0)
+ errorHandle(__FILE__, __LINE__, __func__, ret);
+
+ output.resize(outlen);
+ return output;
+}
+
DataPair keyPair(const EvpPkeyCtxUPtr &ctx, KeyType prv, KeyType pub)
{
EVP_PKEY *pkeyTmp = NULL;
const CryptoAlgorithm &alg,
const RawBuffer &data)
{
- return asymmetricHelper(RSA_public_encrypt, "Asymmetric encryption: ", pkey, alg, data);
+ return asymmetricHelper(EVP_PKEY_encrypt_init, EVP_PKEY_encrypt, pkey, alg, data);
}
RawBuffer asymmetricDecrypt(const EvpShPtr &pkey,
const CryptoAlgorithm &alg,
const RawBuffer &data)
{
- return asymmetricHelper(RSA_private_decrypt, "Asymmetric decryption: ", pkey, alg, data);
+ return asymmetricHelper(EVP_PKEY_decrypt_init, EVP_PKEY_decrypt, pkey, alg, data);
}
RawBuffer sign(EVP_PKEY *pkey,
AlgoType &algo,
uint32_t &ctrLenOrTagSizeBits,
RawBuffer &iv,
- RawBuffer &aad)
+ RawBuffer &aad,
+ HashAlgorithm &oaepHash)
{
algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+ oaepHash = HashAlgorithm::SHA1;
switch (algo) {
case AlgoType::AES_CTR:
iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
alg.getParam(ParamName::ED_AAD, aad);
break;
case AlgoType::RSA_OAEP:
+ alg.getParam(ParamName::ED_OAEP_HASH, oaepHash);
+ if (oaepHash == HashAlgorithm::NONE)
+ ThrowErr(Exc::Crypto::InputParam, "Invalid OAEP hash");
break;
default:
ThrowErr(Exc::Crypto::InputParam, "Invalid decryption algorithm");
uint32_t ctrLenOrTagSizeBits = 0;
RawBuffer iv;
RawBuffer aad;
- decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
+ HashAlgorithm oaepHash;
+ decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad, oaepHash);
// TODO it is awful!
TrustZoneContext::Instance().importWrappedKey(wrappingKeyId,
wrappingKeyPwd,
getAlgType(algo),
+ getHashType(oaepHash),
iv,
ctrLenOrTagSizeBits,
aad,
uint32_t ctrLenOrTagSizeBits = 0;
RawBuffer iv;
RawBuffer aad;
- decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
+ HashAlgorithm oaepHash;
+ decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad, oaepHash);
// TODO it is awful!
return TrustZoneContext::Instance().exportWrappedKey(wrappingKeyId,
wrappingKeyPwd,
getAlgType(algo),
+ getHashType(oaepHash),
iv,
ctrLenOrTagSizeBits,
aad,
keyToWrapId,
keyToWrapPwd,
toTzDataType(keyToWrapType));
+
}
RawBuffer getData(const RawBuffer &dataId,
RawBuffer result;
TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
getAlgType(algo),
+ HASH_SHA1, // ignored
keyId,
pwd,
unpack<RawBuffer>(alg, ParamName::ED_IV),
RawBuffer result;
TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
getAlgType(algo),
+ HASH_SHA1, // ignored
keyId,
pwd,
unpack<RawBuffer>(alg, ParamName::ED_IV),
const RawBuffer &data)
{
AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+ HashAlgorithm hash = HashAlgorithm::SHA1;
+ alg.getParam(ParamName::ED_OAEP_HASH, hash);
+ if (hash == HashAlgorithm::NONE)
+ ThrowErr(Exc::Crypto::InputParam, "Invalid OAEP hash");
+
RawBuffer result;
switch (algo)
case AlgoType::RSA_OAEP: {
TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
getAlgType(algo),
+ getHashType(hash),
keyId,
pwd,
result, // unused dummy
const RawBuffer &cipher)
{
AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+ HashAlgorithm hash = HashAlgorithm::SHA1;
+ alg.getParam(ParamName::ED_OAEP_HASH, hash);
+ if (hash != HashAlgorithm::SHA1 && hash != HashAlgorithm::SHA256)
+ ThrowErr(Exc::Crypto::InputParam, "Invalid OAEP hash");
+
RawBuffer result;
switch (algo)
case AlgoType::RSA_OAEP: {
TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
getAlgType(algo),
+ getHashType(hash),
keyId,
pwd,
result, // unused dummy
void TrustZoneContext::executeCrypt(tz_command cmd,
tz_algo_type algo,
+ tz_hash_type hash,
const RawBuffer &keyId,
const Pwd &pwd,
const RawBuffer &iv,
TZSerializer sIn;
if (algo == ALGO_RSA)
- sIn = makeSerializer(data, pwd, keyId);
+ sIn = makeSerializer(data, pwd, hash, keyId);
else
sIn = makeSerializer(data, pwd, iv, keyId);
void TrustZoneContext::importWrappedKey(const RawBuffer &wrappingKeyId,
const Pwd &wrappingKeyPwd,
tz_algo_type algo,
+ tz_hash_type oaepHash,
const RawBuffer &iv,
const uint32_t ctrLenOrTagSizeBits,
const RawBuffer &aad,
// command ID = CMD_IMPORT_WRAPPED_KEY
LogDebug("TrustZoneContext::importWrappedKey encryptedKey size = [" << encryptedKey.size() << "]");
- auto sIn = makeSerializer(wrappingKeyId,
- wrappingKeyPwd,
- algo,
- iv,
- ctrLenOrTagSizeBits,
- aad,
- encryptedKeyType,
- encryptedKey,
- EncPwd{encryptedKeyPwdBuf, encryptedKeyIV},
- encryptedKeyId);
+ TZSerializer sIn;
+ if (algo == ALGO_RSA) {
+ sIn = makeSerializer(wrappingKeyId,
+ wrappingKeyPwd,
+ algo,
+ oaepHash,
+ encryptedKeyType,
+ encryptedKey,
+ EncPwd{encryptedKeyPwdBuf, encryptedKeyIV},
+ encryptedKeyId);
+ } else {
+ sIn = makeSerializer(wrappingKeyId,
+ wrappingKeyPwd,
+ algo,
+ iv,
+ ctrLenOrTagSizeBits,
+ aad,
+ encryptedKeyType,
+ encryptedKey,
+ EncPwd{encryptedKeyPwdBuf, encryptedKeyIV},
+ encryptedKeyId);
+ }
TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
sIn.Serialize(inMemory);
RawBuffer TrustZoneContext::exportWrappedKey(const RawBuffer &wrappingKeyId,
const Pwd &wrappingKeyPwd,
tz_algo_type algo,
+ tz_hash_type oaepHash,
const RawBuffer &iv,
const uint32_t ctrLenOrTagSizeBits,
const RawBuffer &aad,
// command ID = CMD_EXPORT_WRAPPED_KEY
LogDebug("TrustZoneContext::exportWrappedKey");
- auto sIn = makeSerializer(wrappingKeyId,
- wrappingKeyPwd,
- algo,
- iv,
- ctrLenOrTagSizeBits,
- aad,
- keyToWrapId,
- keyToWrapPwd,
- keyToWrapType);
+ TZSerializer sIn;
+ if (algo == ALGO_RSA) {
+ sIn = makeSerializer(wrappingKeyId,
+ wrappingKeyPwd,
+ algo,
+ oaepHash,
+ keyToWrapId,
+ keyToWrapPwd,
+ keyToWrapType);
+ } else {
+ sIn = makeSerializer(wrappingKeyId,
+ wrappingKeyPwd,
+ algo,
+ iv,
+ ctrLenOrTagSizeBits,
+ aad,
+ keyToWrapId,
+ keyToWrapPwd,
+ keyToWrapType);
+ }
TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
sIn.Serialize(inMemory);
void importWrappedKey(const RawBuffer &wrappingKeyId,
const Pwd &wrappingKeyPwd,
tz_algo_type algo,
+ tz_hash_type oaepHash,
const RawBuffer &iv,
const uint32_t ctrLenOrTagSizeBits,
const RawBuffer &aad,
RawBuffer exportWrappedKey(const RawBuffer &wrappingKeyId,
const Pwd &wrappingKeyPwd,
tz_algo_type algo,
+ tz_hash_type oaepHash,
const RawBuffer &iv,
const uint32_t ctrLenOrTagSizeBits,
const RawBuffer &aad,
void executeCrypt(tz_command cmd,
tz_algo_type algo,
+ tz_hash_type hash,
const RawBuffer &keyId,
const Pwd &pwd,
const RawBuffer &iv,
GObjUPtr secret;
};
+size_t oaepMaxSize(size_t key_bits, HashAlgorithm hash)
+{
+ switch (hash) {
+ case HashAlgorithm::SHA1: return key_bits / 8 - 42;
+ case HashAlgorithm::SHA256: return key_bits / 8 - 66;
+ case HashAlgorithm::SHA384: return key_bits / 8 - 98;
+ case HashAlgorithm::SHA512: return key_bits / 8 - 130;
+ default: BOOST_FAIL("Unsupported OAEP hash"); return 0;
+ }
+}
+
} // namespace
BOOST_AUTO_TEST_SUITE(SW_TEST)
POSITIVE_TEST_CASE(asymmetricEncryptDecrypt)
{
- constexpr int KEY_BIT_LEN = 1024;
+ constexpr int KEY_BIT_LEN = 2048;
auto& rsaKeys = generateObjUPtrPair(AlgoType::RSA_GEN, KEY_BIT_LEN);
CryptoAlgorithm enc;
BOOST_REQUIRE(decrypted == input);
};
- encryptDecrypt(createRandom(KEY_BIT_LEN / 8 - 42));
- encryptDecrypt(createRandom(KEY_BIT_LEN / 8 - 42 - 1));
+ encryptDecrypt(createRandom(oaepMaxSize(KEY_BIT_LEN, HashAlgorithm::SHA1)));
+ encryptDecrypt(createRandom(oaepMaxSize(KEY_BIT_LEN, HashAlgorithm::SHA1) - 1));
encryptDecrypt(RawBuffer());
+
+ enc.setParam(ParamName::ED_OAEP_HASH, HashAlgorithm::SHA1);
+ encryptDecrypt(createRandom(oaepMaxSize(KEY_BIT_LEN, HashAlgorithm::SHA1)));
+ enc.setParam(ParamName::ED_OAEP_HASH, HashAlgorithm::SHA256);
+ encryptDecrypt(createRandom(oaepMaxSize(KEY_BIT_LEN, HashAlgorithm::SHA256)));
}
NEGATIVE_TEST_CASE(asymmetricEncryptDecrypt)
constexpr int KEY_BIT_LEN = 1024;
auto& rsaKeys = generateObjUPtrPair(AlgoType::RSA_GEN, KEY_BIT_LEN);
auto& dsaKeys = generateObjUPtrPair(AlgoType::DSA_GEN, KEY_BIT_LEN);
- const auto data = createRandom(KEY_BIT_LEN / 8 - 42);
+ const auto data = createRandom(oaepMaxSize(KEY_BIT_LEN, HashAlgorithm::SHA1));
auto longData = data;
longData.push_back(0);
enc4.setParam(ParamName::ED_LABEL, RawBuffer(64));
BOOST_REQUIRE_THROW(rsaKeys.pub->encrypt(enc4, data), Exc::Crypto::InputParam);
+ CryptoAlgorithm enc5;
+ enc5.setParam(ParamName::ALGO_TYPE, AlgoType::RSA_OAEP);
+ enc5.setParam(ParamName::ED_OAEP_HASH, HashAlgorithm::NONE);
+ BOOST_REQUIRE_THROW(rsaKeys.pub->encrypt(enc5, data), Exc::Crypto::InputParam);
+ enc5.setParam(ParamName::ED_OAEP_HASH, static_cast<HashAlgorithm>(-1));
+ BOOST_REQUIRE_THROW(rsaKeys.pub->encrypt(enc5, data), Exc::Crypto::InputParam);
+
RawBuffer encrypted;
BOOST_REQUIRE_NO_THROW(encrypted = rsaKeys.pub->encrypt(enc, data));
RawBuffer shortEncrypted = encrypted;