Skip to content

Commit

Permalink
Merge pull request #4368 from Rohde-Schwarz/ffi/raw_encode_asym_keys
Browse files Browse the repository at this point in the history
  • Loading branch information
reneme authored Oct 12, 2024
2 parents 2cc573c + 1bfe01f commit 909840c
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 0 deletions.
12 changes: 12 additions & 0 deletions doc/api_ref/ffi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,12 @@ Public Key Creation, Import and Export

View the unencrypted PEM encoding of the private key

.. cpp:function:: int botan_privkey_view_raw(botan_privkey_t key, \
botan_view_ctx ctx, botan_view_str_fn view)

View the unencrypted canonical raw encoding of the private key
This might not be defined for all key types and throw in that case.

.. cpp:function:: int botan_privkey_export_encrypted(botan_privkey_t key, \
uint8_t out[], size_t* out_len, \
botan_rng_t rng, \
Expand Down Expand Up @@ -1011,6 +1017,12 @@ Public Key Creation, Import and Export

View the PEM encoding of the public key

.. cpp:function:: int botan_pubkey_view_raw(botan_pubkey_t key, \
botan_view_ctx ctx, botan_view_bin_fn view)

View the canonical raw encoding of the public key.
This may not be defined for all public key types and throw.

.. cpp:function:: int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len)

.. cpp:function:: int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate)
Expand Down
10 changes: 10 additions & 0 deletions doc/api_ref/python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ Public Key
Like ``self.export(True)``
.. py:method:: to_raw()
Exports the key in its canonical raw encoding. This might not be
available for all key types and raise an exception in that case.
.. py:method:: get_field(field_name)
Return an integer field related to the public key. The valid field names
Expand Down Expand Up @@ -397,6 +402,11 @@ Private Key
Return the PEM encoded private key (unencrypted). Like ``self.export(False)``
.. py:method:: to_raw()
Exports the key in its canonical raw encoding. This might not be
available for all key types and raise an exception in that case.
.. py:method:: check_key(rng_obj, strong=True):
Test the key for consistency. If ``strong`` is ``True`` then
Expand Down
11 changes: 11 additions & 0 deletions src/lib/ffi/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,7 @@ BOTAN_FFI_EXPORT(2, 0) int botan_privkey_destroy(botan_privkey_t key);

#define BOTAN_PRIVKEY_EXPORT_FLAG_DER 0
#define BOTAN_PRIVKEY_EXPORT_FLAG_PEM 1
#define BOTAN_PRIVKEY_EXPORT_FLAG_RAW 2

/**
* On input *out_len is number of bytes in out[]
Expand All @@ -1199,6 +1200,11 @@ BOTAN_FFI_EXPORT(3, 0) int botan_privkey_view_der(botan_privkey_t key, botan_vie
*/
BOTAN_FFI_EXPORT(3, 0) int botan_privkey_view_pem(botan_privkey_t key, botan_view_ctx ctx, botan_view_str_fn view);

/**
* View the private key's raw encoding
*/
BOTAN_FFI_EXPORT(3, 6) int botan_privkey_view_raw(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view);

BOTAN_FFI_EXPORT(2, 8) int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len);

/**
Expand Down Expand Up @@ -1326,6 +1332,11 @@ BOTAN_FFI_EXPORT(3, 0) int botan_pubkey_view_der(botan_pubkey_t key, botan_view_
*/
BOTAN_FFI_EXPORT(3, 0) int botan_pubkey_view_pem(botan_pubkey_t key, botan_view_ctx ctx, botan_view_str_fn view);

/**
* View the public key's raw encoding
*/
BOTAN_FFI_EXPORT(3, 6) int botan_pubkey_view_raw(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view);

BOTAN_FFI_EXPORT(2, 0) int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len);

