Reference code for ECC operations.
[ Merge of http://go/wvgerrit/113750 ] This introduces two classes EccPublicKey and EccPrivateKey which perform all ECC-specific crypto operations. The main operations required by ECC are: - Load/serialize keys from/to X.509 DER formats - Generate ECC signatures - Verify ECC signatures - Derive session keys used by other OEMCrypto operations These new classes still need to be plugged into rest of the reference OEMCrypto implementation. Bug: 135283522 Test: Future CL Change-Id: Id071cad9129f95a6eb08662322154ba7d1548d40
This commit is contained in:
245
libwvdrmengine/oemcrypto/ref/src/oemcrypto_ecc_key.h
Normal file
245
libwvdrmengine/oemcrypto/ref/src/oemcrypto_ecc_key.h
Normal file
@@ -0,0 +1,245 @@
|
||||
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
//
|
||||
// Reference implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef OEMCRYPTO_ECC_KEY_H_
|
||||
#define OEMCRYPTO_ECC_KEY_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/ec.h>
|
||||
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
enum EccCurve {
|
||||
kEccCurveUnknown = 0,
|
||||
kEccSecp256r1 = 256,
|
||||
kEccSecp384r1 = 384,
|
||||
kEccSecp521r1 = 521
|
||||
};
|
||||
|
||||
// Returns the string representation of the provided curve.
|
||||
// Intended for logging purposes.
|
||||
std::string EccCurveToString(EccCurve curve);
|
||||
|
||||
class EccPrivateKey;
|
||||
|
||||
class EccPublicKey {
|
||||
public:
|
||||
// Creates a new public key equivalent of the provided private key.
|
||||
static std::unique_ptr<EccPublicKey> New(const EccPrivateKey& private_key);
|
||||
|
||||
// Loads a serialized EC public key.
|
||||
// The provided |buffer| must contain a valid ASN.1 DER encoded
|
||||
// SubjectPublicKey. Only supported curves by this API are those
|
||||
// enumerated by EccCurve.
|
||||
//
|
||||
// buffer: SubjectPublicKeyInfo = {
|
||||
// algorithm: AlgorithmIdentifier = {
|
||||
// algorithm: OID = id-ecPublicKey,
|
||||
// parameters: ECParameters = {
|
||||
// namedCurve: OID = secp256r1 | secp384r1 | secp521r1
|
||||
// }
|
||||
// },
|
||||
// subjectPublicKey: BIT STRING = ... -- SEC1 encoded ECPoint
|
||||
// }
|
||||
//
|
||||
// Failure will occur if the provided |buffer| does not contain a
|
||||
// valid SubjectPublicKey, or if the specified curve is not
|
||||
// supported.
|
||||
static std::unique_ptr<EccPublicKey> Load(const uint8_t* buffer,
|
||||
size_t length);
|
||||
static std::unique_ptr<EccPublicKey> Load(const std::string& buffer);
|
||||
static std::unique_ptr<EccPublicKey> Load(const std::vector<uint8_t>& buffer);
|
||||
|
||||
EccCurve curve() const { return curve_; }
|
||||
const EC_KEY* GetEcKey() const { return key_; }
|
||||
|
||||
// Checks if the provided |private_key| is the EC private key of this
|
||||
// public key.
|
||||
bool IsMatchingPrivateKey(const EccPrivateKey& private_key) const;
|
||||
|
||||
// Serializes the public key into an ASN.1 DER encoded SubjectPublicKey
|
||||
// representation.
|
||||
// On success, |*buffer_size| is populated with the number of bytes
|
||||
// written to |buffer|, and OEMCrypto_SUCCESS is returned.
|
||||
// If the provided |*buffer_size| is too small, ERROR_SHORT_BUFFER
|
||||
// is returned and |*buffer_size| is set to the required buffer size.
|
||||
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
|
||||
// Same as above, except directly returns the serialized key.
|
||||
// Returns an empty vector on error.
|
||||
std::vector<uint8_t> Serialize() const;
|
||||
|
||||
// Verifies the |signature| matches the provided |message| by the
|
||||
// private equivalent of this public key.
|
||||
// The |signature| should be a valid ASN.1 DER encoded
|
||||
// ECDSA-Sig-Value.
|
||||
// This implementation uses ECDSA with the following digest
|
||||
// algorithms for the supported curve types.
|
||||
// - SHA-256 / secp256r1
|
||||
// - SHA-384 / secp384r1 (optional support)
|
||||
// - SHA-512 / secp521r1 (optional support)
|
||||
// Returns:
|
||||
// OEMCrypto_SUCCESS if signature is valid
|
||||
// OEMCrypto_ERROR_SIGNATURE_FAILURE if the signature is invalid
|
||||
// Any other result indicates an unexpected error
|
||||
OEMCryptoResult VerifySignature(const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length) const;
|
||||
OEMCryptoResult VerifySignature(const std::string& message,
|
||||
const std::string& signature) const;
|
||||
OEMCryptoResult VerifySignature(const std::vector<uint8_t>& message,
|
||||
const std::vector<uint8_t>& signature) const;
|
||||
|
||||
~EccPublicKey();
|
||||
|
||||
EccPublicKey(const EccPublicKey&) = delete;
|
||||
EccPublicKey(EccPublicKey&&) = delete;
|
||||
const EccPublicKey& operator=(const EccPublicKey&) = delete;
|
||||
EccPublicKey& operator=(EccPublicKey&&) = delete;
|
||||
|
||||
private:
|
||||
EccPublicKey() {}
|
||||
|
||||
// Initializes the public key object using the provided |buffer|.
|
||||
// In case of any failure, false is return and the key should be
|
||||
// discarded.
|
||||
bool InitFromBuffer(const uint8_t* buffer, size_t length);
|
||||
// Initializes the public key object from a private.
|
||||
bool InitFromPrivateKey(const EccPrivateKey& private_key);
|
||||
|
||||
// OpenSSL/BoringSSL implementation of an ECC key.
|
||||
// As a public key, this will only have key point initialized.
|
||||
EC_KEY* key_ = nullptr;
|
||||
EccCurve curve_ = kEccCurveUnknown;
|
||||
};
|
||||
|
||||
class EccPrivateKey {
|
||||
public:
|
||||
// Creates a new, pseudorandom ECC private key belonging to the
|
||||
// curve specified.
|
||||
static std::unique_ptr<EccPrivateKey> New(EccCurve curve);
|
||||
|
||||
// Loads a serialized ECC private key.
|
||||
// The provided |buffer| must contain a valid ASN.1 DER encoded
|
||||
// ECPrivateKey. Only supported curves by this API are those
|
||||
// enumerated by EccCurve.
|
||||
//
|
||||
// buffer: ECPrivateKey = {
|
||||
// version: INTEGER = ecPrivateKeyVer1,
|
||||
// privateKey: OCTET STRING = ..., -- I2OSP of private key point
|
||||
// parameters: ECParameters = {
|
||||
// namedCurve: OID = secp256r1 | secp384r1 | secp521r1
|
||||
// },
|
||||
// publicKey: BIT STRING OPTIONAL = ... -- SEC1 encoded ECPoint
|
||||
// }
|
||||
// Note: If the public key is not included, then it is computed from
|
||||
// the private key.
|
||||
//
|
||||
// Failure will occur if the provided |buffer| does not contain a
|
||||
// valid ECPrivateKey, or if the specified curve is not supported.
|
||||
static std::unique_ptr<EccPrivateKey> Load(const uint8_t* buffer,
|
||||
size_t length);
|
||||
static std::unique_ptr<EccPrivateKey> Load(const std::string& buffer);
|
||||
static std::unique_ptr<EccPrivateKey> Load(
|
||||
const std::vector<uint8_t>& buffer);
|
||||
|
||||
// Creates a new ECC public key of this private key.
|
||||
// Equivalent to calling EccPublicKey::New with this private
|
||||
// key.
|
||||
std::unique_ptr<EccPublicKey> MakePublicKey() const;
|
||||
|
||||
EccCurve curve() const { return curve_; }
|
||||
const EC_KEY* GetEcKey() const { return key_; }
|
||||
|
||||
// Checks if the provided |public_key| is the EC public key of this
|
||||
// private key.
|
||||
bool IsMatchingPublicKey(const EccPublicKey& public_key) const;
|
||||
|
||||
// Serializes the private key into an ASN.1 DER encoded ECPrivateKey
|
||||
// representation.
|
||||
// On success, |*buffer_size| is populated with the number of bytes
|
||||
// written to |buffer|, and SUCCESS is returned.
|
||||
// If the provided |*buffer_size| is too small,
|
||||
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |*buffer_size| is
|
||||
// set to the required buffer size.
|
||||
OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const;
|
||||
// Same as above, except directly returns the serialized key.
|
||||
// Returns an empty vector on error.
|
||||
std::vector<uint8_t> Serialize() const;
|
||||
|
||||
// Signs the provided |message| and serializes the signature
|
||||
// point to |signature| as a ASN.1 DER encoded ECDSA-Sig-Value.
|
||||
// This implementation uses ECDSA with the following digest
|
||||
// algorithms for the supported curve types.
|
||||
// - SHA-256 / secp256r1
|
||||
// - SHA-384 / secp384r1 (optional support)
|
||||
// - SHA-512 / secp521r1 (optional support)
|
||||
// On success, |*signature_length| is populated with the number of
|
||||
// bytes written to |signature|, and SUCCESS is returned.
|
||||
// If the provided |*signature_length| is too small,
|
||||
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |*signature_length|
|
||||
// is set to the required signature size.
|
||||
OEMCryptoResult GenerateSignature(const uint8_t* message,
|
||||
size_t message_length, uint8_t* signature,
|
||||
size_t* signature_length) const;
|
||||
// Same as above, except directly returns the serialized signature.
|
||||
// Returns an empty vector on error.
|
||||
std::vector<uint8_t> GenerateSignature(
|
||||
const std::vector<uint8_t>& message) const;
|
||||
std::vector<uint8_t> GenerateSignature(const std::string& message) const;
|
||||
// Returns an upper bound for the signature size. May be larger than
|
||||
// the actual signature generated by GenerateSignature().
|
||||
size_t SignatureSize() const;
|
||||
|
||||
// Derives the OEMCrypto session key used for deriving other keys.
|
||||
// The provided public key must be of the same curve.
|
||||
// On success, |*session_key_size| is populated with the number of
|
||||
// bytes written to |session_key|, and OEMCrypto_SUCCESS is returned.
|
||||
// If the provided |*session_key_size| is too small,
|
||||
// OEMCrypto_ERROR_SHORT_BUFFER is returned and |*session_key_size|
|
||||
// is set to the required buffer size.
|
||||
OEMCryptoResult DeriveSessionKey(const EccPublicKey& public_key,
|
||||
uint8_t* session_key,
|
||||
size_t* session_key_size) const;
|
||||
// Same as above, except directly returns the derived key.
|
||||
std::vector<uint8_t> DeriveSessionKey(const EccPublicKey& public_key) const;
|
||||
// Returns the byte length of the symmetric key that would be derived
|
||||
// by DeriveSymmetricKey().
|
||||
size_t SessionKeyLength() const;
|
||||
|
||||
~EccPrivateKey();
|
||||
|
||||
EccPrivateKey(const EccPrivateKey&) = delete;
|
||||
EccPrivateKey(EccPrivateKey&&) = delete;
|
||||
const EccPrivateKey& operator=(const EccPrivateKey&) = delete;
|
||||
EccPrivateKey& operator=(EccPrivateKey&&) = delete;
|
||||
|
||||
private:
|
||||
EccPrivateKey() {}
|
||||
|
||||
// Initializes the public key object using the provided |buffer|.
|
||||
// In case of any failure, false is return and the key should be
|
||||
// discarded.
|
||||
bool InitFromBuffer(const uint8_t* buffer, size_t length);
|
||||
// Generates a new key based on the provided curve.
|
||||
bool InitFromCurve(EccCurve curve);
|
||||
|
||||
// OpenSSL/BoringSSL implementation of an ECC key.
|
||||
// The public point of the key will always be present.
|
||||
EC_KEY* key_ = nullptr;
|
||||
EccCurve curve_ = kEccCurveUnknown;
|
||||
};
|
||||
|
||||
} // namespace wvoec_ref
|
||||
|
||||
#endif // OEMCRYPTO_EC_KEY_H_
|
||||
Reference in New Issue
Block a user