Fix signature key import/export, add tests
Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
parent
d29a8fbb67
commit
365814b424
@ -44,6 +44,8 @@ pub enum CryptoError {
|
||||
SignatureFailed,
|
||||
/// The signature does not have the expected size
|
||||
InvalidSignatureSize,
|
||||
/// Trying to load a key which is not the expected format,
|
||||
InvalidKey,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for CryptoError {
|
||||
@ -57,6 +59,7 @@ impl core::fmt::Display for CryptoError {
|
||||
CryptoError::InvalidSignatureSize => {
|
||||
f.write_str("provided signature does not have the expected size")
|
||||
}
|
||||
CryptoError::InvalidKey => f.write_str("the provided bytes are not a valid key"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,3 +95,9 @@ impl From<bincode::error::EncodeError> for Error {
|
||||
Self::Coding
|
||||
}
|
||||
}
|
||||
|
||||
impl From<k256::ecdsa::Error> for CryptoError {
|
||||
fn from(_: k256::ecdsa::Error) -> Self {
|
||||
Self::InvalidKey
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ pub struct SigningKeypair {
|
||||
vk: VerifyingKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct PublicKey(VerifyingKey);
|
||||
|
||||
impl SigningKeypair {
|
||||
@ -58,13 +59,14 @@ impl SigningKeypair {
|
||||
impl PublicKey {
|
||||
/// Import a public key from raw bytes
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
|
||||
if bytes.len() == 64 {
|
||||
Ok(Self(
|
||||
VerifyingKey::from_sec1_bytes(bytes).expect("Key is of valid size"),
|
||||
))
|
||||
} else {
|
||||
Err(CryptoError::InvalidKeySize)
|
||||
}
|
||||
Ok(Self(VerifyingKey::from_sec1_bytes(bytes)?))
|
||||
}
|
||||
|
||||
/// Get the raw bytes of this `PublicKey`, which can be transferred to another party.
|
||||
///
|
||||
/// The public key is SEC-1 encoded and compressed.
|
||||
pub fn as_bytes(&self) -> Box<[u8]> {
|
||||
self.0.to_encoded_point(true).to_bytes()
|
||||
}
|
||||
|
||||
pub fn verify_signature(&self, message: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
|
||||
@ -74,3 +76,67 @@ impl PublicKey {
|
||||
.map_err(|_| CryptoError::SignatureFailed)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
/// Generate a key, get the public key, export the bytes of said public key, import them again
|
||||
/// as a public key, and verify the keys match. This make sure public keys can be exchanged.
|
||||
#[test]
|
||||
fn recover_public_key() {
|
||||
let sk = super::SigningKeypair::new().expect("Can generate new key");
|
||||
let pk = sk.public_key();
|
||||
let pk_bytes = pk.as_bytes();
|
||||
|
||||
let pk2 = super::PublicKey::from_bytes(&pk_bytes).expect("Can import public key");
|
||||
|
||||
assert_eq!(pk, pk2);
|
||||
}
|
||||
|
||||
/// Sign a message and validate the signature with the public key. Together with the above test
|
||||
/// this makes sure a remote system can receive our public key and validate messages we sign.
|
||||
#[test]
|
||||
fn validate_signature() {
|
||||
let sk = super::SigningKeypair::new().expect("Can generate new key");
|
||||
let pk = sk.public_key();
|
||||
|
||||
let message = b"this is an arbitrary message we want to sign";
|
||||
|
||||
let sig = sk.sign(message).expect("Message can be signed");
|
||||
|
||||
assert!(pk.verify_signature(message, &sig).is_ok());
|
||||
}
|
||||
|
||||
/// Make sure a signature which is tampered with does not pass signature validation
|
||||
#[test]
|
||||
fn corrupt_signature_does_not_validate() {
|
||||
let sk = super::SigningKeypair::new().expect("Can generate new key");
|
||||
let pk = sk.public_key();
|
||||
|
||||
let message = b"this is an arbitrary message we want to sign";
|
||||
|
||||
let mut sig = sk.sign(message).expect("Message can be signed");
|
||||
|
||||
// Tamper with the sig
|
||||
sig[0] = sig[0].wrapping_add(1);
|
||||
|
||||
assert!(pk.verify_signature(message, &sig).is_err());
|
||||
}
|
||||
|
||||
/// Make sure a valid signature does not work for a message which has been modified
|
||||
#[test]
|
||||
fn tampered_message_does_not_validate() {
|
||||
let sk = super::SigningKeypair::new().expect("Can generate new key");
|
||||
let pk = sk.public_key();
|
||||
|
||||
let message = b"this is an arbitrary message we want to sign";
|
||||
let mut message_clone = message.to_vec();
|
||||
|
||||
let sig = sk.sign(message).expect("Message can be signed");
|
||||
|
||||
// Modify the message
|
||||
message_clone[0] = message[0].wrapping_add(1);
|
||||
|
||||
assert!(pk.verify_signature(&message_clone, &sig).is_err());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user