Search code examples
rustprivate-keypublic-keyecdsa

How can I export (to store) an ecdsa key pair in Rust?


I am able to create a public/private ecdsa key in Rust, how can I store the keys for further use? I can't seem to find a method that will export the key.

use p256::{ecdsa::{SigningKey, Signature, signature::Signer}};
use rand_core::OsRng; // requires 'getrandom' feature

fn main() {
    // Signing
    let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()`
    let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
    let signature = signing_key.sign(message);


    // Verification
    use p256::ecdsa::{VerifyingKey, signature::Verifier};

    let verifying_key = VerifyingKey::from(&signing_key); // Serialize with `::to_encoded_point()`
    assert!(verifying_key.verify(message, &signature).is_ok());
}

Solution

  • There are many different ways to represent keys. Internally, it's a byte array that can be dumped as such directly. But for compatibility, you probably want a more standardized, human readable format.

    The most common one is the PEM format.

    To get a PEM, you cannot construct SigningKey and VerifyingKey directly. You need to create a SecretKey and a PublicKey. They can be stored and loaded to/from the PEM format.

    You can then convert the SecretKey to a SigningKey and the PublicKey to a VerifyingKey.

    Be aware that you need to enable the pem feature for the p256 dependency:

    p256 = { version = "0.11", features = ["pem"] }
    
    use p256::{
        ecdsa::{
            signature::{Signer, Verifier},
            SigningKey, VerifyingKey,
        },
        pkcs8::EncodePrivateKey,
        PublicKey, SecretKey,
    };
    use rand_core::OsRng;
    
    fn main() {
        // Generate secret key
        let secret_key = SecretKey::random(&mut OsRng);
    
        // Store secret key
        let secret_key_serialized = secret_key
            .to_pkcs8_pem(Default::default())
            .unwrap()
            .to_string();
        println!("Secret Key: \n{}", secret_key_serialized);
    
        // Load secret key
        let secret_key = secret_key_serialized.parse::<SecretKey>().unwrap();
    
        // Derive public key
        let public_key = secret_key.public_key();
    
        // Store public key
        let public_key_serialized = public_key.to_string();
        println!("Public Key: \n{}", public_key_serialized);
    
        // Load public key
        let public_key = public_key_serialized.parse::<PublicKey>().unwrap();
    
        // Signing
        let signing_key: SigningKey = secret_key.into();
        let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
        let signature = signing_key.sign(message);
    
        // Verification
        let verifying_key: VerifyingKey = public_key.into();
        assert!(verifying_key.verify(message, &signature).is_ok());
    }
    
    Secret Key: 
    -----BEGIN PRIVATE KEY-----
    MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQguKslF8gIC/Fm36Yk
    SK2qZ4MXbUg/ZwCJwY9OmzRzkOehRANCAAQrRw99abOvHAPdz79CkuihXfaKZqx+
    ZUG6iQRDzZy0c+gw20KeevA4gXKnW0nFK8PDmOgBprCU/uHf4vpMbqgo
    -----END PRIVATE KEY-----
    
    Public Key: 
    -----BEGIN PUBLIC KEY-----
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEK0cPfWmzrxwD3c+/QpLooV32imas
    fmVBuokEQ82ctHPoMNtCnnrwOIFyp1tJxSvDw5joAaawlP7h3+L6TG6oKA==
    -----END PUBLIC KEY-----