#include <openssl/err.h>
#include <openssl/x509v3.h>
#include <openssl/obj_mac.h>
+#include <openssl/kdf.h>
#include <ckm/ckm-error.h>
#include <key-impl.h>
#include <generic-backend/crypto-params.h>
#include <sw-backend/internals.h>
#include <sw-backend/crypto.h>
-
#include <openssl-error-handler.h>
+#include "kbkdf.h"
#define OPENSSL_SUCCESS 1 // DO NOT CHANGE THIS VALUE
#define OPENSSL_FAIL 0 // DO NOT CHANGE THIS VALUE
true,
DefaultValidator<RawBuffer>> EcdhPubKeyCheck;
+typedef ParamCheck<ParamName::ALGO_TYPE,
+ AlgoType,
+ true,
+ Type<AlgoType>::Equals<AlgoType::KBKDF>> IsKbkdf;
+
+typedef ParamCheck<ParamName::KDF_PRF,
+ KdfPrf,
+ true,
+ Type<KdfPrf>::Equals<KdfPrf::HMAC_SHA256,
+ KdfPrf::HMAC_SHA384,
+ KdfPrf::HMAC_SHA512>> KdfPrfCheck;
+
+typedef ParamCheck<ParamName::KBKDF_MODE,
+ KbkdfMode,
+ true,
+ Type<KbkdfMode>::Equals<KbkdfMode::COUNTER>> KbkdfModeCheck;
+
+typedef ParamCheck<ParamName::KDF_LEN,
+ int,
+ true,
+ Type<int>::Equals<16, 24, 32>> KdfLenCheck;
+
+typedef ParamCheck<ParamName::KBKDF_COUNTER_LOCATION,
+ KbkdfCounterLocation,
+ true,
+ Type<KbkdfCounterLocation>::Equals<KbkdfCounterLocation::BEFORE_FIXED,
+ KbkdfCounterLocation::AFTER_FIXED,
+ KbkdfCounterLocation::MIDDLE_FIXED>> KbkdfCounterLocationCheck;
+
+typedef ParamCheck<ParamName::KBKDF_RLEN,
+ int,
+ false,
+ Type<int>::Equals<8, 16, 24, 32>> KbkdfRlenCheck;
+
+typedef ParamCheck<ParamName::KBKDF_LLEN,
+ int,
+ false,
+ Type<int>::Equals<0, 8, 16, 24, 32>> KbkdfLlenCheck;
+
+
typedef std::map<AlgoType, ValidatorVector> ValidatorMap;
ValidatorMap initValidators()
{
validators.emplace(AlgoType::AES_GCM, VBuilder<GcmIvCheck, GcmTagCheck>::Build());
validators.emplace(AlgoType::RSA_OAEP, VBuilder<RsaLabelCheck>::Build());
validators.emplace(AlgoType::ECDH, VBuilder<EcdhPubKeyCheck>::Build());
+ validators.emplace(AlgoType::KBKDF, VBuilder<KdfPrfCheck,
+ KbkdfModeCheck,
+ KdfLenCheck,
+ KbkdfCounterLocationCheck,
+ KbkdfRlenCheck,
+ KbkdfLlenCheck>::Build());
return validators;
};
return { DataType::BINARY_DATA, std::move(secret)};
}
+Data deriveKBKDF(const RawBuffer &secret, const CryptoAlgorithm &alg)
+{
+ validateParams<IsKbkdf>(alg);
+
+ RawBuffer label, context, fixed;
+ KbkdfCounterLocation counterLocation;
+ KdfPrf prf;
+ size_t length, rlenBits = 32, llenBits = 0, tmp;
+ bool hasLabel = alg.getParam(ParamName::KBKDF_LABEL, label);
+ bool hasContext = alg.getParam(ParamName::KBKDF_CONTEXT, context);
+ bool hasFixed = alg.getParam(ParamName::KBKDF_FIXED_INPUT, fixed);
+ alg.getParam(ParamName::KBKDF_COUNTER_LOCATION, counterLocation);
+ alg.getParam(ParamName::KDF_PRF, prf);
+ alg.getParam(ParamName::KDF_LEN, length);
+ alg.getParam(ParamName::KBKDF_RLEN, rlenBits);
+ alg.getParam(ParamName::KBKDF_LLEN, llenBits);
+ bool useSeparator = !alg.getParam(ParamName::KBKDF_NO_SEPARATOR, tmp);
+
+ const EVP_MD* md = nullptr;
+ switch (prf) {
+ case KdfPrf::HMAC_SHA256:
+ md = EVP_sha256();
+ break;
+ case KdfPrf::HMAC_SHA384:
+ md = EVP_sha384();
+ break;
+ case KdfPrf::HMAC_SHA512:
+ md = EVP_sha512();
+ break;
+ default:
+ assert(false); // prf is checked in validateParams above
+ }
+
+ RawBuffer key;
+ if (hasFixed) {
+ if (hasLabel || hasContext || !useSeparator || llenBits > 0 ||
+ counterLocation == KbkdfCounterLocation::MIDDLE_FIXED)
+ ThrowErr(Exc::Crypto::InputParam, "Unexpected parameters for fixed input mode.");
+
+ key = deriveKbkdfHmac(secret, length * 8, md, counterLocation, rlenBits, fixed);
+ } else {
+ if (!hasLabel || !hasContext)
+ ThrowErr(Exc::Crypto::InputParam, "Missing label and/or context.");
+
+ key = deriveKbkdfHmac(secret,
+ length * 8,
+ md,
+ counterLocation,
+ rlenBits,
+ llenBits,
+ label,
+ context,
+ useSeparator);
+ }
+
+ return { DataType::KEY_AES, std::move(key)};
+}
+
} // namespace Internals
} // namespace SW
} // namespace Crypto
#include <utility>
#include <memory>
#include <exception>
+#include <optional>
#include <boost_macros_wrapper.h>
#include <test_common.h>
using Cert::getEvpShPtr;
};
+const std::optional<RawBuffer> NO_BUF;
+const std::optional<size_t> NO_SIZE;
+const std::optional<KdfPrf> NO_PRF;
+const std::optional<KbkdfMode> NO_MODE;
+const std::optional<KbkdfCounterLocation> NO_LOC;
+
+constexpr KdfPrf HMAC256 = KdfPrf::HMAC_SHA256;
+constexpr KdfPrf HMAC384 = KdfPrf::HMAC_SHA384;
+constexpr KdfPrf HMAC512 = KdfPrf::HMAC_SHA512;
+constexpr KbkdfCounterLocation BEFORE = KbkdfCounterLocation::BEFORE_FIXED;
+constexpr KbkdfCounterLocation AFTER = KbkdfCounterLocation::AFTER_FIXED;
+constexpr KbkdfCounterLocation MIDDLE = KbkdfCounterLocation::MIDDLE_FIXED;
+constexpr KbkdfMode COUNTER = KbkdfMode::COUNTER;
+
+const RawBuffer CTX{'c','o','n','t','e','x','t'};
+const RawBuffer LAB{'l','a','b','e','l'};
+const RawBuffer FIX{'f','i','x','e','d'};
+const RawBuffer ONE(1);
+const RawBuffer EMPTY;
+
+class KbkdfParamTester {
+public:
+ KbkdfParamTester() {
+ Token token;
+ BOOST_REQUIRE_NO_THROW(token = STORE.import(Data(DataType::BINARY_DATA, RawBuffer(16)),
+ "",
+ EncryptionParams(),
+ RawBuffer()));
+
+ BOOST_REQUIRE_NO_THROW(secret = STORE.getObject(token, ""));
+ }
+
+ void Ok(const std::optional<size_t>& len,
+ const std::optional<KdfPrf>& prf,
+ const std::optional<KbkdfMode>& mode,
+ const std::optional<KbkdfCounterLocation>& location,
+ const std::optional<RawBuffer>& context,
+ const std::optional<RawBuffer>& label,
+ const std::optional<RawBuffer>& fixed,
+ const std::optional<size_t>& rlen,
+ const std::optional<size_t>& llen,
+ bool noSeparator = false)
+ {
+ return Test(true, len, prf, mode, location, context, label, fixed, rlen, llen, noSeparator);
+ }
+
+ void Fail(const std::optional<size_t>& len,
+ const std::optional<KdfPrf>& prf,
+ const std::optional<KbkdfMode>& mode,
+ const std::optional<KbkdfCounterLocation>& location,
+ const std::optional<RawBuffer>& context,
+ const std::optional<RawBuffer>& label,
+ const std::optional<RawBuffer>& fixed,
+ const std::optional<size_t>& rlen,
+ const std::optional<size_t>& llen,
+ bool noSeparator = false)
+ {
+ return Test(
+ false, len, prf, mode, location, context, label, fixed, rlen, llen, noSeparator);
+ }
+private:
+ void Test(bool ok,
+ const std::optional<size_t>& len,
+ const std::optional<KdfPrf>& prf,
+ const std::optional<KbkdfMode>& mode,
+ const std::optional<KbkdfCounterLocation>& location,
+ const std::optional<RawBuffer>& context,
+ const std::optional<RawBuffer>& label,
+ const std::optional<RawBuffer>& fixed,
+ const std::optional<size_t>& rlen,
+ const std::optional<size_t>& llen,
+ bool noSeparator = false)
+ {
+ CryptoAlgorithm derive;
+ derive.setParam(ParamName::ALGO_TYPE, AlgoType::KBKDF);
+ if (len)
+ derive.setParam(ParamName::KDF_LEN, *len);
+ if (prf)
+ derive.setParam(ParamName::KDF_PRF, *prf);
+ if (mode)
+ derive.setParam(ParamName::KBKDF_MODE, *mode);
+ if (location)
+ derive.setParam(ParamName::KBKDF_COUNTER_LOCATION, *location);
+ if (context)
+ derive.setParam(ParamName::KBKDF_CONTEXT, *context);
+ if (label)
+ derive.setParam(ParamName::KBKDF_LABEL, *label);
+ if (fixed)
+ derive.setParam(ParamName::KBKDF_FIXED_INPUT, *fixed);
+ if (rlen)
+ derive.setParam(ParamName::KBKDF_RLEN, *rlen);
+ if (llen)
+ derive.setParam(ParamName::KBKDF_LLEN, *llen);
+ if (noSeparator)
+ derive.setParam(ParamName::KBKDF_NO_SEPARATOR, 1);
+
+ GObjUPtr key;
+ if (ok) {
+ Token derived;
+ BOOST_REQUIRE_NO_THROW(derived = secret->derive(derive, "", RawBuffer()));
+
+ BOOST_REQUIRE(derived.backendId == CryptoBackend::OpenSSL);
+ BOOST_REQUIRE(derived.dataType == DataType::KEY_AES);
+
+ BOOST_REQUIRE_NO_THROW(key = STORE.getObject(derived, ""));
+
+ BOOST_REQUIRE(key->getBinary().size() == *len);
+ } else {
+ BOOST_REQUIRE_THROW(secret->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+ }
+ }
+
+ GObjUPtr secret;
+};
+
} // namespace
BOOST_AUTO_TEST_SUITE(SW_TEST)
BOOST_REQUIRE_THROW(rsaPrivate->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
}
+POSITIVE_TEST_CASE(deriveKBKDFHMAC)
+{
+ KbkdfParamTester test;
+
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+
+ test.Ok(16, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Ok(24, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+
+ test.Ok(32, HMAC384, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Ok(32, HMAC512, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+
+ test.Ok(32, HMAC256, COUNTER, AFTER, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, MIDDLE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+
+ test.Ok(32, HMAC256, COUNTER, BEFORE, ONE, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, EMPTY, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, ONE, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, EMPTY, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, EMPTY, EMPTY, NO_BUF, NO_SIZE, NO_SIZE);
+
+ test.Ok(32, HMAC256, COUNTER, BEFORE, NO_BUF, NO_BUF, FIX, NO_SIZE, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, AFTER, NO_BUF, NO_BUF, FIX, NO_SIZE, NO_SIZE);
+
+ test.Ok(32, HMAC256, COUNTER, BEFORE, NO_BUF, NO_BUF, ONE, NO_SIZE, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, NO_BUF, NO_BUF, EMPTY, NO_SIZE, NO_SIZE);
+
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, 32, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, 24, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, 16, NO_SIZE);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, 8, NO_SIZE);
+
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, 32);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, 24);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, 16);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, 8);
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, 0);
+
+ test.Ok(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE, true);
+ test.Ok(32, HMAC256, COUNTER, MIDDLE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE, true);
+}
+
+NEGATIVE_TEST_CASE(deriveKBKDFHMACwrongAlgo)
+{
+ Token token;
+ BOOST_REQUIRE_NO_THROW(token = STORE.import(Data(DataType::BINARY_DATA, RawBuffer(16)),
+ "",
+ EncryptionParams(),
+ RawBuffer()));
+
+ GObjUPtr secret;
+ BOOST_REQUIRE_NO_THROW(secret = STORE.getObject(token, ""));
+
+ CryptoAlgorithm derive;
+
+ // no algorithm
+ BOOST_REQUIRE_THROW(secret->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+
+ // wrong algorithm
+ derive.setParam(ParamName::ALGO_TYPE, AlgoType::ECDH);
+ BOOST_REQUIRE_THROW(secret->derive(derive, "", RawBuffer()), Exc::Crypto::InputParam);
+}
+
+NEGATIVE_TEST_CASE(deriveKBKDFHMACwrongParams)
+{
+ KbkdfParamTester test;
+
+ // missing parameters
+ test.Fail(NO_SIZE, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(32, NO_PRF, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, NO_MODE, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, NO_LOC, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, NO_BUF, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, NO_BUF, NO_BUF, NO_SIZE, NO_SIZE);
+
+ // conflicting parameters
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, LAB, FIX, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, NO_BUF, LAB, FIX, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, NO_BUF, FIX, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, MIDDLE, NO_BUF, NO_BUF, FIX, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, MIDDLE, NO_BUF, NO_BUF, FIX, NO_SIZE, 32);
+ test.Fail(32, HMAC256, COUNTER, MIDDLE, NO_BUF, NO_BUF, FIX, NO_SIZE, 0);
+ test.Fail(32, HMAC256, COUNTER, MIDDLE, NO_BUF, NO_BUF, FIX, NO_SIZE, NO_SIZE, true);
+
+ // invalid values
+ test.Fail(0, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(1, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(8, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(64, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+
+ test.Fail(32, static_cast<KdfPrf>(0), COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(32, static_cast<KdfPrf>(4), COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+
+ test.Fail(32, HMAC256, static_cast<KbkdfMode>(0), BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, static_cast<KbkdfMode>(2), BEFORE, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+
+ auto wrongLocation1 = static_cast<KbkdfCounterLocation>(0);
+ auto wrongLocation2 = static_cast<KbkdfCounterLocation>(4);
+ test.Fail(32, HMAC256, COUNTER, wrongLocation1, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, wrongLocation2, CTX, LAB, NO_BUF, NO_SIZE, NO_SIZE);
+
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, 0, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, 1, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, 7, NO_SIZE);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, 64, NO_SIZE);
+
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, 1);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, 7);
+ test.Fail(32, HMAC256, COUNTER, BEFORE, CTX, LAB, NO_BUF, NO_SIZE, 64);
+}
+
BOOST_AUTO_TEST_SUITE_END()