pub struct Crypto { /* private fields */ }Expand description
Bundle of crypto state used by a Dynomite peer instance.
Holds an RSA key pair loaded from a PEM file and a fresh 32-byte
AES session key buffer generated when the bundle is constructed.
The session key is used for symmetric encryption of DNODE
payloads (AES-128-CBC consumes the first 16 bytes; the remaining
16 bytes match the C aes_key[AES_KEYLEN] buffer layout), while
the RSA pair is used to wrap and unwrap session keys during the
handshake.
§Examples
use dynomite::crypto::Crypto;
let crypto = Crypto::from_pem("conf/dynomite.pem").unwrap();
let payload = b"sample";
let cipher = Crypto::aes_encrypt(payload, crypto.aes_key()).unwrap();
let plain = Crypto::aes_decrypt(&cipher, crypto.aes_key()).unwrap();
assert_eq!(plain, payload);Implementations§
Source§impl Crypto
impl Crypto
Sourcepub fn from_pem<P: AsRef<Path>>(path: P) -> Result<Self, CryptoError>
pub fn from_pem<P: AsRef<Path>>(path: P) -> Result<Self, CryptoError>
Construct a new bundle by loading an RSA private key from the given PEM file and generating a fresh 32-byte AES key buffer from the system CSPRNG.
AES-128-CBC consumes only the first 16 bytes of the buffer;
the trailing 16 bytes match the C aes_key[AES_KEYLEN] layout.
§Examples
use dynomite::crypto::Crypto;
let crypto = Crypto::from_pem("conf/dynomite.pem").unwrap();
assert_eq!(crypto.aes_key().len(), 32);Sourcepub fn from_parts(rsa: RsaPrivateKey, aes_key: [u8; 32]) -> Self
pub fn from_parts(rsa: RsaPrivateKey, aes_key: [u8; 32]) -> Self
Construct a bundle from an already-loaded RSA private key and a caller-supplied AES key. Used by tests and embedders that want to exercise the bundle without touching the filesystem.
§Examples
use dynomite::crypto::Crypto;
use rsa::RsaPrivateKey;
use rand::rngs::OsRng;
let aes_key = Crypto::generate_aes_key().unwrap();
let mut rng = OsRng;
let rsa = RsaPrivateKey::new(&mut rng, 2048).unwrap();
let crypto = Crypto::from_parts(rsa, aes_key);
assert_eq!(crypto.aes_key().len(), 32);Sourcepub fn generate_aes_key() -> Result<[u8; 32], CryptoError>
pub fn generate_aes_key() -> Result<[u8; 32], CryptoError>
Generate a fresh 32-byte AES key buffer from the system CSPRNG.
The returned slice is 32 random bytes. AES-128-CBC consumes
only the first 16 bytes; the trailing 16 bytes are kept to
match the C aes_key[AES_KEYLEN] buffer layout.
§Examples
use dynomite::crypto::Crypto;
let a = Crypto::generate_aes_key().unwrap();
let b = Crypto::generate_aes_key().unwrap();
assert_ne!(a, b);Sourcepub fn aes_key(&self) -> &[u8; 32]
pub fn aes_key(&self) -> &[u8; 32]
Borrow the bundle’s AES session key.
§Examples
use dynomite::crypto::Crypto;
let crypto = Crypto::from_pem("conf/dynomite.pem").unwrap();
assert_eq!(crypto.aes_key().len(), 32);Sourcepub fn rsa_private_key(&self) -> &RsaPrivateKey
pub fn rsa_private_key(&self) -> &RsaPrivateKey
Borrow the bundle’s RSA private key.
§Examples
use dynomite::crypto::Crypto;
let crypto = Crypto::from_pem("conf/dynomite.pem").unwrap();
assert!(crypto.rsa_size() > 0);Sourcepub fn rsa_size(&self) -> usize
pub fn rsa_size(&self) -> usize
Modulus size of the loaded RSA key in bytes.
§Examples
use dynomite::crypto::Crypto;
let crypto = Crypto::from_pem("conf/dynomite.pem").unwrap();
assert!(crypto.rsa_size() >= 128);Sourcepub fn aes_encrypt(
msg: &[u8],
aes_key: &[u8; 32],
) -> Result<Vec<u8>, CryptoError>
pub fn aes_encrypt( msg: &[u8], aes_key: &[u8; 32], ) -> Result<Vec<u8>, CryptoError>
AES-128-CBC encrypt msg with aes_key. The output is the
PKCS#7-padded ciphertext with no IV prefix.
§Security
- AES-128 in CBC mode with PKCS#7 padding. The cipher
consumes only the first 16 bytes of the 32-byte
aes_keybuffer. - The IV is the same 16 bytes as the key. The static IV is a known weakness of the legacy wire protocol; the Rust port faithfully reproduces it for wire compatibility. Two encryptions of the same plaintext under the same key produce identical ciphertext.
- The output is not authenticated. Integrity is provided by the surrounding DNODE message framing. Embedders that need authenticated payloads should treat this as a transport-layer encryption only and layer an AEAD on top.
§Examples
use dynomite::crypto::Crypto;
let key = Crypto::generate_aes_key().unwrap();
let cipher = Crypto::aes_encrypt(b"hi", &key).unwrap();
let plain = Crypto::aes_decrypt(&cipher, &key).unwrap();
assert_eq!(plain, b"hi");Sourcepub fn aes_decrypt(
enc: &[u8],
aes_key: &[u8; 32],
) -> Result<Vec<u8>, CryptoError>
pub fn aes_decrypt( enc: &[u8], aes_key: &[u8; 32], ) -> Result<Vec<u8>, CryptoError>
AES-128-CBC decrypt the output of Crypto::aes_encrypt.
enc must be a non-empty integral number of 16-byte
ciphertext blocks. There is no IV prefix; the IV is derived
from aes_key exactly as on the encryption side.
§Examples
use dynomite::crypto::Crypto;
let key = Crypto::generate_aes_key().unwrap();
let cipher = Crypto::aes_encrypt(b"hello", &key).unwrap();
let plain = Crypto::aes_decrypt(&cipher, &key).unwrap();
assert_eq!(plain, b"hello");Sourcepub fn dyn_aes_encrypt(
msg: &[u8],
aes_key: &[u8; 32],
pool: &MbufPool,
) -> Result<MbufQueue, CryptoError>
pub fn dyn_aes_encrypt( msg: &[u8], aes_key: &[u8; 32], pool: &MbufPool, ) -> Result<MbufQueue, CryptoError>
AES-128-CBC encrypt msg, writing the result into a fresh
MbufQueue drawn from pool. The chain holds the raw
ciphertext; there is no IV prefix. Output spans as many
chunks as needed; each chunk is filled up to the writable
region before allocating the next one.
§Examples
use dynomite::crypto::Crypto;
use dynomite::io::mbuf::MbufPool;
let pool = MbufPool::default();
let key = Crypto::generate_aes_key().unwrap();
let mut chain = Crypto::dyn_aes_encrypt(b"hello", &key, &pool).unwrap();
let plain = Crypto::dyn_aes_decrypt_to_vec(&mut chain, &key).unwrap();
assert_eq!(plain, b"hello");Sourcepub fn dyn_aes_decrypt(
enc: &mut MbufQueue,
aes_key: &[u8; 32],
pool: &MbufPool,
) -> Result<MbufQueue, CryptoError>
pub fn dyn_aes_decrypt( enc: &mut MbufQueue, aes_key: &[u8; 32], pool: &MbufPool, ) -> Result<MbufQueue, CryptoError>
AES-128-CBC decrypt a ciphertext chain produced by
Crypto::dyn_aes_encrypt, appending the recovered plaintext
to a fresh MbufQueue drawn from pool.
enc is consumed: chunks are popped off the front and pushed
to the pool free list as they are drained.
§Examples
use dynomite::crypto::Crypto;
use dynomite::io::mbuf::MbufPool;
let pool = MbufPool::default();
let key = Crypto::generate_aes_key().unwrap();
let mut chain = Crypto::dyn_aes_encrypt(b"abc", &key, &pool).unwrap();
let mut plain_chain = Crypto::dyn_aes_decrypt(&mut chain, &key, &pool).unwrap();
assert_eq!(plain_chain.total_len(), 3);Sourcepub fn dyn_aes_decrypt_to_vec(
enc: &mut MbufQueue,
aes_key: &[u8; 32],
) -> Result<Vec<u8>, CryptoError>
pub fn dyn_aes_decrypt_to_vec( enc: &mut MbufQueue, aes_key: &[u8; 32], ) -> Result<Vec<u8>, CryptoError>
Convenience wrapper that decrypts a ciphertext chain into a
flat Vec<u8>. Useful for tests and protocol code that needs
the cleartext as a single buffer.
§Examples
use dynomite::crypto::Crypto;
use dynomite::io::mbuf::MbufPool;
let pool = MbufPool::default();
let key = Crypto::generate_aes_key().unwrap();
let mut chain = Crypto::dyn_aes_encrypt(b"hello", &key, &pool).unwrap();
let plain = Crypto::dyn_aes_decrypt_to_vec(&mut chain, &key).unwrap();
assert_eq!(plain, b"hello");Sourcepub fn dyn_aes_encrypt_msg(
msg: &Mbuf,
aes_key: &[u8; 32],
pool: &MbufPool,
) -> Result<(MbufQueue, usize), CryptoError>
pub fn dyn_aes_encrypt_msg( msg: &Mbuf, aes_key: &[u8; 32], pool: &MbufPool, ) -> Result<(MbufQueue, usize), CryptoError>
AES-128-CBC encrypt the readable region of msg, returning a
new chain holding the ciphertext along with the total number
of ciphertext bytes written.
The handshake encodes its own framing on top of the returned chain, so the output count is reported separately rather than derived from the queue.
§Examples
use dynomite::crypto::Crypto;
use dynomite::io::mbuf::{Mbuf, MbufPool};
let pool = MbufPool::default();
let key = Crypto::generate_aes_key().unwrap();
let mut buf = pool.get();
buf.recv(b"payload");
let (mut chain, n) = Crypto::dyn_aes_encrypt_msg(&buf, &key, &pool).unwrap();
assert!(n > 0);
let plain = Crypto::dyn_aes_decrypt_to_vec(&mut chain, &key).unwrap();
assert_eq!(plain, b"payload");Sourcepub fn rsa_encrypt(&self, msg: &[u8]) -> Result<Vec<u8>, CryptoError>
pub fn rsa_encrypt(&self, msg: &[u8]) -> Result<Vec<u8>, CryptoError>
RSA encrypt msg with the bundle’s public key using PKCS#1
OAEP padding (with the OpenSSL default SHA-1 hash and MGF1).
The output length is the RSA modulus size in bytes (typically
128 for 1024-bit keys, 256 for 2048-bit).
§Examples
use dynomite::crypto::Crypto;
let crypto = Crypto::from_pem("conf/dynomite.pem").unwrap();
let key = Crypto::generate_aes_key().unwrap();
let wrapped = crypto.rsa_encrypt(&key).unwrap();
let unwrapped = crypto.rsa_decrypt(&wrapped).unwrap();
assert_eq!(unwrapped, key);Sourcepub fn rsa_decrypt(&self, enc: &[u8]) -> Result<Vec<u8>, CryptoError>
pub fn rsa_decrypt(&self, enc: &[u8]) -> Result<Vec<u8>, CryptoError>
RSA decrypt enc with the bundle’s private key using PKCS#1
OAEP padding (with the OpenSSL default SHA-1 hash and MGF1).
§Examples
use dynomite::crypto::Crypto;
let crypto = Crypto::from_pem("conf/dynomite.pem").unwrap();
let key = Crypto::generate_aes_key().unwrap();
let wrapped = crypto.rsa_encrypt(&key).unwrap();
let unwrapped = crypto.rsa_decrypt(&wrapped).unwrap();
assert_eq!(unwrapped, key);