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}