diff --git a/doc/api_ref/ffi.rst b/doc/api_ref/ffi.rst index e4309b0d88b..6cb4a54c46f 100644 --- a/doc/api_ref/ffi.rst +++ b/doc/api_ref/ffi.rst @@ -943,6 +943,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, \ @@ -1007,6 +1013,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) diff --git a/doc/api_ref/python.rst b/doc/api_ref/python.rst index 2e9ed56a671..d5edc42d207 100644 --- a/doc/api_ref/python.rst +++ b/doc/api_ref/python.rst @@ -313,6 +313,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 @@ -392,6 +397,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 diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index 874408acb18..a05bab14709 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -1178,6 +1178,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[] @@ -1198,6 +1199,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); /** @@ -1325,6 +1331,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); /** diff --git a/src/lib/ffi/ffi_pkey.cpp b/src/lib/ffi/ffi_pkey.cpp index 3e34e6c9ec6..40339c6d9a0 100644 --- a/src/lib/ffi/ffi_pkey.cpp +++ b/src/lib/ffi/ffi_pkey.cpp @@ -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; } @@ -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; } @@ -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, diff --git a/src/python/botan3.py b/src/python/botan3.py index 9c75b31e494..79adc720d9b 100755 --- a/src/python/botan3.py +++ b/src/python/botan3.py @@ -281,6 +281,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, @@ -306,6 +307,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]) @@ -1147,6 +1149,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)) @@ -1296,6 +1301,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)) diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py index e13155051ec..f6d0a11fe99 100644 --- a/src/scripts/test_python.py +++ b/src/scripts/test_python.py @@ -304,9 +304,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) @@ -524,9 +532,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) @@ -543,6 +553,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() @@ -852,11 +865,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() diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 1625d63f0e1..c428a377f7e 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -3263,15 +3263,21 @@ class FFI_Kyber512_Test final : public FFI_Test { } std::vector privkey_read(1632); + std::vector 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 pubkey_read(800); + std::vector 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)); @@ -3302,15 +3308,21 @@ class FFI_Kyber768_Test final : public FFI_Test { } std::vector privkey_read(2400); + std::vector 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 pubkey_read(1184); + std::vector 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)); @@ -3341,15 +3353,21 @@ class FFI_Kyber1024_Test final : public FFI_Test { } std::vector privkey_read(3168); + std::vector 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 pubkey_read(1568); + std::vector 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));