1 // Copyright 2024, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! Edwards-curve digital signature algorithm. 16 17 use bssl_crypto::{ed25519, InvalidSignatureError}; 18 use mls_rs_core::crypto::{CipherSuite, SignaturePublicKey, SignatureSecretKey}; 19 use mls_rs_crypto_traits::Curve; 20 21 use core::array::TryFromSliceError; 22 use thiserror::Error; 23 24 /// Errors returned from EdDSA. 25 #[derive(Debug, Error)] 26 pub enum EdDsaError { 27 /// Error returned when conversion from slice to array fails. 28 #[error(transparent)] 29 TryFromSliceError(#[from] TryFromSliceError), 30 /// Error returned on an invalid signature. 31 #[error("invalid signature")] 32 InvalidSig(InvalidSignatureError), 33 /// Error returned when the private key length is invalid. 34 #[error("EdDSA private key of invalid length {len}, expected length {expected_len}")] 35 InvalidPrivKeyLen { 36 /// Invalid key length. 37 len: usize, 38 /// Expected key length. 39 expected_len: usize, 40 }, 41 /// Error returned when the public key length is invalid. 42 #[error("EdDSA public key of invalid length {len}, expected length {expected_len}")] 43 InvalidPubKeyLen { 44 /// Invalid key length. 45 len: usize, 46 /// Expected key length. 47 expected_len: usize, 48 }, 49 /// Error returned when the signature length is invalid. 50 #[error("EdDSA signature of invalid length {len}, expected length {expected_len}")] 51 InvalidSigLen { 52 /// Invalid signature length. 53 len: usize, 54 /// Expected signature length. 55 expected_len: usize, 56 }, 57 /// Error returned when unsupported cipher suite is requested. 58 #[error("unsupported cipher suite")] 59 UnsupportedCipherSuite, 60 } 61 62 // Explicitly implemented as InvalidSignatureError's as_dyn_error does not satisfy trait bounds. 63 impl From<InvalidSignatureError> for EdDsaError { from(e: InvalidSignatureError) -> Self64 fn from(e: InvalidSignatureError) -> Self { 65 EdDsaError::InvalidSig(e) 66 } 67 } 68 69 /// EdDSA implementation backed by BoringSSL. 70 #[derive(Clone, Debug, Copy, PartialEq, Eq)] 71 pub struct EdDsa(Curve); 72 73 impl EdDsa { 74 /// Creates a new EdDsa. new(cipher_suite: CipherSuite) -> Option<Self>75 pub fn new(cipher_suite: CipherSuite) -> Option<Self> { 76 Curve::from_ciphersuite(cipher_suite, /*for_sig=*/ true).map(Self) 77 } 78 79 /// Generates a key pair. signature_key_generate( &self, ) -> Result<(SignatureSecretKey, SignaturePublicKey), EdDsaError>80 pub fn signature_key_generate( 81 &self, 82 ) -> Result<(SignatureSecretKey, SignaturePublicKey), EdDsaError> { 83 if self.0 != Curve::Ed25519 { 84 return Err(EdDsaError::UnsupportedCipherSuite); 85 } 86 87 let private_key = ed25519::PrivateKey::generate(); 88 let public_key = private_key.to_public(); 89 Ok((private_key.to_seed().to_vec().into(), public_key.as_bytes().to_vec().into())) 90 } 91 92 /// Derives the public key from the private key. signature_key_derive_public( &self, secret_key: &SignatureSecretKey, ) -> Result<SignaturePublicKey, EdDsaError>93 pub fn signature_key_derive_public( 94 &self, 95 secret_key: &SignatureSecretKey, 96 ) -> Result<SignaturePublicKey, EdDsaError> { 97 if self.0 != Curve::Ed25519 { 98 return Err(EdDsaError::UnsupportedCipherSuite); 99 } 100 if secret_key.len() != ed25519::SEED_LEN { 101 return Err(EdDsaError::InvalidPrivKeyLen { 102 len: secret_key.len(), 103 expected_len: ed25519::SEED_LEN, 104 }); 105 } 106 107 let private_key = 108 ed25519::PrivateKey::from_seed(secret_key[..ed25519::SEED_LEN].try_into()?); 109 Ok(private_key.to_public().as_bytes().to_vec().into()) 110 } 111 112 /// Signs `data` using `secret_key`. sign( &self, secret_key: &SignatureSecretKey, data: &[u8], ) -> Result<Vec<u8>, EdDsaError>113 pub fn sign( 114 &self, 115 secret_key: &SignatureSecretKey, 116 data: &[u8], 117 ) -> Result<Vec<u8>, EdDsaError> { 118 if self.0 != Curve::Ed25519 { 119 return Err(EdDsaError::UnsupportedCipherSuite); 120 } 121 if secret_key.len() != ed25519::SEED_LEN { 122 return Err(EdDsaError::InvalidPrivKeyLen { 123 len: secret_key.len(), 124 expected_len: ed25519::SEED_LEN, 125 }); 126 } 127 128 let private_key = 129 ed25519::PrivateKey::from_seed(secret_key[..ed25519::SEED_LEN].try_into()?); 130 Ok(private_key.sign(data).to_vec()) 131 } 132 133 /// Verifies `signature` is a valid signature of `data` using `public_key`. verify( &self, public_key: &SignaturePublicKey, signature: &[u8], data: &[u8], ) -> Result<(), EdDsaError>134 pub fn verify( 135 &self, 136 public_key: &SignaturePublicKey, 137 signature: &[u8], 138 data: &[u8], 139 ) -> Result<(), EdDsaError> { 140 if self.0 != Curve::Ed25519 { 141 return Err(EdDsaError::UnsupportedCipherSuite); 142 } 143 if public_key.len() != ed25519::PUBLIC_KEY_LEN { 144 return Err(EdDsaError::InvalidPubKeyLen { 145 len: public_key.len(), 146 expected_len: ed25519::PUBLIC_KEY_LEN, 147 }); 148 } 149 if signature.len() != ed25519::SIGNATURE_LEN { 150 return Err(EdDsaError::InvalidSigLen { 151 len: signature.len(), 152 expected_len: ed25519::SIGNATURE_LEN, 153 }); 154 } 155 156 let public_key = ed25519::PublicKey::from_bytes( 157 public_key.as_bytes()[..ed25519::PUBLIC_KEY_LEN].try_into()?, 158 ); 159 match public_key.verify(data, signature[..ed25519::SIGNATURE_LEN].try_into()?) { 160 Ok(_) => Ok(()), 161 Err(e) => Err(EdDsaError::InvalidSig(e)), 162 } 163 } 164 } 165 166 #[cfg(all(not(mls_build_async), test))] 167 mod test { 168 use super::{EdDsa, EdDsaError}; 169 use crate::test_helpers::decode_hex; 170 use assert_matches::assert_matches; 171 use mls_rs_core::crypto::{CipherSuite, SignaturePublicKey, SignatureSecretKey}; 172 173 #[test] signature_key_generate()174 fn signature_key_generate() { 175 let ed25519 = EdDsa::new(CipherSuite::CURVE25519_AES128).unwrap(); 176 assert!(ed25519.signature_key_generate().is_ok()); 177 } 178 179 #[test] signature_key_derive_public()180 fn signature_key_derive_public() { 181 // Test 1 from https://www.rfc-editor.org/rfc/rfc8032#section-7.1 182 let private_key = SignatureSecretKey::from( 183 decode_hex::<32>("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") 184 .to_vec(), 185 ); 186 let expected_public_key = SignaturePublicKey::from( 187 decode_hex::<32>("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a") 188 .to_vec(), 189 ); 190 191 let ed25519 = EdDsa::new(CipherSuite::CURVE25519_CHACHA).unwrap(); 192 assert_eq!(ed25519.signature_key_derive_public(&private_key).unwrap(), expected_public_key); 193 } 194 195 #[test] signature_key_derive_public_invalid_key()196 fn signature_key_derive_public_invalid_key() { 197 let private_key_short = 198 SignatureSecretKey::from(decode_hex::<16>("9d61b19deffd5a60ba844af492ec2cc4").to_vec()); 199 200 let ed25519 = EdDsa::new(CipherSuite::CURVE25519_CHACHA).unwrap(); 201 assert_matches!( 202 ed25519.signature_key_derive_public(&private_key_short), 203 Err(EdDsaError::InvalidPrivKeyLen { .. }) 204 ); 205 } 206 207 #[test] sign_verify()208 fn sign_verify() { 209 // Test 3 from https://www.rfc-editor.org/rfc/rfc8032#section-7.1 210 let private_key = SignatureSecretKey::from( 211 decode_hex::<32>("c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7") 212 .to_vec(), 213 ); 214 let data: [u8; 2] = decode_hex("af82"); 215 let expected_sig = decode_hex::<64>("6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a").to_vec(); 216 217 let ed25519 = EdDsa::new(CipherSuite::CURVE25519_AES128).unwrap(); 218 let sig = ed25519.sign(&private_key, &data).unwrap(); 219 assert_eq!(sig, expected_sig); 220 221 let public_key = ed25519.signature_key_derive_public(&private_key).unwrap(); 222 assert!(ed25519.verify(&public_key, &sig, &data).is_ok()); 223 } 224 225 #[test] sign_invalid_key()226 fn sign_invalid_key() { 227 let private_key_short = 228 SignatureSecretKey::from(decode_hex::<16>("c5aa8df43f9f837bedb7442f31dcb7b1").to_vec()); 229 230 let ed25519 = EdDsa::new(CipherSuite::CURVE25519_AES128).unwrap(); 231 assert_matches!( 232 ed25519.sign(&private_key_short, &decode_hex::<2>("af82")), 233 Err(EdDsaError::InvalidPrivKeyLen { .. }) 234 ); 235 } 236 237 #[test] verify_invalid_key()238 fn verify_invalid_key() { 239 let public_key_short = 240 SignaturePublicKey::from(decode_hex::<16>("fc51cd8e6218a1a38da47ed00230f058").to_vec()); 241 let sig = decode_hex::<64>("6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a").to_vec(); 242 let data: [u8; 2] = decode_hex("af82"); 243 244 let ed25519 = EdDsa::new(CipherSuite::CURVE25519_AES128).unwrap(); 245 assert_matches!( 246 ed25519.verify(&public_key_short, &sig, &data), 247 Err(EdDsaError::InvalidPubKeyLen { .. }) 248 ); 249 } 250 251 #[test] verify_invalid_sig()252 fn verify_invalid_sig() { 253 let public_key = SignaturePublicKey::from( 254 decode_hex::<32>("fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025") 255 .to_vec(), 256 ); 257 let sig_short = 258 decode_hex::<32>("6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac") 259 .to_vec(); 260 let data: [u8; 2] = decode_hex("af82"); 261 262 let ed25519 = EdDsa::new(CipherSuite::CURVE25519_AES128).unwrap(); 263 assert_matches!( 264 ed25519.verify(&public_key, &sig_short, &data), 265 Err(EdDsaError::InvalidSigLen { .. }) 266 ); 267 } 268 269 #[test] unsupported_cipher_suites()270 fn unsupported_cipher_suites() { 271 for suite in vec![ 272 CipherSuite::P256_AES128, 273 CipherSuite::P384_AES256, 274 CipherSuite::P521_AES256, 275 CipherSuite::CURVE448_CHACHA, 276 CipherSuite::CURVE448_AES256, 277 ] { 278 assert_matches!( 279 EdDsa::new(suite).unwrap().signature_key_generate(), 280 Err(EdDsaError::UnsupportedCipherSuite) 281 ); 282 } 283 } 284 } 285