Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: protect cryptographic material in memory #109

Open
aestgar62 opened this issue Oct 9, 2023 · 0 comments
Open

fix: protect cryptographic material in memory #109

aestgar62 opened this issue Oct 9, 2023 · 0 comments

Comments

@aestgar62
Copy link

This fix proposes changing the BaseKeyPair object so that instead of having an option to the PrivateKey, it has as an option an encryptor object that encrypts the secret key in memory when creating the key pair and decrypts it on demand when signing is needed.
We can use the memsec crate, which implements the same functions as the OpenSSH libsodium library, and enforce our encryptor based on an efficient symmetric algorithm (with chacha20poly1305), or use the memsecurity crate that has already implemented it. I attach a proof of concept with memsecurity.

Example BaseKeyPair:

use memsecurity::EncryptedMem;

/// Base key pair.
///
/// This type contains the public key and some `EncryptedMem` object with the
/// secret key or none.
///
pub struct BaseKeyPair<K> {
    pub public: K,
    pub secret: Option<EncryptedMem>,
}

Example type ed25519:

/// Ed25519 key pair.
pub type Ed25519KeyPair = BaseKeyPair<VerifyingKey>;

Example build from secret bytes:

    fn from_secret(secret: &[u8]) -> Result<Self, Error>
    where
        Self: Sized,
    {
        let mut encrytion = EncryptedMem::new();
        let sk = SigningKey::try_from(secret)
            .map_err(|_| Error::KeyPair("Ed25519".to_owned(), "geting SigningKey".to_owned()))?;
        let public_key = VerifyingKey::from(&sk);
        encrytion
            .encrypt(&sk.to_bytes())
            .map_err(|_| Error::KeyPair("Ed25519".to_owned(), "mem encryption".to_owned()))?;
        Ok(Ed25519KeyPair {
            public: public_key,
            secret: Some(encrytion),
        })
    }

Example sign:

    fn sign(&mut self, message: &[u8]) -> Result<Vec<u8>, Error> {
        let encr = self.secret.as_ref().ok_or(Error::KeyPair(
            "Ed25519".to_owned(),
            "secret not found".to_owned(),
        ))?;
        let sk = encr
            .decrypt()
            .map_err(|_| Error::KeyPair("Ed25519".to_owned(), "mem decryption".to_owned()))?;

        let signing_key = SigningKey::try_from(sk.as_ref()).map_err(|_| {
            Error::KeyPair("Ed25519".to_owned(), "SigningKey from slice".to_owned())
        })?;
        let signature = signing_key.sign(message);
        Ok(signature.to_bytes().to_vec())
    }
}

The verification would remain the same as before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant