1#include <vanetza/security/backend_cryptopp.hpp>
2#include <vanetza/security/ecc_point.hpp>
3#include <boost/optional/optional.hpp>
4#include <cryptopp/oids.h>
22CryptoPP::OID get_oid(KeyType key_type)
24 if (key_type == KeyType::NistP256) {
25 return CryptoPP::ASN1::secp256r1();
26 }
else if (key_type == KeyType::BrainpoolP256r1) {
27 return CryptoPP::ASN1::brainpoolP256r1();
28 }
else if (key_type == KeyType::BrainpoolP384r1) {
29 return CryptoPP::ASN1::brainpoolP384r1();
31 return CryptoPP::OID {};
44ByteBuffer encode_public_key(
const PublicKey& pub_key)
48 if (pub_key.compression == KeyCompression::NoCompression) {
49 encoded.reserve(1 + pub_key.x.size() + pub_key.y.size());
50 encoded.push_back(0x04);
51 encoded.insert(encoded.end(), pub_key.x.begin(), pub_key.x.end());
52 encoded.insert(encoded.end(), pub_key.y.begin(), pub_key.y.end());
53 }
else if (pub_key.compression == KeyCompression::Y0) {
54 encoded.reserve(1 + pub_key.x.size());
55 encoded.push_back(0x02);
56 encoded.insert(encoded.end(), pub_key.x.begin(), pub_key.x.end());
57 }
else if (pub_key.compression == KeyCompression::Y1) {
58 encoded.reserve(1 + pub_key.x.size());
59 encoded.push_back(0x03);
60 encoded.insert(encoded.end(), pub_key.x.begin(), pub_key.x.end());
66using InternalPublicKey = CryptoPP::DL_PublicKey_EC<CryptoPP::ECP>;
67using InternalPrivateKey = CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP>;
74boost::optional<InternalPublicKey> convert_public_key(
const PublicKey& pub_key)
76 InternalPublicKey out;
77 out.AccessGroupParameters().Initialize(get_oid(pub_key.type));
78 auto& curve = out.GetGroupParameters().GetCurve();
80 CryptoPP::ECP::Point point;
81 ByteBuffer encoded_pub_key = encode_public_key(pub_key);
82 CryptoPP::StringStore store { encoded_pub_key.data(), encoded_pub_key.size() };
83 if (!curve.DecodePoint(point, store, store.MaxRetrievable())) {
86 out.SetPublicElement(point);
95InternalPrivateKey convert_private_key(
const PrivateKey& priv_key)
97 InternalPrivateKey out;
98 out.AccessGroupParameters().Initialize(get_oid(priv_key.type));
99 out.SetPrivateExponent(CryptoPP::Integer(priv_key.key.data(), priv_key.key.size()));
106template<
typename ECDSA>
107class Verifier :
public ECDSA::Verifier
110 using BaseVerifier =
typename ECDSA::Verifier;
116 Verifier(
const InternalPublicKey& pub)
127 bool VerifyDigest(
const ByteBuffer& digest,
const Signature& sig)
129 using namespace CryptoPP;
130 const auto& alg = this->GetSignatureAlgorithm();
131 const auto& params = this->GetAbstractGroupParameters();
132 const auto& key = this->GetKeyInterface();
133 this->GetMaterial().DoQuickSanityCheck();
135 Integer e { digest.data(), digest.size() };
136 Integer r { sig.r.data(), sig.r.size() };
137 Integer s { sig.s.data(), sig.s.size() };
138 return alg.Verify(params, key, e, r, s);
143class IdentityHash :
public CryptoPP::HashTransformation
146 CRYPTOPP_CONSTANT(DIGESTSIZE = N);
148 static const char* StaticAlgorithmName()
150 return "IdentityHash";
153 void Update(
const uint8_t* input,
size_t length)
override
155 std::copy_n(input, std::min(length, m_hash.size()), m_hash.begin());;
158 void TruncatedFinal(uint8_t* output,
size_t len)
override
160 if (output !=
nullptr) {
161 std::copy_n(m_hash.begin(), std::min(len, m_hash.size()), output);
166 unsigned int DigestSize()
const override
168 return m_hash.size();
172 std::array<uint8_t, N> m_hash;
176using DigestEcdsa = CryptoPP::ECDSA<CryptoPP::ECP, IdentityHash<N>>;
180using std::placeholders::_1;
182BackendCryptoPP::BackendCryptoPP()
194 Ecdsa256::Signer signer(private_key);
195 ByteBuffer signature(signer.MaxSignatureLength(), 0x00);
196 auto signature_length = signer.SignMessage(m_prng, data.data(), data.size(), signature.data());
197 signature.resize(signature_length);
199 auto signature_delimiter = signature.begin();
200 std::advance(signature_delimiter, 32);
205 coordinate.x = ByteBuffer(signature.begin(), signature_delimiter);
206 ecdsa_signature.R = std::move(coordinate);
208 ByteBuffer trailer_field_buffer(signature_delimiter, signature.end());
209 ecdsa_signature.s = std::move(trailer_field_buffer);
211 return ecdsa_signature;
218 CryptoPP::DL_Keys_ECDSA<CryptoPP::ECP>::PrivateKey key;
219 CryptoPP::Integer integer { private_key.key.data(), private_key.key.size() };
221 if (private_key.type == KeyType::NistP256) {
222 CryptoPP::Integer integer { private_key.key.data(), private_key.key.size() };
223 key.Initialize(CryptoPP::ASN1::secp256r1(), integer);
224 }
else if (private_key.type == KeyType::BrainpoolP256r1) {
225 CryptoPP::Integer integer { private_key.key.data(), private_key.key.size() };
226 key.Initialize(CryptoPP::ASN1::brainpoolP256r1(), integer);
227 }
else if (private_key.type == KeyType::BrainpoolP384r1) {
228 CryptoPP::Integer integer { private_key.key.data(), private_key.key.size() };
229 key.Initialize(CryptoPP::ASN1::brainpoolP384r1(), integer);
234 auto calculate_signature = [&](CryptoPP::PK_Signer* signer) ->
Signature
237 ByteBuffer signature(signer->MaxSignatureLength(), 0x00);
238 auto signature_length = signer->SignMessage(m_prng, digest.data(), digest.size(), signature.data());
239 signature.resize(signature_length);
241 auto signature_delimiter = signature.begin();
242 std::advance(signature_delimiter, signer->MaxSignatureLength() / 2);
245 ecdsa_signature.type = private_key.type;
246 ecdsa_signature.r = ByteBuffer(signature.begin(), signature_delimiter);
247 ecdsa_signature.s = ByteBuffer(signature_delimiter, signature.end());
248 return ecdsa_signature;
251 if (digest.size() == 32) {
252 DigestEcdsa<32>::Signer signer(key);
253 return calculate_signature(&signer);
254 }
else if (digest.size() == 48) {
255 DigestEcdsa<48>::Signer signer(key);
256 return calculate_signature(&signer);
264 const ByteBuffer sigbuf = extract_signature_buffer(sig);
270 if (public_key.type != sig.type) {
274 boost::optional<InternalPublicKey> internal_pub_key = convert_public_key(public_key);
275 if (!internal_pub_key) {
277 }
else if (!internal_pub_key->Validate(m_prng, 3)) {
281 if (sig.type == KeyType::NistP256 || sig.type == KeyType::BrainpoolP256r1) {
282 Verifier<Ecdsa256> verifier(*internal_pub_key);
283 return verifier.VerifyDigest(digest, sig);
284 }
else if (sig.type == KeyType::BrainpoolP384r1) {
285 Verifier<Ecdsa384> verifier(*internal_pub_key);
286 return verifier.VerifyDigest(digest, sig);
294 Ecdsa256::Verifier verifier(public_key);
295 return verifier.VerifyMessage(msg.data(), msg.size(), sig.data(), sig.size());
300 struct DecompressionVisitor :
public boost::static_visitor<bool>
309 decompress(p.x, 0x02);
315 decompress(p.x, 0x03);
325 void decompress(
const ByteBuffer& x, ByteBuffer::value_type type)
328 compact.reserve(x.size() + 1);
329 compact.push_back(type);
330 std::copy(x.begin(), x.end(), std::back_inserter(compact));
332 CryptoPP::ECP::Point point;
333 CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> group(CryptoPP::ASN1::secp256r1());
334 group.GetCurve().DecodePoint(point, compact.data(), compact.size());
337 result.y.resize(result.x.size());
338 point.y.Encode(result.y.data(), result.y.size());
344 DecompressionVisitor visitor;
345 if (boost::apply_visitor(visitor, ecc_point)) {
346 return visitor.result;
355 if (algo_id == HashAlgorithm::SHA256) {
356 CryptoPP::SHA256 algo;
357 hash.resize(algo.DigestSize());
358 algo.CalculateDigest(hash.data(), buffer.data(), buffer.size());
359 }
else if (algo_id == HashAlgorithm::SHA384) {
360 CryptoPP::SHA384 algo;
361 hash.resize(algo.DigestSize());
362 algo.CalculateDigest(hash.data(), buffer.data(), buffer.size());
371 auto& private_exponent = private_key.GetPrivateExponent();
372 assert(kp.private_key.key.size() >= private_exponent.ByteCount());
373 private_exponent.Encode(kp.private_key.key.data(), kp.private_key.key.size());
376 auto& public_element = public_key.GetPublicElement();
377 assert(kp.public_key.x.size() >= public_element.x.ByteCount());
378 assert(kp.public_key.y.size() >= public_element.y.ByteCount());
379 public_element.x.Encode(kp.public_key.x.data(), kp.public_key.x.size());
380 public_element.y.Encode(kp.public_key.y.data(), kp.public_key.y.size());
386 CryptoPP::OID oid(CryptoPP::ASN1::secp256r1());
387 Ecdsa256::PrivateKey private_key;
388 private_key.Initialize(m_prng, oid);
389 assert(private_key.Validate(m_prng, 3));
395 Ecdsa256::PublicKey public_key;
396 private_key.MakePublicKey(public_key);
397 assert(public_key.Validate(m_prng, 3));
403 CryptoPP::Integer x {
generic.x.data(),
generic.x.size() };
404 CryptoPP::Integer y {
generic.y.data(),
generic.y.size() };
405 CryptoPP::ECP::Point q { x, y };
407 Ecdsa256::PublicKey pub;
408 pub.Initialize(CryptoPP::ASN1::secp256r1(), q);
409 assert(pub.Validate(m_prng, 3));
415 Ecdsa256::PrivateKey key;
416 CryptoPP::Integer integer {
generic.key.data(),
generic.key.size() };
417 key.Initialize(CryptoPP::ASN1::secp256r1(), integer);
Ecdsa256::PrivateKey generate_private_key()
create private key
Ecdsa256::PublicKey internal_public_key(const ecdsa256::PublicKey &)
adapt generic public key to internal structure
ByteBuffer calculate_hash(HashAlgorithm, const ByteBuffer &) override
boost::optional< Uncompressed > decompress_point(const EccPoint &ecc_point) override
Ecdsa256::PublicKey generate_public_key(const Ecdsa256::PrivateKey &)
derive public key from private key
bool verify_data(const ecdsa256::PublicKey &public_key, const ByteBuffer &data, const EcdsaSignature &sig) override
Signature sign_digest(const PrivateKey &, const ByteBuffer &digest) override
EcdsaSignature sign_data(const ecdsa256::PrivateKey &private_key, const ByteBuffer &data_buffer) override
bool verify_digest(const PublicKey &, const ByteBuffer &digest, const Signature &) override
ecdsa256::KeyPair generate_key_pair()
generate a private key and the corresponding public key
Ecdsa256::PrivateKey internal_private_key(const ecdsa256::PrivateKey &)
adapt generic private key to internal structure
Compressed_Lsb_Y_0 specified in TS 103 097 v1.2.1 in section 4.2.5.
Compressed_Lsb_Y_1 specified in TS 103 097 v1.2.1 in section 4.2.5.
EcdsaSignature specified in TS 103 097 v1.2.1, section 4.2.9.
Uncompressed specified in TS 103 097 v1.2.1 in section 4.2.5.
X_Coordinate_Only specified in TS 103 097 v1.2.1 in section 4.2.5.