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>;
73boost::optional<InternalPublicKey> convert_public_key(
const PublicKey& pub_key)
75 InternalPublicKey out;
76 out.AccessGroupParameters().Initialize(get_oid(pub_key.type));
77 auto& curve = out.GetGroupParameters().GetCurve();
79 CryptoPP::ECP::Point point;
80 ByteBuffer encoded_pub_key = encode_public_key(pub_key);
81 CryptoPP::StringStore store { encoded_pub_key.data(), encoded_pub_key.size() };
82 if (!curve.DecodePoint(point, store, store.MaxRetrievable())) {
85 out.SetPublicElement(point);
92template<
typename ECDSA>
93class Verifier :
public ECDSA::Verifier
96 using BaseVerifier =
typename ECDSA::Verifier;
102 Verifier(
const InternalPublicKey& pub)
113 bool VerifyDigest(
const ByteBuffer& digest,
const Signature& sig)
115 using namespace CryptoPP;
116 const auto& alg = this->GetSignatureAlgorithm();
117 const auto& params = this->GetAbstractGroupParameters();
118 const auto& key = this->GetKeyInterface();
119 this->GetMaterial().DoQuickSanityCheck();
121 Integer e { digest.data(), digest.size() };
122 Integer r { sig.r.data(), sig.r.size() };
123 Integer s { sig.s.data(), sig.s.size() };
124 return alg.Verify(params, key, e, r, s);
130using std::placeholders::_1;
132BackendCryptoPP::BackendCryptoPP() :
133 m_private_cache(
std::bind(&BackendCryptoPP::internal_private_key, this, _1), 8),
134 m_public_cache(
std::bind(&BackendCryptoPP::internal_public_key, this, _1), 2048)
140 return sign_data(m_private_cache[generic_key], data);
143EcdsaSignature BackendCryptoPP::sign_data(
const Ecdsa256::PrivateKey& private_key,
const ByteBuffer& data)
146 Ecdsa256::Signer signer(private_key);
147 ByteBuffer signature(signer.MaxSignatureLength(), 0x00);
148 auto signature_length = signer.SignMessage(m_prng, data.data(), data.size(), signature.data());
149 signature.resize(signature_length);
151 auto signature_delimiter = signature.begin();
152 std::advance(signature_delimiter, 32);
157 coordinate.x = ByteBuffer(signature.begin(), signature_delimiter);
158 ecdsa_signature.R = std::move(coordinate);
160 ByteBuffer trailer_field_buffer(signature_delimiter, signature.end());
161 ecdsa_signature.s = std::move(trailer_field_buffer);
163 return ecdsa_signature;
168 const ByteBuffer sigbuf = extract_signature_buffer(sig);
169 return verify_data(m_public_cache[generic_key], msg, sigbuf);
172bool BackendCryptoPP::verify_digest(
const PublicKey& public_key,
const ByteBuffer& digest,
const Signature& sig)
174 if (public_key.type != sig.type) {
178 boost::optional<InternalPublicKey> internal_pub_key = convert_public_key(public_key);
179 if (!internal_pub_key) {
181 }
else if (!internal_pub_key->Validate(m_prng, 3)) {
185 if (sig.type == KeyType::NistP256 || sig.type == KeyType::BrainpoolP256r1) {
186 Verifier<Ecdsa256> verifier(*internal_pub_key);
187 return verifier.VerifyDigest(digest, sig);
188 }
else if (sig.type == KeyType::BrainpoolP384r1) {
189 Verifier<Ecdsa384> verifier(*internal_pub_key);
190 return verifier.VerifyDigest(digest, sig);
196bool BackendCryptoPP::verify_data(
const Ecdsa256::PublicKey& public_key,
const ByteBuffer& msg,
const ByteBuffer& sig)
198 Ecdsa256::Verifier verifier(public_key);
199 return verifier.VerifyMessage(msg.data(), msg.size(), sig.data(), sig.size());
202boost::optional<Uncompressed> BackendCryptoPP::decompress_point(
const EccPoint& ecc_point)
204 struct DecompressionVisitor :
public boost::static_visitor<bool>
213 decompress(p.x, 0x02);
219 decompress(p.x, 0x03);
229 void decompress(
const ByteBuffer& x, ByteBuffer::value_type type)
232 compact.reserve(x.size() + 1);
233 compact.push_back(type);
234 std::copy(x.begin(), x.end(), std::back_inserter(compact));
236 CryptoPP::ECP::Point point;
237 CryptoPP::DL_GroupParameters_EC<CryptoPP::ECP> group(CryptoPP::ASN1::secp256r1());
238 group.GetCurve().DecodePoint(point, compact.data(), compact.size());
241 result.y.resize(result.x.size());
242 point.y.Encode(result.y.data(), result.y.size());
248 DecompressionVisitor visitor;
249 if (boost::apply_visitor(visitor, ecc_point)) {
250 return visitor.result;
256ByteBuffer BackendCryptoPP::calculate_hash(KeyType key,
const ByteBuffer& buffer)
260 case KeyType::NistP256:
261 case KeyType::BrainpoolP256r1: {
262 CryptoPP::SHA256 algo;
263 hash.resize(algo.DigestSize());
264 algo.CalculateDigest(hash.data(), buffer.data(), buffer.size());
267 case KeyType::BrainpoolP384r1: {
268 CryptoPP::SHA384 algo;
269 hash.resize(algo.DigestSize());
270 algo.CalculateDigest(hash.data(), buffer.data(), buffer.size());
283 auto private_key = generate_private_key();
284 auto& private_exponent = private_key.GetPrivateExponent();
285 assert(kp.private_key.key.size() >= private_exponent.ByteCount());
286 private_exponent.Encode(kp.private_key.key.data(), kp.private_key.key.size());
288 auto public_key = generate_public_key(private_key);
289 auto& public_element = public_key.GetPublicElement();
290 assert(kp.public_key.x.size() >= public_element.x.ByteCount());
291 assert(kp.public_key.y.size() >= public_element.y.ByteCount());
292 public_element.x.Encode(kp.public_key.x.data(), kp.public_key.x.size());
293 public_element.y.Encode(kp.public_key.y.data(), kp.public_key.y.size());
297BackendCryptoPP::Ecdsa256::PrivateKey BackendCryptoPP::generate_private_key()
299 CryptoPP::OID oid(CryptoPP::ASN1::secp256r1());
300 Ecdsa256::PrivateKey private_key;
301 private_key.Initialize(m_prng, oid);
302 assert(private_key.Validate(m_prng, 3));
306BackendCryptoPP::Ecdsa256::PublicKey BackendCryptoPP::generate_public_key(
const Ecdsa256::PrivateKey& private_key)
308 Ecdsa256::PublicKey public_key;
309 private_key.MakePublicKey(public_key);
310 assert(public_key.Validate(m_prng, 3));
314BackendCryptoPP::Ecdsa256::PublicKey BackendCryptoPP::internal_public_key(
const ecdsa256::PublicKey& generic)
316 CryptoPP::Integer x {
generic.x.data(),
generic.x.size() };
317 CryptoPP::Integer y {
generic.y.data(),
generic.y.size() };
318 CryptoPP::ECP::Point q { x, y };
320 Ecdsa256::PublicKey pub;
321 pub.Initialize(CryptoPP::ASN1::secp256r1(), q);
322 assert(pub.Validate(m_prng, 3));
326BackendCryptoPP::Ecdsa256::PrivateKey BackendCryptoPP::internal_private_key(
const ecdsa256::PrivateKey& generic)
328 Ecdsa256::PrivateKey key;
329 CryptoPP::Integer integer {
generic.key.data(),
generic.key.size() };
330 key.Initialize(CryptoPP::ASN1::secp256r1(), integer);
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.