aboutsummaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorAdam Langley <agl@chromium.org>2024-01-07 18:05:24 -0800
committerAdam Langley <agl@google.com>2024-01-19 18:24:55 +0000
commit9333b29d08451a85d69cbf86d26950c8a96a532c (patch)
tree3891dc78ed099b2d4c52b4622d6b248038f9ef19 /rust
parent169128d47a7d558477bcb4ffbc565450cd449914 (diff)
downloadboringssl-9333b29d08451a85d69cbf86d26950c8a96a532c.zip
boringssl-9333b29d08451a85d69cbf86d26950c8a96a532c.tar.gz
boringssl-9333b29d08451a85d69cbf86d26950c8a96a532c.tar.bz2
Reworking bssl_crypto: Ed25519
Change-Id: Ie59326b9c987319dfbe4909955e2370384a7532f Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/65177 Reviewed-by: Bob Beck <bbe@google.com>
Diffstat (limited to 'rust')
-rw-r--r--rust/bssl-crypto/src/ecdsa.rs10
-rw-r--r--rust/bssl-crypto/src/ed25519.rs168
-rw-r--r--rust/bssl-crypto/src/lib.rs1
3 files changed, 90 insertions, 89 deletions
diff --git a/rust/bssl-crypto/src/ecdsa.rs b/rust/bssl-crypto/src/ecdsa.rs
index ae65200..c0b5fee 100644
--- a/rust/bssl-crypto/src/ecdsa.rs
+++ b/rust/bssl-crypto/src/ecdsa.rs
@@ -34,7 +34,7 @@
//! assert!(public_key.verify(signed_message, sig.as_slice()).is_ok());
//! ```
-use crate::{ec, sealed, with_output_vec, Buffer, FfiSlice};
+use crate::{ec, sealed, with_output_vec, Buffer, FfiSlice, InvalidSignatureError};
use alloc::vec::Vec;
use core::marker::PhantomData;
@@ -44,10 +44,6 @@ pub struct PublicKey<C: ec::Curve> {
marker: PhantomData<C>,
}
-/// InvalidSignature is a [`Result`] error type when a signature fails to verify.
-#[derive(Debug)]
-pub struct InvalidSignature;
-
impl<C: ec::Curve> PublicKey<C> {
/// Parse a public key in uncompressed X9.62 format. (This is the common
/// format for elliptic curve points beginning with an 0x04 byte.)
@@ -83,7 +79,7 @@ impl<C: ec::Curve> PublicKey<C> {
/// with this public key. SHA-256 will be used to produce the digest if the
/// curve of this public key is P-256. SHA-384 will be used to produce the
/// digest if the curve of this public key is P-384.
- pub fn verify(&self, signed_msg: &[u8], signature: &[u8]) -> Result<(), InvalidSignature> {
+ pub fn verify(&self, signed_msg: &[u8], signature: &[u8]) -> Result<(), InvalidSignatureError> {
let digest = C::hash(signed_msg);
let result = self.point.with_point_as_ec_key(|ec_key| unsafe {
// Safety: `ec_key` is valid per `with_point_as_ec_key`.
@@ -99,7 +95,7 @@ impl<C: ec::Curve> PublicKey<C> {
if result == 1 {
Ok(())
} else {
- Err(InvalidSignature)
+ Err(InvalidSignatureError)
}
}
}
diff --git a/rust/bssl-crypto/src/ed25519.rs b/rust/bssl-crypto/src/ed25519.rs
index f4ab5be..5ac5291 100644
--- a/rust/bssl-crypto/src/ed25519.rs
+++ b/rust/bssl-crypto/src/ed25519.rs
@@ -13,108 +13,126 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-use crate::CSlice;
+//! Ed25519, a signature scheme.
+//!
+//! Ed25519 builds a signature scheme over a curve that is isogenous to
+//! curve25519. This module provides the "pure" signature scheme described in
+//! <https://datatracker.ietf.org/doc/html/rfc8032>.
+//!
+//! ```
+//! use bssl_crypto::ed25519;
+//!
+//! let key = ed25519::PrivateKey::generate();
+//! // Publish your public key.
+//! let public_key_bytes = *key.to_public().as_bytes();
+//!
+//! // Sign and publish some message.
+//! let signed_message = b"hello world";
+//! let mut sig = key.sign(signed_message);
+//!
+//! // Anyone with the public key can verify it.
+//! let public_key = ed25519::PublicKey::from_bytes(&public_key_bytes);
+//! assert!(public_key.verify(signed_message, &sig).is_ok());
+//! ```
+
+use crate::{FfiMutSlice, FfiSlice, InvalidSignatureError};
/// The length in bytes of an Ed25519 public key.
-pub const PUBLIC_KEY_LENGTH: usize = bssl_sys::ED25519_PUBLIC_KEY_LEN as usize;
+pub const PUBLIC_KEY_LEN: usize = bssl_sys::ED25519_PUBLIC_KEY_LEN as usize;
-/// The length in bytes of an Ed25519 seed which is the 32-byte private key representation defined
-/// in RFC 8032.
-pub const SEED_LENGTH: usize =
+/// The length in bytes of an Ed25519 seed which is the 32-byte private key
+/// representation defined in RFC 8032.
+pub const SEED_LEN: usize =
(bssl_sys::ED25519_PRIVATE_KEY_LEN - bssl_sys::ED25519_PUBLIC_KEY_LEN) as usize;
/// The length in bytes of an Ed25519 signature.
-pub const SIGNATURE_LENGTH: usize = bssl_sys::ED25519_SIGNATURE_LEN as usize;
+pub const SIGNATURE_LEN: usize = bssl_sys::ED25519_SIGNATURE_LEN as usize;
// The length in bytes of an Ed25519 keypair. In BoringSSL, the private key is suffixed with the
// public key, so the keypair length is the same as the private key length.
-const KEYPAIR_LENGTH: usize = bssl_sys::ED25519_PRIVATE_KEY_LEN as usize;
+const KEYPAIR_LEN: usize = bssl_sys::ED25519_PRIVATE_KEY_LEN as usize;
/// An Ed25519 private key.
-pub struct PrivateKey([u8; KEYPAIR_LENGTH]);
-
-/// An Ed25519 signature created by signing a message with a private key.
-pub struct Signature([u8; SIGNATURE_LENGTH]);
+pub struct PrivateKey([u8; KEYPAIR_LEN]);
/// An Ed25519 public key used to verify a signature + message.
-pub struct PublicKey([u8; PUBLIC_KEY_LENGTH]);
+pub struct PublicKey([u8; PUBLIC_KEY_LEN]);
-/// Error returned if the verification on the signature + message fails.
-#[derive(Debug)]
-pub struct SignatureError;
+/// An Ed25519 signature created by signing a message with a private key.
+pub type Signature = [u8; SIGNATURE_LEN];
impl PrivateKey {
/// Generates a new Ed25519 keypair.
pub fn generate() -> Self {
- let mut public_key = [0u8; PUBLIC_KEY_LENGTH];
- let mut private_key = [0u8; KEYPAIR_LENGTH];
+ let mut public_key = [0u8; PUBLIC_KEY_LEN];
+ let mut private_key = [0u8; KEYPAIR_LEN];
// Safety:
// - Public key and private key are the correct length.
- unsafe { bssl_sys::ED25519_keypair(public_key.as_mut_ptr(), private_key.as_mut_ptr()) }
+ unsafe {
+ bssl_sys::ED25519_keypair(public_key.as_mut_ffi_ptr(), private_key.as_mut_ffi_ptr())
+ }
PrivateKey(private_key)
}
- /// Converts the key-pair to an array of bytes consisting of the bytes of the private key
- /// followed by the bytes of the public key.
- pub fn to_seed(&self) -> [u8; SEED_LENGTH] {
+ /// Returns the "seed" of this private key, as defined in RFC 8032.
+ pub fn to_seed(&self) -> [u8; SEED_LEN] {
// This code will never panic because a length 32 slice will always fit into a
// size 32 byte array. The private key is the first 32 bytes of the keypair.
#[allow(clippy::expect_used)]
- self.0[..SEED_LENGTH].try_into().expect(
- "A slice of length SEED_LENGTH will always fit into an array of length SEED_LENGTH",
- )
+ self.0[..SEED_LEN]
+ .try_into()
+ .expect("A slice of length SEED_LEN will always fit into an array of length SEED_LEN")
}
- /// Builds this key-pair from `seed`, which is the 32-byte private key representation defined
+ /// Derives a key-pair from `seed`, which is the 32-byte private key representation defined
/// in RFC 8032.
- pub fn new_from_seed(seed: &[u8; SEED_LENGTH]) -> Self {
- let mut public_key = [0u8; PUBLIC_KEY_LENGTH];
- let mut private_key = [0u8; KEYPAIR_LENGTH];
+ pub fn from_seed(seed: &[u8; SEED_LEN]) -> Self {
+ let mut public_key = [0u8; PUBLIC_KEY_LEN];
+ let mut private_key = [0u8; KEYPAIR_LEN];
// Safety:
// - Public key, private key, and seed are the correct lengths.
unsafe {
bssl_sys::ED25519_keypair_from_seed(
- public_key.as_mut_ptr(),
- private_key.as_mut_ptr(),
- seed.as_ptr(),
+ public_key.as_mut_ffi_ptr(),
+ private_key.as_mut_ffi_ptr(),
+ seed.as_ffi_ptr(),
)
}
PrivateKey(private_key)
}
- /// Signs the given message and returns a digital signature.
+ /// Signs the given message and returns the signature.
pub fn sign(&self, msg: &[u8]) -> Signature {
- let mut sig_bytes = [0u8; SIGNATURE_LENGTH];
+ let mut sig_bytes = [0u8; SIGNATURE_LEN];
- let msg_ffi = CSlice(msg);
// Safety:
// - On allocation failure we panic.
// - Signature and private keys are always the correct length.
let result = unsafe {
bssl_sys::ED25519_sign(
- sig_bytes.as_mut_ptr(),
- msg_ffi.as_ptr(),
- msg_ffi.len(),
- self.0.as_ptr(),
+ sig_bytes.as_mut_ffi_ptr(),
+ msg.as_ffi_ptr(),
+ msg.len(),
+ self.0.as_ffi_ptr(),
)
};
assert_eq!(result, 1, "allocation failure in bssl_sys::ED25519_sign");
- Signature(sig_bytes)
+ sig_bytes
}
- /// Returns the PublicKey of the KeyPair.
- pub fn public(&self) -> PublicKey {
- let keypair_bytes = self.0;
+ /// Returns the [`PublicKey`] corresponding to this private key.
+ pub fn to_public(&self) -> PublicKey {
+ let keypair_bytes = &self.0;
// This code will never panic because a length 32 slice will always fit into a
// size 32 byte array. The public key is the last 32 bytes of the keypair.
#[allow(clippy::expect_used)]
PublicKey(
- keypair_bytes[PUBLIC_KEY_LENGTH..]
+ keypair_bytes[PUBLIC_KEY_LEN..]
.try_into()
.expect("The slice is always the correct size for a public key"),
)
@@ -123,78 +141,66 @@ impl PrivateKey {
impl PublicKey {
/// Builds the public key from an array of bytes.
- pub fn from_bytes(bytes: [u8; PUBLIC_KEY_LENGTH]) -> Self {
- PublicKey(bytes)
+ pub fn from_bytes(bytes: &[u8; PUBLIC_KEY_LEN]) -> Self {
+ PublicKey(*bytes)
}
/// Returns the bytes of the public key.
- pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
- self.0
+ pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LEN] {
+ &self.0
}
- /// Succeeds if the signature is a valid signature created by this keypair, otherwise returns an Error.
- pub fn verify(&self, message: &[u8], signature: Signature) -> Result<(), SignatureError> {
- let message_cslice = CSlice::from(message);
+ /// Verifies that `signature` is a valid signature, by this key, of `msg`.
+ pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), InvalidSignatureError> {
let ret = unsafe {
+ // Safety: `self.0` is the correct length and other buffers are valid.
bssl_sys::ED25519_verify(
- message_cslice.as_ptr(),
- message_cslice.len(),
- signature.0.as_ptr(),
- self.0.as_ptr(),
+ msg.as_ffi_ptr(),
+ msg.len(),
+ signature.as_ffi_ptr(),
+ self.0.as_ffi_ptr(),
)
};
if ret == 1 {
Ok(())
} else {
- Err(SignatureError)
+ Err(InvalidSignatureError)
}
}
}
-impl Signature {
- /// Creates a signature from a byte array.
- pub fn from_bytes(bytes: [u8; SIGNATURE_LENGTH]) -> Self {
- Self(bytes)
- }
-
- /// Returns the bytes of the signature.
- pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
- self.0
- }
-}
-
#[cfg(test)]
mod test {
use super::*;
use crate::test_helpers;
#[test]
- fn ed25519_kp_gen_roundtrip() {
+ fn gen_roundtrip() {
let private_key = PrivateKey::generate();
assert_ne!([0u8; 64], private_key.0);
let seed = private_key.to_seed();
- let new_private_key = PrivateKey::new_from_seed(&seed);
+ let new_private_key = PrivateKey::from_seed(&seed);
assert_eq!(private_key.0, new_private_key.0);
}
#[test]
- fn ed25519_empty_msg() {
+ fn empty_msg() {
// Test Case 1 from RFC test vectors: https://www.rfc-editor.org/rfc/rfc8032#section-7.1
let pk = test_helpers::decode_hex(
"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
);
- let sk = test_helpers::decode_hex(
+ let seed = test_helpers::decode_hex(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
);
let msg = [0u8; 0];
let sig_expected = test_helpers::decode_hex("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b");
- let kp = PrivateKey::new_from_seed(&sk);
+ let kp = PrivateKey::from_seed(&seed);
let sig = kp.sign(&msg);
- assert_eq!(sig_expected, sig.0);
+ assert_eq!(sig_expected, sig);
- let pub_key = PublicKey::from_bytes(pk);
- assert_eq!(pub_key.to_bytes(), kp.public().to_bytes());
- assert!(pub_key.verify(&msg, sig).is_ok());
+ let pub_key = PublicKey::from_bytes(&pk);
+ assert_eq!(pub_key.as_bytes(), kp.to_public().as_bytes());
+ assert!(pub_key.verify(&msg, &sig).is_ok());
}
#[test]
@@ -208,13 +214,13 @@ mod test {
);
let msg: [u8; 14] = test_helpers::decode_hex("55c7fa434f5ed8cdec2b7aeac173");
let sig_expected = test_helpers::decode_hex("6ee3fe81e23c60eb2312b2006b3b25e6838e02106623f844c44edb8dafd66ab0671087fd195df5b8f58a1d6e52af42908053d55c7321010092748795ef94cf06");
- let kp = PrivateKey::new_from_seed(&sk);
+ let kp = PrivateKey::from_seed(&sk);
let sig = kp.sign(&msg);
- assert_eq!(sig_expected, sig.0);
+ assert_eq!(sig_expected, sig);
- let pub_key = PublicKey::from_bytes(pk);
- assert_eq!(pub_key.to_bytes(), kp.public().to_bytes());
- assert!(pub_key.verify(&msg, sig).is_ok());
+ let pub_key = PublicKey::from_bytes(&pk);
+ assert_eq!(pub_key.as_bytes(), kp.to_public().as_bytes());
+ assert!(pub_key.verify(&msg, &sig).is_ok());
}
}
diff --git a/rust/bssl-crypto/src/lib.rs b/rust/bssl-crypto/src/lib.rs
index 4263be5..babb044 100644
--- a/rust/bssl-crypto/src/lib.rs
+++ b/rust/bssl-crypto/src/lib.rs
@@ -43,7 +43,6 @@ pub mod cipher;
pub mod digest;
-/// Ed25519, a signature scheme.
pub mod ed25519;
pub mod hkdf;