Add tests for asymmetric keys, add public key export
Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
		@@ -1,10 +1,7 @@
 | 
			
		||||
//! An implementation of asymmetric cryptography using SECP256k1 ECDH with ChaCha20Poly1305
 | 
			
		||||
//! for the actual encryption.
 | 
			
		||||
 | 
			
		||||
use k256::{
 | 
			
		||||
    SecretKey,
 | 
			
		||||
    ecdh::diffie_hellman,
 | 
			
		||||
};
 | 
			
		||||
use k256::{SecretKey, ecdh::diffie_hellman, elliptic_curve::sec1::ToEncodedPoint};
 | 
			
		||||
use sha2::Sha256;
 | 
			
		||||
 | 
			
		||||
use crate::{error::CryptoError, key::symmetric::SymmetricKey};
 | 
			
		||||
@@ -18,6 +15,7 @@ pub struct AsymmetricKeypair {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The public key part of an asymmetric keypair.
 | 
			
		||||
#[derive(Debug, PartialEq, Eq)]
 | 
			
		||||
pub struct PublicKey(k256::PublicKey);
 | 
			
		||||
 | 
			
		||||
impl AsymmetricKeypair {
 | 
			
		||||
@@ -101,12 +99,63 @@ impl AsymmetricKeypair {
 | 
			
		||||
impl PublicKey {
 | 
			
		||||
    /// Import a public key from raw bytes
 | 
			
		||||
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
 | 
			
		||||
        if bytes.len() == 64 {
 | 
			
		||||
            Ok(Self(
 | 
			
		||||
                k256::PublicKey::from_sec1_bytes(bytes).expect("Key is of valid size"),
 | 
			
		||||
            ))
 | 
			
		||||
        } else {
 | 
			
		||||
            Err(CryptoError::InvalidKeySize)
 | 
			
		||||
        }
 | 
			
		||||
        Ok(Self(k256::PublicKey::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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    /// Export a public key and import it later
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn import_public_key() {
 | 
			
		||||
        let kp = super::AsymmetricKeypair::new().expect("Can generate new keypair");
 | 
			
		||||
        let pk1 = kp.public_key();
 | 
			
		||||
        let pk_bytes = pk1.as_bytes();
 | 
			
		||||
        let pk2 = super::PublicKey::from_bytes(&pk_bytes).expect("Can import public key");
 | 
			
		||||
 | 
			
		||||
        assert_eq!(pk1, pk2);
 | 
			
		||||
    }
 | 
			
		||||
    /// Make sure 2 random keypairs derive the same shared secret (and thus encryption key), by
 | 
			
		||||
    /// encrypting a random message, decrypting it, and verifying it matches.
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn encrypt_and_decrypt() {
 | 
			
		||||
        let kp1 = super::AsymmetricKeypair::new().expect("Can generate new keypair");
 | 
			
		||||
        let kp2 = super::AsymmetricKeypair::new().expect("Can generate new keypair");
 | 
			
		||||
 | 
			
		||||
        let pk1 = kp1.public_key();
 | 
			
		||||
        let pk2 = kp2.public_key();
 | 
			
		||||
 | 
			
		||||
        let message = b"this is a random message to encrypt and decrypt";
 | 
			
		||||
 | 
			
		||||
        let enc = kp1.encrypt(&pk2, message).expect("Can encrypt message");
 | 
			
		||||
        let dec = kp2.decrypt(&pk1, &enc).expect("Can decrypt message");
 | 
			
		||||
 | 
			
		||||
        assert_eq!(message.as_slice(), dec.as_slice());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Use a different public key for decrypting than the expected one, this should fail the
 | 
			
		||||
    /// decryption process as we use AEAD encryption with the symmetric key.
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn decrypt_with_wrong_key() {
 | 
			
		||||
        let kp1 = super::AsymmetricKeypair::new().expect("Can generate new keypair");
 | 
			
		||||
        let kp2 = super::AsymmetricKeypair::new().expect("Can generate new keypair");
 | 
			
		||||
        let kp3 = super::AsymmetricKeypair::new().expect("Can generate new keypair");
 | 
			
		||||
 | 
			
		||||
        let pk2 = kp2.public_key();
 | 
			
		||||
        let pk3 = kp3.public_key();
 | 
			
		||||
 | 
			
		||||
        let message = b"this is a random message to encrypt and decrypt";
 | 
			
		||||
 | 
			
		||||
        let enc = kp1.encrypt(&pk2, message).expect("Can encrypt message");
 | 
			
		||||
        let dec = kp2.decrypt(&pk3, &enc);
 | 
			
		||||
 | 
			
		||||
        assert!(dec.is_err());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -69,8 +69,8 @@ impl SymmetricKey {
 | 
			
		||||
 | 
			
		||||
        // Extract nonce from the end of ciphertext
 | 
			
		||||
        let ciphertext_len = ciphertext.len() - NONCE_SIZE;
 | 
			
		||||
        let ciphertext = &ciphertext[0..ciphertext_len];
 | 
			
		||||
        let nonce_bytes = &ciphertext[ciphertext_len..];
 | 
			
		||||
        let ciphertext = &ciphertext[0..ciphertext_len];
 | 
			
		||||
 | 
			
		||||
        // Create cipher
 | 
			
		||||
        let cipher = ChaCha20Poly1305::new_from_slice(&self.0)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user