/**
Expand Down
14 changes: 14 additions & 0 deletions src/lib/ffi/ffi_pkey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint
return copy_view_bin(out, out_len, botan_pubkey_view_der, key);
} else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
return copy_view_str(out, out_len, botan_pubkey_view_pem, key);
} else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_RAW) {
return copy_view_bin(out, out_len, botan_pubkey_view_raw, key);
} else {
return BOTAN_FFI_ERROR_BAD_FLAG;
}
Expand All @@ -151,11 +153,18 @@ int botan_pubkey_view_pem(botan_pubkey_t key, botan_view_ctx ctx, botan_view_str
key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::X509::PEM_encode(k)); });
}

int botan_pubkey_view_raw(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
return BOTAN_FFI_VISIT(
key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.raw_public_key_bits()); });
}

int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
return copy_view_bin(out, out_len, botan_privkey_view_der, key);
} else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
return copy_view_str(out, out_len, botan_privkey_view_pem, key);
} else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_RAW) {
return copy_view_bin(out, out_len, botan_privkey_view_raw, key);
} else {
return BOTAN_FFI_ERROR_BAD_FLAG;
}
Expand All @@ -171,6 +180,11 @@ int botan_privkey_view_pem(botan_privkey_t key, botan_view_ctx ctx, botan_view_s
key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::PKCS8::PEM_encode(k)); });
}

int botan_privkey_view_raw(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
return BOTAN_FFI_VISIT(
key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.raw_private_key_bits()); });
}

int botan_privkey_export_encrypted(botan_privkey_t key,
uint8_t out[],
size_t* out_len,
Expand Down
8 changes: 8 additions & 0 deletions src/python/botan3.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ def ffi_api(fn, args, allowed_errors=None):

ffi_api(dll.botan_privkey_view_der, [c_void_p, c_void_p, VIEW_BIN_CALLBACK])
ffi_api(dll.botan_privkey_view_pem, [c_void_p, c_void_p, VIEW_STR_CALLBACK])
ffi_api(dll.botan_privkey_view_raw, [c_void_p, c_void_p, VIEW_BIN_CALLBACK])

ffi_api(dll.botan_privkey_algo_name, [c_void_p, c_char_p, POINTER(c_size_t)])
ffi_api(dll.botan_privkey_export_encrypted,
Expand All @@ -309,6 +310,7 @@ def ffi_api(fn, args, allowed_errors=None):

ffi_api(dll.botan_pubkey_view_der, [c_void_p, c_void_p, VIEW_BIN_CALLBACK])
ffi_api(dll.botan_pubkey_view_pem, [c_void_p, c_void_p, VIEW_STR_CALLBACK])
ffi_api(dll.botan_pubkey_view_raw, [c_void_p, c_void_p, VIEW_BIN_CALLBACK])

ffi_api(dll.botan_pubkey_algo_name, [c_void_p, c_char_p, POINTER(c_size_t)])
ffi_api(dll.botan_pubkey_check_key, [c_void_p, c_void_p, c_uint32], [-1])
Expand Down Expand Up @@ -1261,6 +1263,9 @@ def to_der(self):
def to_pem(self):
return _call_fn_viewing_str(lambda vc, vfn: _DLL.botan_pubkey_view_pem(self.__obj, vc, vfn))

def to_raw(self):
return _call_fn_viewing_vec(lambda vc, vfn: _DLL.botan_pubkey_view_raw(self.__obj, vc, vfn))

def view_kyber_raw_key(self):
return _call_fn_viewing_vec(lambda vc, vfn: _DLL.botan_pubkey_view_kyber_raw_key(self.__obj, vc, vfn))

Expand Down Expand Up @@ -1410,6 +1415,9 @@ def to_der(self):
def to_pem(self):
return _call_fn_viewing_str(lambda vc, vfn: _DLL.botan_privkey_view_pem(self.__obj, vc, vfn))

def to_raw(self):
return _call_fn_viewing_vec(lambda vc, vfn: _DLL.botan_privkey_view_raw(self.__obj, vc, vfn))

def view_kyber_raw_key(self):
return _call_fn_viewing_vec(lambda vc, vfn: _DLL.botan_privkey_view_kyber_raw_key(self.__obj, vc, vfn))

Expand Down
17 changes: 17 additions & 0 deletions src/scripts/test_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,17 @@ def test_rsa_load_store(self):

self.assertEqual(rsapriv.to_pem(), rsa_priv_pem)

# RSA does not provide a dedicated raw encoding for its keys
with self.assertRaisesRegex(botan.BotanException, r".*Not implemented.*"):
rsapriv.to_raw()

rsapub = rsapriv.get_public_key()
self.assertEqual(rsapub.to_pem(), rsa_pub_pem)

# RSA does not provide a dedicated raw encoding for its keys
with self.assertRaisesRegex(botan.BotanException, r".*Not implemented.*"):
rsapub.to_raw()

rsapub = botan.PublicKey.load(rsa_pub_pem)
self.assertEqual(rsapub.to_pem(), rsa_pub_pem)

Expand Down Expand Up @@ -582,9 +590,11 @@ def test_ecdh(self):

a_pub_pt = a_priv.get_public_key().get_public_point()
b_pub_pt = b_priv.get_public_key().get_public_point()
a_pub_raw = a_priv.get_public_key().to_raw()

self.assertEqual(a_op.public_value(), a_pub_pt)
self.assertEqual(b_op.public_value(), b_pub_pt)
self.assertEqual(a_pub_raw, a_pubv)

salt = a_rng.get(8) + b_rng.get(8)

Expand All @@ -601,6 +611,9 @@ def test_ecdh(self):

self.assertEqual(a_pem, new_a.to_pem())

a_raw = hex_encode(a_priv.to_raw())
self.assertEqual(int(a_raw, base=16), a_priv_x)

def test_rfc7748_kex(self):
rng = botan.RandomNumberGenerator()

Expand Down Expand Up @@ -910,11 +923,15 @@ def test_kyber_raw_keys(self):
b_priv = botan.PrivateKey.load_kyber(b_priv_bits) #2400

privkey_read = b_priv.view_kyber_raw_key()
privkey_generic_raw = b_priv.to_raw()
self.assertEqual(privkey_read, b_priv_bits)
self.assertEqual(privkey_generic_raw, b_priv_bits)

b_pub = b_priv.get_public_key()
pubkey_read = b_pub.view_kyber_raw_key()
pubkey_generic_raw = b_pub.to_raw()
self.assertEqual(pubkey_read, b_pub_bits)
self.assertEqual(pubkey_generic_raw, b_pub_bits)

a_pub = botan.PublicKey.load_kyber(a_pub_bits) #1184
pubkey_read = a_pub.view_kyber_raw_key()
Expand Down
18 changes: 18 additions & 0 deletions src/tests/test_ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3317,15 +3317,21 @@ class FFI_Kyber512_Test final : public FFI_Test {
}

std::vector<uint8_t> privkey_read(1632);
std::vector<uint8_t> privkey_read_raw(1632);
TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.data(), botan_ffi_view_u8_fn));
TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.data(), botan_ffi_view_u8_fn));
result.test_eq("kyber512 private key", privkey_read, b_priv_bits);
result.test_eq("kyber512 private key raw", privkey_read_raw, b_priv_bits);

std::vector<uint8_t> pubkey_read(800);
std::vector<uint8_t> pubkey_read_raw(800);

botan_pubkey_t b_pub;
TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.data(), botan_ffi_view_u8_fn));
TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.data(), botan_ffi_view_u8_fn));
result.test_eq("kyber512 public key b", pubkey_read, b_pub_bits);
result.test_eq("kyber512 raw public key b", pubkey_read_raw, b_pub_bits);

botan_pubkey_t a_pub;
TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 800));
Expand Down Expand Up @@ -3356,15 +3362,21 @@ class FFI_Kyber768_Test final : public FFI_Test {
}

std::vector<uint8_t> privkey_read(2400);
std::vector<uint8_t> privkey_read_raw(2400);
TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.data(), botan_ffi_view_u8_fn));
TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.data(), botan_ffi_view_u8_fn));
result.test_eq("kyber768 private key", privkey_read, b_priv_bits);
result.test_eq("kyber768 private key raw", privkey_read_raw, b_priv_bits);

std::vector<uint8_t> pubkey_read(1184);
std::vector<uint8_t> pubkey_read_raw(1184);

botan_pubkey_t b_pub;
TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.data(), botan_ffi_view_u8_fn));
TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.data(), botan_ffi_view_u8_fn));
result.test_eq("kyber768 public key b", pubkey_read, b_pub_bits);
result.test_eq("kyber768 public key raw b", pubkey_read_raw, b_pub_bits);

botan_pubkey_t a_pub;
TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 1184));
Expand Down Expand Up @@ -3395,15 +3407,21 @@ class FFI_Kyber1024_Test final : public FFI_Test {
}

std::vector<uint8_t> privkey_read(3168);
std::vector<uint8_t> privkey_read_raw(3168);
TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.data(), botan_ffi_view_u8_fn));
TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.data(), botan_ffi_view_u8_fn));
result.test_eq("kyber1024 private key", privkey_read, b_priv_bits);
result.test_eq("kyber1024 private key raw", privkey_read_raw, b_priv_bits);

std::vector<uint8_t> pubkey_read(1568);
std::vector<uint8_t> pubkey_read_raw(1568);

botan_pubkey_t b_pub;
TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.data(), botan_ffi_view_u8_fn));
TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.data(), botan_ffi_view_u8_fn));
result.test_eq("kyber1024 public key b", pubkey_read, b_pub_bits);
result.test_eq("kyber1024 public key raw b", pubkey_read_raw, b_pub_bits);

botan_pubkey_t a_pub;
TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 1568));
Expand Down

0 comments on commit 909840c

Please sign in to comment.