randombit / botan

Cryptography Toolkit
https://botan.randombit.net
BSD 2-Clause "Simplified" License
2.52k stars 558 forks source link

Create ECDH_PrivateKey from raw bits #4224

Open ClausDampsoft opened 1 month ago

ClausDampsoft commented 1 month ago

Hello, I'm new to Botan, having some difficulties.

For test purposes I need to create an ECDH_PrivateKey on P-256 (secp256r1) from raw bits (32 bytes in std::vector). I tried the ECDH_PrivateKey-Konstruktor with the AlgorithmIdentifier but I always get some exceptions.

Nearly the same question is for an ECDH_PublicKey with given x and y as raw bits.

Thanks for any hints Claus

reneme commented 1 month ago

Hi! Typically, Botan does not expect the private key as a raw 256bit vector but wrapped as a PEM container. But there's a hack that might get you there:

#include <botan/bigint.h>
#include <botan/ecdh.h>
#include <botan/hex.h>
#include <botan/rng.h>

int main() {
   const auto private_key_bytes = Botan::hex_decode("D2AC61C35CAEE918E47B0BD5E61DA9B3A5C2964AB317647DEF6DFC042A06C829");

   Botan::Null_RNG null_rng;
   const auto private_key = 
      Botan::ECDH_PrivateKey(null_rng,
                             Botan::EC_Group::from_name("secp256r1"),
                             Botan::BigInt(private_key_bytes));
}
randombit commented 1 month ago

^ Not really a hack, that's how it's supposed to work!

For public key from (x,y) similarly construct an EC_Point

reneme commented 1 month ago

Here's some snippet for the public key:

#include <botan/bigint.h>
#include <botan/ecdh.h>
#include <botan/hex.h>
#include <botan/rng.h>

#include <vector>

int main() {
   const auto pk_x = Botan::hex_decode("278309D4A88ADF89CA0E5328D3B655CF8949F2D9F9B2308AA22FE28202A315EC");
   const auto pk_y = Botan::hex_decode("AC457F18D1F3675D46E98ED2E509EE47AC2CB9A012F73263B30CD7248AEA6020");

   std::vector<uint8_t> public_key_bytes;
   public_key_bytes.reserve(pk_x.size() + pk_y.size() + 1);
   public_key_bytes.push_back(0x04);  // means: uncompressed point encoding
   public_key_bytes.insert(public_key_bytes.end(), pk_x.begin(), pk_x.end());
   public_key_bytes.insert(public_key_bytes.end(), pk_y.begin(), pk_y.end());

   const auto domain = Botan::EC_Group::from_name("secp256r1");
   const auto public_key = Botan::ECDH_PublicKey(domain, domain.OS2ECP(public_key_bytes));
}

@randombit domain.point(BigInt(x), BigInt(y)) would have been nice, but that's deprecated. I didn't see another way than to restore the 65-byte encoding above and then call domain.OS2ECP(). Did I miss something?

ClausDampsoft commented 1 month ago

Thanks to you! Private key seems to work. Happy, happy no exception! I detected myself this thing with the 0x04 for the public key. But it looks wrong (= bad style) to me.

Claus

randombit commented 1 month ago

This is an area in need of some cleanup. Right now we've deprecated the stuff we want to remove, but without necessarily introducing (much less documenting...) full replacements. After #4203 lands I'll work on updating the various constructors, etc