#include <utils.h>
#include <openssl/evp.h>
#include <openssl/dsa.h>
+#include <openssl/ec.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <tz-backend/tz-context.h>
#include <openssl-error-handler.h>
#include <km_ta_defines.h>
+#include <key-impl.h>
#include <functional>
signature);
}
+void deriveECDH(const RawBuffer &prvKey,
+ const Pwd &prvKeyPwd,
+ const RawBuffer &pubKey,
+ const Password &secretPwd,
+ const RawBuffer &secretPwdIV,
+ RawBuffer &secretTag,
+ const RawBuffer &secretHash)
+{
+ auto peerKey = std::make_shared<KeyImpl>(pubKey);
+ 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 subType = EVP_PKEY_type(EVP_PKEY_id(peerEvp));
+ if (subType != EVP_PKEY_EC)
+ ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", subType);
+
+ auto ecKey = EVP_PKEY_get0_EC_KEY(peerEvp);
+ if (!ecKey)
+ ThrowErr(Exc::Crypto::InternalError, "Can't get EC key");
+
+ auto ecPoint = EC_KEY_get0_public_key(ecKey);
+ if (!ecPoint)
+ ThrowErr(Exc::Crypto::InternalError, "Can't get EC public key");
+
+ auto ecGroup = EC_KEY_get0_group(ecKey);
+ if (!ecGroup)
+ ThrowErr(Exc::Crypto::InternalError, "Can't get EC group");
+
+ BIGNUM *x = BN_new();
+ BIGNUM *y = BN_new();
+ if (!EC_POINT_get_affine_coordinates(ecGroup, ecPoint, x, y, NULL))
+ ThrowErr(Exc::Crypto::InternalError, "Failed to get EC pub key coordinates");
+
+ auto xBuf = extractBignumData(x);
+ auto yBuf = extractBignumData(y);
+
+ RawBuffer secretPwdBuf(secretPwd.begin(), secretPwd.end());
+
+ TrustZoneContext::Instance().executeEcdh(prvKey,
+ prvKeyPwd,
+ xBuf,
+ yBuf,
+ secretPwdBuf,
+ secretPwdIV,
+ secretTag,
+ secretHash);
+}
+
+void deriveKBKDF(const RawBuffer &secret,
+ const CryptoAlgorithm &alg,
+ const Password &keyPwd,
+ const RawBuffer &keyPwdIV,
+ RawBuffer &keyTag,
+ const RawBuffer &keyHash)
+{
+ auto prf = unpack<KdfPrf>(alg, ParamName::KDF_PRF);
+ auto mode = unpack<KbkdfMode>(alg, ParamName::KBKDF_MODE);
+ auto location = unpack<KbkdfCounterLocation>(alg, ParamName::KBKDF_COUNTER_LOCATION);
+
+ size_t rlen = 32, llen = 32, dummy;
+ alg.getParam(ParamName::KBKDF_RLEN, rlen);
+ alg.getParam(ParamName::KBKDF_LLEN, llen);
+ bool noSeparator = alg.getParam(ParamName::KBKDF_NO_SEPARATOR, dummy);
+
+ RawBuffer keyPwdBuf(keyPwd.begin(), keyPwd.end());
+
+ TrustZoneContext::Instance().executeKbkdf(secret,
+ prf,
+ mode,
+ location,
+ rlen,
+ llen,
+ noSeparator,
+ keyPwdBuf,
+ keyPwdIV,
+ keyTag,
+ keyHash);
+}
+
+
} // namespace Internals
} // namespace TZ
} // namespace Crypto
const RawBuffer &message,
const RawBuffer &signature);
+void deriveECDH(const RawBuffer &prvKey,
+ const Pwd &prvKeyPwd,
+ const RawBuffer &pubKey,
+ const Password &secretPwd,
+ const RawBuffer &secretPwdIV,
+ RawBuffer &secretTag,
+ const RawBuffer &secretHash);
+
+void deriveKBKDF(const RawBuffer &secret,
+ const CryptoAlgorithm &alg,
+ const Password &keyPwd,
+ const RawBuffer &keyPwdIV,
+ RawBuffer &keyTag,
+ const RawBuffer &keyHash);
} // namespace Internals
} // namespace TZ
} // namespace Crypto
* @version 1.0
*/
#include <generic-backend/exception.h>
+#include <generic-backend/algo-validation.h>
#include <tz-backend/obj.h>
+#include <tz-backend/store.h>
#include <tz-backend/internals.h>
namespace CKM {
}
} // namespace anonymous
+Token BData::derive(const CryptoAlgorithm &alg, const Password &pass, const RawBuffer &hash)
+{
+ auto algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+ if (algo != AlgoType::KBKDF)
+ ThrowErr(Exc::Crypto::InputParam, "Wrong algorithm");
+
+ RawBuffer iv;
+ RawBuffer tag;
+ if (!pass.empty()) {
+ // IV is needed for key encryption
+ iv = Internals::generateIV();
+ }
+
+ Internals::deriveKBKDF(getBinary(), alg, pass, iv, tag, hash);
+
+ return Token(backendId(), DataType(KeyType::KEY_AES), Store::pack(hash, pass, iv, tag));
+}
+
RawBuffer SKey::encrypt(const CryptoAlgorithm &alg, const RawBuffer &data)
{
return Internals::symmetricEncrypt(getBinary(), getPassword(), alg, data);
return Internals::asymmetricDecrypt(getBinary(), getPassword(), alg, cipher);
}
+Token AKey::derive(const CryptoAlgorithm &alg, const Password &pass, const RawBuffer &hash)
+{
+ if (m_type != DataType::KEY_ECDSA_PRIVATE)
+ ThrowErr(Exc::Crypto::InputParam, "ECDH requires EC private key");
+
+ auto algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+ if (algo != AlgoType::ECDH)
+ ThrowErr(Exc::Crypto::InputParam, "Wrong algorithm");
+
+ auto pubKey = unpack<RawBuffer>(alg, ParamName::ECDH_PUBKEY);
+
+ RawBuffer iv;
+ RawBuffer tag;
+ if (!pass.empty()) {
+ // IV is needed for key encryption
+ iv = Internals::generateIV();
+ }
+
+ Internals::deriveECDH(getBinary(), getPassword(), pubKey, pass, iv, tag, hash);
+
+ return Token(backendId(), DataType::BINARY_DATA, Store::pack(hash, pass, iv, tag));
+}
+
RawBuffer AKey::sign(
const CryptoAlgorithm &alg,
const RawBuffer &message)
{
return m_raw;
}
+ Token derive(const CryptoAlgorithm &, const Password &, const RawBuffer &) override;
protected:
RawBuffer m_raw;
const RawBuffer &sign) override;
RawBuffer encrypt(const CryptoAlgorithm &, const RawBuffer &) override;
RawBuffer decrypt(const CryptoAlgorithm &, const RawBuffer &) override;
+ Token derive(const CryptoAlgorithm &, const Password &, const RawBuffer &) override;
};
class Cert : public AKey {
return data;
}
-RawBuffer pack(const RawBuffer &keyId, const Password &pwd,
- const RawBuffer &iv, const RawBuffer &tag)
-{
- // determine whether the key is password protected and store schema info
- // we don't need to additionally encrypt key ID
- int scheme = pwd.empty() ? EncryptionScheme::NONE : EncryptionScheme::PASSWORD;
-
- if (scheme == EncryptionScheme::PASSWORD) {
- return SerializeMessage(scheme, keyId, iv, tag);
- } else {
- return SerializeMessage(scheme, keyId);
- }
-}
-
} // namespace
Store::Store(CryptoBackend backendId) :
Internals::destroyKey(id);
}
+RawBuffer Store::pack(const RawBuffer &keyId,
+ const Password &pwd,
+ const RawBuffer &iv,
+ const RawBuffer &tag)
+{
+ // determine whether the key is password protected and store schema info
+ // we don't need to additionally encrypt key ID
+ int scheme = pwd.empty() ? EncryptionScheme::NONE : EncryptionScheme::PASSWORD;
+
+ if (scheme == EncryptionScheme::PASSWORD) {
+ return SerializeMessage(scheme, keyId, iv, tag);
+ } else {
+ return SerializeMessage(scheme, keyId);
+ }
+}
+
} // namespace TZ
} // namespace Crypto
} // namespace CKM
const RawBuffer &);
virtual void destroy(const Token &);
+ static RawBuffer pack(const RawBuffer &keyId,
+ const Password &pwd,
+ const RawBuffer &iv,
+ const RawBuffer &tag);
+
// TODO device key ID is needed here to support importEncrypted
};
Execute(CMD_DESTROY_DATA, &op);
}
+TZSerializablePwdData* makeSerializablePwd(const Pwd &pwd)
+{
+ auto &tag = pwd.getTag();
+ return new TZSerializablePwdData(pwd.getPassword(), pwd.getIV(), tag.size() * 8, tag);
+}
+
+void TrustZoneContext::executeEcdh(const RawBuffer &prvKeyId,
+ const Pwd &prvKeyPwd,
+ const RawBuffer &pubX,
+ const RawBuffer &pubY,
+ const RawBuffer &secretPwdBuf,
+ const RawBuffer &secretPwdIV,
+ RawBuffer &secretTag,
+ const RawBuffer &secretHash)
+{
+ // command ID = CMD_DERIVE
+ LogDebug("TrustZoneContext::executeEcdh");
+
+ auto sIn = makeSerializer(
+ prvKeyId, prvKeyPwd, pubX, pubY, EncPwd{secretPwdBuf, secretPwdIV}, secretHash);
+ TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
+ sIn.Serialize(inMemory);
+
+ TZSerializer sOut;
+ if (!secretPwdBuf.empty()) {
+ sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+ }
+
+ TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
+
+ TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
+ if (!secretPwdBuf.empty())
+ op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
+ op.params[0].value.a = ALGO_ECDH_DRV;
+
+ Execute(CMD_DERIVE, &op);
+
+ if (!secretPwdBuf.empty()) {
+ sOut.Deserialize(outMemory);
+ sOut.Pull(secretTag);
+ }
+
+ LogDebug("Derived object ID is (hex): " << rawToHexString(secretHash));
+}
+
+void TrustZoneContext::executeKbkdf(const RawBuffer& secret,
+ KdfPrf prf,
+ KbkdfMode mode,
+ KbkdfCounterLocation location,
+ size_t rlen,
+ size_t llen,
+ bool noSeparator,
+ const RawBuffer &keyPwdBuf,
+ const RawBuffer &keyPwdIV,
+ RawBuffer &keyTag,
+ const RawBuffer &keyHash)
+{
+ // command ID = CMD_DERIVE
+ LogDebug("TrustZoneContext::executeKbkdf");
+
+ auto sIn = makeSerializer(
+ secret, prf, mode, location, rlen, llen, noSeparator, EncPwd{keyPwdBuf, keyPwdIV}, keyHash);
+ TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT);
+ sIn.Serialize(inMemory);
+
+ TZSerializer sOut;
+ if (!keyPwdBuf.empty()) {
+ sOut.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+ }
+
+ TrustZoneMemory outMemory(m_Context, sOut.GetSize(), TEEC_MEM_OUTPUT);
+
+ TEEC_Operation op = makeOp(TEEC_VALUE_INOUT, inMemory);
+ if (!keyPwdBuf.empty())
+ op = makeOp(TEEC_VALUE_INOUT, inMemory, outMemory);
+ op.params[0].value.a = ALGO_KBKDF_DRV;
+
+ Execute(CMD_DERIVE, &op);
+
+ if (!keyPwdBuf.empty()) {
+ sOut.Deserialize(outMemory);
+ sOut.Pull(keyTag);
+ }
+
+ LogDebug("Derived object ID is (hex): " << rawToHexString(keyHash));
+}
+
void TrustZoneContext::Initialize()
{
TEEC_Operation op;
void destroyData(const RawBuffer &dataId);
+ void executeEcdh(const RawBuffer &prvKeyId,
+ const Pwd &prvKeyPwd,
+ const RawBuffer &pubX,
+ const RawBuffer &pubY,
+ const RawBuffer &secretPwdBuf,
+ const RawBuffer &secretPwdIV,
+ RawBuffer &secretTag,
+ const RawBuffer &secretHash);
+
+ void executeKbkdf(const RawBuffer& secret,
+ KdfPrf prf,
+ KbkdfMode mode,
+ KbkdfCounterLocation location,
+ size_t rlen,
+ size_t llen,
+ bool noSeparator,
+ const RawBuffer &keyPwdBuf,
+ const RawBuffer &keyPwdIV,
+ RawBuffer &keyTag,
+ const RawBuffer &keyHash);
+
private:
TrustZoneContext();
~TrustZoneContext();