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,
|
SignatureFailed,
|
||||||
/// The signature does not have the expected size
|
/// The signature does not have the expected size
|
||||||
InvalidSignatureSize,
|
InvalidSignatureSize,
|
||||||
|
/// Trying to load a key which is not the expected format,
|
||||||
|
InvalidKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Display for CryptoError {
|
impl core::fmt::Display for CryptoError {
|
||||||
@ -57,6 +59,7 @@ impl core::fmt::Display for CryptoError {
|
|||||||
CryptoError::InvalidSignatureSize => {
|
CryptoError::InvalidSignatureSize => {
|
||||||
f.write_str("provided signature does not have the expected size")
|
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
|
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,
|
vk: VerifyingKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct PublicKey(VerifyingKey);
|
pub struct PublicKey(VerifyingKey);
|
||||||
|
|
||||||
impl SigningKeypair {
|
impl SigningKeypair {
|
||||||
@ -58,13 +59,14 @@ impl SigningKeypair {
|
|||||||
impl PublicKey {
|
impl PublicKey {
|
||||||
/// Import a public key from raw bytes
|
/// Import a public key from raw bytes
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
|
||||||
if bytes.len() == 64 {
|
Ok(Self(VerifyingKey::from_sec1_bytes(bytes)?))
|
||||||
Ok(Self(
|
|
||||||
VerifyingKey::from_sec1_bytes(bytes).expect("Key is of valid size"),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Err(CryptoError::InvalidKeySize)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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> {
|
pub fn verify_signature(&self, message: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
|
||||||
@ -74,3 +76,67 @@ impl PublicKey {
|
|||||||
.map_err(|_| CryptoError::SignatureFailed)
|
.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