rust_bottle/
utils.rs

1use crate::ecdh::rsa_encrypt;
2use crate::errors::{BottleError, Result};
3use rand::{CryptoRng, RngCore};
4use rsa::RsaPublicKey;
5use zeroize::Zeroize;
6
7/// Securely clear sensitive data from memory.
8///
9/// This function uses the `zeroize` crate to overwrite memory with zeros,
10/// helping to prevent sensitive data from remaining in memory after use.
11/// This is important for cryptographic keys and other sensitive material.
12///
13/// # Arguments
14///
15/// * `data` - Mutable slice of bytes to clear
16///
17/// # Example
18///
19/// ```rust
20/// use rust_bottle::utils::mem_clr;
21///
22/// let mut sensitive = vec![1, 2, 3, 4, 5];
23/// mem_clr(&mut sensitive);
24/// // sensitive is now all zeros
25/// ```
26pub fn mem_clr(data: &mut [u8]) {
27    data.zeroize();
28}
29
30/// Encrypt a short buffer (like AES keys) to a public key.
31///
32/// This function encrypts small buffers (typically 32 bytes or less, like AES keys)
33/// directly to a public key without using ECDH key exchange. This is useful for
34/// key wrapping scenarios.
35///
36/// Currently supports RSA keys only. For RSA, the plaintext must be smaller than
37/// the key size minus 42 bytes (for OAEP with SHA-256 padding).
38///
39/// # Arguments
40///
41/// * `rng` - A cryptographically secure random number generator
42/// * `plaintext` - The plaintext to encrypt (should be short, e.g., 32 bytes for AES-256 keys)
43/// * `public_key` - The recipient's public key (PKIX DER format or raw RSA public key bytes)
44///
45/// # Returns
46///
47/// * `Ok(Vec<u8>)` - Encrypted ciphertext
48/// * `Err(BottleError::UnsupportedAlgorithm)` - If the key type is not supported
49/// * `Err(BottleError::Encryption)` - If encryption fails
50///
51/// # Example
52///
53/// ```rust,no_run
54/// use rust_bottle::utils::encrypt_short_buffer;
55/// use rust_bottle::keys::RsaKey;
56/// use rust_bottle::ecdh::rsa_encrypt;
57/// use rand::rngs::OsRng;
58///
59/// let rng = &mut OsRng;
60/// let rsa_key = RsaKey::generate(rng, 2048).unwrap();
61///
62/// // Encrypt a 32-byte AES key
63/// // Note: For now, use rsa_encrypt directly with RsaPublicKey
64/// // PKIX parsing for RSA is not yet fully implemented
65/// let aes_key = vec![0u8; 32];
66/// let ciphertext = rsa_encrypt(rng, &aes_key, rsa_key.public_key()).unwrap();
67/// ```
68pub fn encrypt_short_buffer<R: RngCore + CryptoRng>(
69    rng: &mut R,
70    plaintext: &[u8],
71    public_key: &[u8],
72) -> Result<Vec<u8>> {
73    // Try to parse as PKIX (SubjectPublicKeyInfo) format
74    // Check if it looks like PKIX format (starts with DER SEQUENCE tag 0x30)
75    if !public_key.is_empty() && public_key[0] == 0x30 {
76        // Try to parse as PKIX and extract RSA public key
77        if let Ok(rsa_pub_key) = parse_rsa_public_key_from_pkix(public_key) {
78            return rsa_encrypt(rng, plaintext, &rsa_pub_key);
79        }
80    }
81
82    // Note: PKCS#1 parsing is not yet fully implemented
83    // For now, users should use rsa_encrypt directly with an RsaPublicKey reference,
84    // or provide keys in PKIX format
85
86    // If we can't parse as RSA, return unsupported
87    Err(BottleError::UnsupportedAlgorithm)
88}
89
90/// Parse RSA public key from PKIX (SubjectPublicKeyInfo) format.
91fn parse_rsa_public_key_from_pkix(der_bytes: &[u8]) -> Result<RsaPublicKey> {
92    use const_oid::db::rfc5912;
93    use der::asn1::AnyRef;
94    use der::asn1::BitString;
95    use der::Decode;
96    use spki::SubjectPublicKeyInfo;
97
98    let spki: SubjectPublicKeyInfo<AnyRef, BitString> =
99        SubjectPublicKeyInfo::from_der(der_bytes).map_err(|_| BottleError::InvalidKeyType)?;
100
101    // Check if it's an RSA key (OID 1.2.840.113549.1.1.1)
102    if spki.algorithm.oid != rfc5912::RSA_ENCRYPTION {
103        return Err(BottleError::InvalidKeyType);
104    }
105
106    // Extract the RSA public key bytes (RSAPublicKey structure)
107    let rsa_key_bytes = spki.subject_public_key.raw_bytes();
108
109    // Parse RSAPublicKey structure (SEQUENCE { n INTEGER, e INTEGER })
110    parse_rsa_public_key_pkcs1(rsa_key_bytes)
111}
112
113/// Parse RSA public key from PKCS#1 format (RSAPublicKey structure).
114///
115/// RSAPublicKey ::= SEQUENCE {
116///     modulus           INTEGER,  -- n
117///     publicExponent    INTEGER   -- e
118/// }
119///
120/// This function manually parses the DER-encoded sequence to extract
121/// the modulus (n) and public exponent (e).
122fn parse_rsa_public_key_pkcs1(der_bytes: &[u8]) -> Result<RsaPublicKey> {
123    use der::Decode;
124    use rsa::BigUint;
125
126    // Manual DER parsing of SEQUENCE { INTEGER, INTEGER }
127    // DER format: [0x30 (SEQUENCE tag)] [length] [INTEGER n] [INTEGER e]
128
129    if der_bytes.is_empty() || der_bytes[0] != 0x30 {
130        return Err(BottleError::InvalidKeyType);
131    }
132
133    // Skip SEQUENCE tag (0x30) and length byte(s)
134    let mut pos = 1;
135    if pos >= der_bytes.len() {
136        return Err(BottleError::InvalidKeyType);
137    }
138
139    // Parse length (can be short form or long form)
140    let seq_len = if (der_bytes[pos] & 0x80) == 0 {
141        // Short form: length is in the byte itself
142        let len = der_bytes[pos] as usize;
143        pos += 1;
144        len
145    } else {
146        // Long form: length is encoded in multiple bytes
147        let len_bytes = (der_bytes[pos] & 0x7f) as usize;
148        if len_bytes == 0 || len_bytes > 4 || pos + len_bytes >= der_bytes.len() {
149            return Err(BottleError::InvalidKeyType);
150        }
151        pos += 1;
152        let mut len = 0usize;
153        for i in 0..len_bytes {
154            len = (len << 8) | (der_bytes[pos + i] as usize);
155        }
156        pos += len_bytes;
157        len
158    };
159
160    if pos + seq_len > der_bytes.len() {
161        return Err(BottleError::InvalidKeyType);
162    }
163
164    // Now parse the two INTEGERs from the sequence content
165    let seq_content = &der_bytes[pos..pos + seq_len];
166
167    // Parse first INTEGER (modulus n)
168    let n_uint = der::asn1::Uint::from_der(seq_content).map_err(|_| BottleError::InvalidKeyType)?;
169
170    // Calculate offset for second integer
171    // INTEGER tag (0x02) + length + value
172    let n_len = if seq_content.is_empty() || seq_content[0] != 0x02 {
173        return Err(BottleError::InvalidKeyType);
174    } else {
175        let mut n_pos = 1;
176        if n_pos >= seq_content.len() {
177            return Err(BottleError::InvalidKeyType);
178        }
179        let n_val_len = if (seq_content[n_pos] & 0x80) == 0 {
180            let len = seq_content[n_pos] as usize;
181            n_pos += 1;
182            len
183        } else {
184            let len_bytes = (seq_content[n_pos] & 0x7f) as usize;
185            if len_bytes == 0 || len_bytes > 4 || n_pos + len_bytes >= seq_content.len() {
186                return Err(BottleError::InvalidKeyType);
187            }
188            n_pos += 1;
189            let mut len = 0usize;
190            for i in 0..len_bytes {
191                len = (len << 8) | (seq_content[n_pos + i] as usize);
192            }
193            n_pos += len_bytes;
194            len
195        };
196        n_pos + n_val_len
197    };
198
199    if n_len >= seq_content.len() {
200        return Err(BottleError::InvalidKeyType);
201    }
202
203    // Parse second INTEGER (exponent e)
204    let e_uint = der::asn1::Uint::from_der(&seq_content[n_len..])
205        .map_err(|_| BottleError::InvalidKeyType)?;
206
207    // Convert to BigUint
208    let n = BigUint::from_bytes_be(n_uint.as_bytes());
209    let e = BigUint::from_bytes_be(e_uint.as_bytes());
210
211    // Create RsaPublicKey
212    RsaPublicKey::new(n, e).map_err(|_| BottleError::InvalidKeyType)
213}
214
215/// Decrypt a short buffer using a private key.
216///
217/// # Note
218///
219/// This is a placeholder function. It will be implemented in a future release
220/// to support decrypting small buffers encrypted with `encrypt_short_buffer`.
221///
222/// # Arguments
223///
224/// * `_ciphertext` - The encrypted data
225/// * `_private_key` - The recipient's private key
226///
227/// # Returns
228///
229/// * `Err(BottleError::UnsupportedAlgorithm)` - Currently not implemented
230///
231/// # Future Implementation
232///
233/// This will support RSA decryption for short buffers when RSA support is added.
234pub fn decrypt_short_buffer(_ciphertext: &[u8], _private_key: &[u8]) -> Result<Vec<u8>> {
235    // This will be implemented based on the key type
236    // For now, placeholder
237    Err(BottleError::UnsupportedAlgorithm)
238}