#include <openssl/obj_mac.h>
#include <ckm/ckm-error.h>
+#include <key-impl.h>
#include <dpl/log/log.h>
#include <utils.h>
ElipticCurve::prime256v1,
ElipticCurve::secp384r1>> EcdsaEcCheck;
+// key derivation
+typedef ParamCheck<ParamName::ALGO_TYPE,
+ AlgoType,
+ true,
+ Type<AlgoType>::Equals<AlgoType::ECDH>> IsEcdh;
+
+typedef ParamCheck<ParamName::ECDH_PUBKEY,
+ RawBuffer,
+ true,
+ DefaultValidator<RawBuffer>> EcdhPubKeyCheck;
+
typedef std::map<AlgoType, ValidatorVector> ValidatorMap;
ValidatorMap initValidators()
{
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::ECDH, VBuilder<EcdhPubKeyCheck>::Build());
return validators;
};
aad);
}
+EC_KEY* getEcKey(EVP_PKEY* evpKey)
+{
+ int subType = EVP_PKEY_type(EVP_PKEY_id(evpKey));
+ if (subType != EVP_PKEY_EC)
+ ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", subType);
+
+ EC_KEY *ecKey = EVP_PKEY_get0_EC_KEY(evpKey);
+ if (!ecKey)
+ ThrowErr(Exc::Crypto::InternalError, "Can't get EC key");
+
+ return ecKey;
+}
+
+int getCurve(const EC_KEY* ecKey)
+{
+ return EC_GROUP_get_curve_name(EC_KEY_get0_group(ecKey));
+}
+
} // namespace
return digestVerifyMessage(pkey, message, signature, md_algo, rsa_padding);
}
+Data deriveECDH(const EvpShPtr &pkey, const CryptoAlgorithm &alg)
+{
+ validateParams<IsEcdh>(alg);
+
+ EC_KEY *ecKey = getEcKey(pkey.get());
+
+ // get private key curve name
+ int prvCurve = getCurve(ecKey);
+
+ auto prv = EC_KEY_get0_private_key(ecKey);
+ if (!prv)
+ ThrowErr(Exc::Crypto::InputParam, "ECDH requires own private EC key");
+
+ // Create the context for the shared secret derivation
+ auto ctx = newCtx(pkey.get());
+ if (ctx == nullptr)
+ ThrowErr(Exc::Crypto::InternalError, "Key context creation failed");
+
+ // import peer's public key from buffer
+ RawBuffer pubKeyBuffer;
+ [[maybe_unused]] bool hasPubKey = alg.getParam(ParamName::ECDH_PUBKEY, pubKeyBuffer);
+ assert(hasPubKey);
+ auto peerKey = std::make_shared<KeyImpl>(pubKeyBuffer);
+ if (peerKey->getType() != KeyType::KEY_ECDSA_PUBLIC)
+ ThrowErr(Exc::Crypto::InputParam, "ECDH requires peer's public EC key");
+ auto peerEvp = peerKey->getEvpShPtr().get();
+ assert(peerEvp);
+
+ int pubCurve = getCurve(getEcKey(peerEvp));
+
+ if (pubCurve != prvCurve)
+ ThrowErr(Exc::Crypto::InputParam, "Private and public key use different ECs");
+
+ // initialise
+ if (1 != EVP_PKEY_derive_init(ctx.get()))
+ ThrowErr(Exc::Crypto::InternalError, "EVP_PKEY_derive_init failed");
+
+ // provide the peer public key
+ if (1 != EVP_PKEY_derive_set_peer(ctx.get(), peerEvp))
+ ThrowErr(Exc::Crypto::InternalError, "EVP_PKEY_derive_set_peer failed");
+
+ // determine buffer length for shared secret
+ size_t secretLen;
+ if(1 != EVP_PKEY_derive(ctx.get(), nullptr, &secretLen))
+ ThrowErr(Exc::Crypto::InternalError, "Failed to determine ECDH secret length");
+
+ RawBuffer secret(secretLen);
+
+ // derive the shared secret
+ if (1 != (EVP_PKEY_derive(ctx.get(), secret.data(), &secretLen)))
+ ThrowErr(Exc::Crypto::InternalError, "ECDH failed");
+
+ // Never use a derived secret directly. Typically it is passed
+ // through some hash function to produce a key
+ return { DataType::BINARY_DATA, std::move(secret)};
+}
+
} // namespace Internals
} // namespace SW
} // namespace Crypto
const RawBuffer &message,
const RawBuffer &signature);
+Data deriveECDH(const EvpShPtr &pkey, const CryptoAlgorithm &alg);
+
} // namespace Internals
} // namespace SW
} // namespace Crypto
#include <generic-backend/exception.h>
#include <sw-backend/obj.h>
+#include <sw-backend/store.h>
#include <sw-backend/internals.h>
namespace CKM {
return Internals::asymmetricDecrypt(getEvpShPtr(), alg, data);
}
-Token AKey::derive(const CryptoAlgorithm &, const Password &, const RawBuffer &)
+Token AKey::derive(const CryptoAlgorithm &alg, const Password &pass, const RawBuffer & /* digest */)
{
- return Token();
+ auto data = Internals::deriveECDH(getEvpShPtr(), alg);
+
+ return Token(backendId(), data.type, Store::pack(data.buffer, pass));
}
EvpShPtr AKey::getEvpShPtr()
BOOST_REQUIRE_THROW(cert.getEvpShPtr(), Exc::Crypto::InternalError);
}
+POSITIVE_TEST_CASE(deriveECDH)
+{
+ CryptoAlgorithm gen;
+ gen.setParam(ParamName::ALGO_TYPE, AlgoType::ECDSA_GEN);
+ gen.setParam(ParamName::GEN_EC, ElipticCurve::prime256v1);
+
+ auto ours = STORE.generateAKey(gen, "", "", RawBuffer(), RawBuffer());
+ auto peers = STORE.generateAKey(gen, "", "", RawBuffer(), RawBuffer());
+
+ CryptoAlgorithm derive;
+ derive.setParam(ParamName::ALGO_TYPE, AlgoType::ECDH);
+
+ // our part
+ GObjUPtr peersPublic;
+ BOOST_REQUIRE_NO_THROW(peersPublic = STORE.getObject(peers.second, ""));
+ derive.setParam(ParamName::ECDH_PUBKEY, peersPublic->getBinary());
+
+ GObjUPtr oursPrivate;
+ BOOST_REQUIRE_NO_THROW(oursPrivate = STORE.getObject(ours.first, ""));
+
+ Token oursDerived;
+ BOOST_REQUIRE_NO_THROW(oursDerived = oursPrivate->derive(derive, "", RawBuffer()));
+
+ BOOST_REQUIRE(oursDerived.backendId == CryptoBackend::OpenSSL);
+ BOOST_REQUIRE(oursDerived.dataType == DataType::BINARY_DATA);
+
+ GObjUPtr oursDerivedObj;
+ BOOST_REQUIRE_NO_THROW(oursDerivedObj = STORE.getObject(oursDerived, ""));
+ BOOST_REQUIRE(!oursDerivedObj->getBinary().empty());
+
+ // peer's part
+ GObjUPtr oursPublic;
+ BOOST_REQUIRE_NO_THROW(oursPublic = STORE.getObject(ours.second, ""));
+ derive.setParam(ParamName::ECDH_PUBKEY, oursPublic->getBinary());
+
+ GObjUPtr peersPrivate;
+ BOOST_REQUIRE_NO_THROW(peersPrivate = STORE.getObject(peers.first, ""));
+
+ Token peersDerived;
+ BOOST_REQUIRE_NO_THROW(peersDerived = peersPrivate->derive(derive, "", RawBuffer()));
+
+ BOOST_REQUIRE(peersDerived.backendId == CryptoBackend::OpenSSL);
+ BOOST_REQUIRE(peersDerived.dataType == DataType::BINARY_DATA);
+
+ GObjUPtr peersDerivedObj;
+ BOOST_REQUIRE_NO_THROW(peersDerivedObj = STORE.getObject(peersDerived, ""));
+ BOOST_REQUIRE(oursDerivedObj->getBinary() == peersDerivedObj->getBinary());
+}
+
+NEGATIVE_TEST_CASE(deriveECDH)
+{
+ CryptoAlgorithm gen;
+ gen.setParam(ParamName::ALGO_TYPE, AlgoType::ECDSA_GEN);
+ gen.setParam(ParamName::GEN_EC, ElipticCurve::prime256v1);
+
+ auto ours = STORE.generateAKey(gen, "", "", RawBuffer(), RawBuffer());
+ auto peers = STORE.generateAKey(gen, "", "", RawBuffer(), RawBuffer());
+
+ GObjUPtr oursPrivate;
+ BOOST_REQUIRE_NO_THROW(oursPrivate = STORE.getObject(ours.first, ""));
+
+ CryptoAlgorithm derive;
+
+ // no algorithm
+ BOOST_REQUIRE_THROW(oursPrivate->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+
+ // wrong algorithm
+ derive.setParam(ParamName::ALGO_TYPE, AlgoType::ECDSA_GEN);
+ BOOST_REQUIRE_THROW(oursPrivate->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+
+ // no pubkey
+ derive.setParam(ParamName::ALGO_TYPE, AlgoType::ECDH);
+ BOOST_REQUIRE_THROW(oursPrivate->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+
+ // empty pubkey
+ derive.setParam(ParamName::ECDH_PUBKEY, RawBuffer());
+ BOOST_REQUIRE_THROW(oursPrivate->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+
+ // private key instead of public
+ derive.setParam(ParamName::ECDH_PUBKEY, oursPrivate->getBinary());
+ BOOST_REQUIRE_THROW(oursPrivate->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+
+ // public key instead of private key
+ GObjUPtr oursPublic;
+ BOOST_REQUIRE_NO_THROW(oursPublic = STORE.getObject(ours.second, ""));
+ derive.setParam(ParamName::ECDH_PUBKEY, oursPublic->getBinary());
+ BOOST_REQUIRE_THROW(oursPublic->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+
+ // RSA key instead of EC
+ gen.setParam(ParamName::ALGO_TYPE, AlgoType::RSA_GEN);
+ gen.setParam(ParamName::GEN_KEY_LEN, 1024);
+ auto rsa = STORE.generateAKey(gen, "", "", RawBuffer(), RawBuffer());
+ GObjUPtr rsaPrivate;
+ BOOST_REQUIRE_NO_THROW(rsaPrivate = STORE.getObject(rsa.first, ""));
+ BOOST_REQUIRE_THROW(rsaPrivate->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+}
+
BOOST_AUTO_TEST_SUITE_END()