blob: f8fc5741013536e025e40e99fe66b6b863dabee8 [file] [log] [blame]
Joel Galensonca0efb12020-10-01 14:32:30 -07001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Janis Danisevskis9d90b812020-11-25 21:02:11 -080015//! This module implements safe wrappers for some crypto operations required by
16//! Keystore 2.0.
17
18mod error;
Janis Danisevskisa16ddf32021-10-20 09:40:02 -070019pub mod zvec;
Janis Danisevskis9d90b812020-11-25 21:02:11 -080020pub use error::Error;
21use keystore2_crypto_bindgen::{
David Drysdalec97eb9e2022-01-26 13:03:48 -080022 extractSubjectFromCertificate, generateKeyFromPassword, hmacSha256, randomBytes,
23 AES_gcm_decrypt, AES_gcm_encrypt, ECDHComputeKey, ECKEYGenerateKey, ECKEYMarshalPrivateKey,
Paul Crowley7bb5edd2021-03-20 20:26:43 -070024 ECKEYParsePrivateKey, ECPOINTOct2Point, ECPOINTPoint2Oct, EC_KEY_free, EC_KEY_get0_public_key,
25 EC_POINT_free, HKDFExpand, HKDFExtract, EC_KEY, EC_MAX_BYTES, EC_POINT, EVP_MAX_MD_SIZE,
Janis Danisevskis9d90b812020-11-25 21:02:11 -080026};
Shawn Willden8fde4c22021-02-14 13:58:22 -070027use std::convert::TryFrom;
Joel Galenson05914582021-01-08 09:30:41 -080028use std::convert::TryInto;
29use std::marker::PhantomData;
Janis Danisevskis9d90b812020-11-25 21:02:11 -080030pub use zvec::ZVec;
31
32/// Length of the expected initialization vector.
Paul Crowley9a7f5a52021-04-23 16:12:08 -070033pub const GCM_IV_LENGTH: usize = 12;
Janis Danisevskis9d90b812020-11-25 21:02:11 -080034/// Length of the expected AEAD TAG.
35pub const TAG_LENGTH: usize = 16;
36/// Length of an AES 256 key in bytes.
37pub const AES_256_KEY_LENGTH: usize = 32;
38/// Length of an AES 128 key in bytes.
39pub const AES_128_KEY_LENGTH: usize = 16;
40/// Length of the expected salt for key from password generation.
41pub const SALT_LENGTH: usize = 16;
David Drysdalec97eb9e2022-01-26 13:03:48 -080042/// Length of an HMAC-SHA256 tag in bytes.
43pub const HMAC_SHA256_LEN: usize = 32;
Janis Danisevskis9d90b812020-11-25 21:02:11 -080044
Paul Crowley9a7f5a52021-04-23 16:12:08 -070045/// Older versions of keystore produced IVs with four extra
46/// ignored zero bytes at the end; recognise and trim those.
47pub const LEGACY_IV_LENGTH: usize = 16;
Janis Danisevskis9d90b812020-11-25 21:02:11 -080048
49/// Generate an AES256 key, essentially 32 random bytes from the underlying
50/// boringssl library discretely stuffed into a ZVec.
51pub fn generate_aes256_key() -> Result<ZVec, Error> {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080052 let mut key = ZVec::new(AES_256_KEY_LENGTH)?;
Andrew Walbrana47698a2023-07-21 17:23:56 +010053 // Safety: key has the same length as the requested number of random bytes.
Joel Galenson05914582021-01-08 09:30:41 -080054 if unsafe { randomBytes(key.as_mut_ptr(), AES_256_KEY_LENGTH) } {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080055 Ok(key)
56 } else {
57 Err(Error::RandomNumberGenerationFailed)
58 }
59}
60
61/// Generate a salt.
62pub fn generate_salt() -> Result<Vec<u8>, Error> {
David Drysdale0e45a612021-02-25 17:24:36 +000063 generate_random_data(SALT_LENGTH)
64}
65
66/// Generate random data of the given size.
67pub fn generate_random_data(size: usize) -> Result<Vec<u8>, Error> {
David Drysdale0e45a612021-02-25 17:24:36 +000068 let mut data = vec![0; size];
Andrew Walbrana47698a2023-07-21 17:23:56 +010069 // Safety: data has the same length as the requested number of random bytes.
David Drysdale0e45a612021-02-25 17:24:36 +000070 if unsafe { randomBytes(data.as_mut_ptr(), size) } {
71 Ok(data)
Janis Danisevskis9d90b812020-11-25 21:02:11 -080072 } else {
73 Err(Error::RandomNumberGenerationFailed)
74 }
75}
76
David Drysdalec97eb9e2022-01-26 13:03:48 -080077/// Perform HMAC-SHA256.
78pub fn hmac_sha256(key: &[u8], msg: &[u8]) -> Result<Vec<u8>, Error> {
79 let mut tag = vec![0; HMAC_SHA256_LEN];
80 // Safety: The first two pairs of arguments must point to const buffers with
81 // size given by the second arg of the pair. The final pair of arguments
82 // must point to an output buffer with size given by the second arg of the
83 // pair.
84 match unsafe {
85 hmacSha256(key.as_ptr(), key.len(), msg.as_ptr(), msg.len(), tag.as_mut_ptr(), tag.len())
86 } {
87 true => Ok(tag),
88 false => Err(Error::HmacSha256Failed),
89 }
90}
91
Janis Danisevskis9d90b812020-11-25 21:02:11 -080092/// Uses AES GCM to decipher a message given an initialization vector, aead tag, and key.
93/// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based
94/// on the key length.
95/// This function returns the plaintext message in a ZVec because it is assumed that
96/// it contains sensitive information that should be zeroed from memory before its buffer is
97/// freed. Input key is taken as a slice for flexibility, but it is recommended that it is held
98/// in a ZVec as well.
99pub fn aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error> {
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700100 // Old versions of aes_gcm_encrypt produced 16 byte IVs, but the last four bytes were ignored
101 // so trim these to the correct size.
102 let iv = match iv.len() {
103 GCM_IV_LENGTH => iv,
104 LEGACY_IV_LENGTH => &iv[..GCM_IV_LENGTH],
105 _ => return Err(Error::InvalidIvLength),
106 };
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800107 if tag.len() != TAG_LENGTH {
108 return Err(Error::InvalidAeadTagLength);
109 }
110
111 match key.len() {
112 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
113 _ => return Err(Error::InvalidKeyLength),
114 }
115
116 let mut result = ZVec::new(data.len())?;
117
118 // Safety: The first two arguments must point to buffers with a size given by the third
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700119 // argument. We pass the length of the key buffer along with the key.
120 // The `iv` buffer must be 12 bytes and the `tag` buffer 16, which we check above.
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800121 match unsafe {
122 AES_gcm_decrypt(
123 data.as_ptr(),
124 result.as_mut_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800125 data.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800126 key.as_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800127 key.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800128 iv.as_ptr(),
129 tag.as_ptr(),
130 )
131 } {
132 true => Ok(result),
133 false => Err(Error::DecryptionFailed),
134 }
135}
136
137/// Uses AES GCM to encrypt a message given a key.
138/// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based on
139/// the key length. The function generates an initialization vector. The return value is a tuple
140/// of `(ciphertext, iv, tag)`.
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700141pub fn aes_gcm_encrypt(plaintext: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Error> {
142 let mut iv = vec![0; GCM_IV_LENGTH];
143 // Safety: iv is GCM_IV_LENGTH bytes long.
Joel Galenson05914582021-01-08 09:30:41 -0800144 if !unsafe { randomBytes(iv.as_mut_ptr(), GCM_IV_LENGTH) } {
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800145 return Err(Error::RandomNumberGenerationFailed);
146 }
147
148 match key.len() {
149 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
150 _ => return Err(Error::InvalidKeyLength),
151 }
152
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700153 let mut ciphertext: Vec<u8> = vec![0; plaintext.len()];
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800154 let mut tag: Vec<u8> = vec![0; TAG_LENGTH];
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700155 // Safety: The first two arguments must point to buffers with a size given by the third
156 // argument. We pass the length of the key buffer along with the key.
157 // The `iv` buffer must be 12 bytes and the `tag` buffer 16, which we check above.
158 if unsafe {
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800159 AES_gcm_encrypt(
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700160 plaintext.as_ptr(),
161 ciphertext.as_mut_ptr(),
162 plaintext.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800163 key.as_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800164 key.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800165 iv.as_ptr(),
166 tag.as_mut_ptr(),
167 )
168 } {
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700169 Ok((ciphertext, iv, tag))
170 } else {
171 Err(Error::EncryptionFailed)
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800172 }
173}
174
Paul Crowleyf61fee72021-03-17 14:38:44 -0700175/// Represents a "password" that can be used to key the PBKDF2 algorithm.
176pub enum Password<'a> {
177 /// Borrow an existing byte array
178 Ref(&'a [u8]),
179 /// Use an owned ZVec to store the key
180 Owned(ZVec),
181}
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800182
Paul Crowleyf61fee72021-03-17 14:38:44 -0700183impl<'a> From<&'a [u8]> for Password<'a> {
184 fn from(pw: &'a [u8]) -> Self {
185 Self::Ref(pw)
186 }
187}
188
189impl<'a> Password<'a> {
190 fn get_key(&'a self) -> &'a [u8] {
191 match self {
192 Self::Ref(b) => b,
Chris Wailes263de9f2022-08-11 15:00:51 -0700193 Self::Owned(z) => z,
Paul Crowleyf61fee72021-03-17 14:38:44 -0700194 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800195 }
196
Paul Crowleyf61fee72021-03-17 14:38:44 -0700197 /// Generate a key from the given password and salt.
198 /// The salt must be exactly 16 bytes long.
199 /// Two key sizes are accepted: 16 and 32 bytes.
David Drysdale6a0ec2c2022-04-19 08:11:18 +0100200 pub fn derive_key(&self, salt: &[u8], key_length: usize) -> Result<ZVec, Error> {
201 if salt.len() != SALT_LENGTH {
202 return Err(Error::InvalidSaltLength);
203 }
Paul Crowleyf61fee72021-03-17 14:38:44 -0700204 match key_length {
205 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
206 _ => return Err(Error::InvalidKeyLength),
207 }
208
David Drysdale6a0ec2c2022-04-19 08:11:18 +0100209 let pw = self.get_key();
Paul Crowleyf61fee72021-03-17 14:38:44 -0700210 let mut result = ZVec::new(key_length)?;
211
Andrew Walbrana47698a2023-07-21 17:23:56 +0100212 // Safety: We checked that the salt is exactly 16 bytes long. The other pointers are valid,
213 // and have matching lengths.
Paul Crowleyf61fee72021-03-17 14:38:44 -0700214 unsafe {
215 generateKeyFromPassword(
216 result.as_mut_ptr(),
217 result.len(),
218 pw.as_ptr() as *const std::os::raw::c_char,
219 pw.len(),
David Drysdale6a0ec2c2022-04-19 08:11:18 +0100220 salt.as_ptr(),
Paul Crowleyf61fee72021-03-17 14:38:44 -0700221 )
222 };
223
224 Ok(result)
225 }
226
227 /// Try to make another Password object with the same data.
228 pub fn try_clone(&self) -> Result<Password<'static>, Error> {
229 Ok(Password::Owned(ZVec::try_from(self.get_key())?))
230 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800231}
Joel Galenson46d6fd02020-11-19 17:58:33 -0800232
Joel Galenson05914582021-01-08 09:30:41 -0800233/// Calls the boringssl HKDF_extract function.
234pub fn hkdf_extract(secret: &[u8], salt: &[u8]) -> Result<ZVec, Error> {
235 let max_size: usize = EVP_MAX_MD_SIZE.try_into().unwrap();
236 let mut buf = ZVec::new(max_size)?;
237 let mut out_len = 0;
238 // Safety: HKDF_extract writes at most EVP_MAX_MD_SIZE bytes.
239 // Secret and salt point to valid buffers.
240 let result = unsafe {
241 HKDFExtract(
242 buf.as_mut_ptr(),
243 &mut out_len,
244 secret.as_ptr(),
245 secret.len(),
246 salt.as_ptr(),
247 salt.len(),
248 )
249 };
250 if !result {
251 return Err(Error::HKDFExtractFailed);
252 }
253 // According to the boringssl API, this should never happen.
254 if out_len > max_size {
255 return Err(Error::HKDFExtractFailed);
256 }
257 // HKDF_extract may write fewer than the maximum number of bytes, so we
258 // truncate the buffer.
259 buf.reduce_len(out_len);
260 Ok(buf)
261}
262
263/// Calls the boringssl HKDF_expand function.
264pub fn hkdf_expand(out_len: usize, prk: &[u8], info: &[u8]) -> Result<ZVec, Error> {
265 let mut buf = ZVec::new(out_len)?;
266 // Safety: HKDF_expand writes out_len bytes to the buffer.
267 // prk and info are valid buffers.
268 let result = unsafe {
269 HKDFExpand(buf.as_mut_ptr(), out_len, prk.as_ptr(), prk.len(), info.as_ptr(), info.len())
270 };
271 if !result {
272 return Err(Error::HKDFExpandFailed);
273 }
274 Ok(buf)
275}
276
277/// A wrapper around the boringssl EC_KEY type that frees it on drop.
278pub struct ECKey(*mut EC_KEY);
279
280impl Drop for ECKey {
281 fn drop(&mut self) {
282 // Safety: We only create ECKey objects for valid EC_KEYs
283 // and they are the sole owners of those keys.
284 unsafe { EC_KEY_free(self.0) };
285 }
286}
287
288// Wrappers around the boringssl EC_POINT type.
289// The EC_POINT can either be owned (and therefore mutable) or a pointer to an
290// EC_POINT owned by someone else (and thus immutable). The former are freed
291// on drop.
292
293/// An owned EC_POINT object.
294pub struct OwnedECPoint(*mut EC_POINT);
295
296/// A pointer to an EC_POINT object.
297pub struct BorrowedECPoint<'a> {
298 data: *const EC_POINT,
299 phantom: PhantomData<&'a EC_POINT>,
300}
301
302impl OwnedECPoint {
303 /// Get the wrapped EC_POINT object.
304 pub fn get_point(&self) -> &EC_POINT {
305 // Safety: We only create OwnedECPoint objects for valid EC_POINTs.
306 unsafe { self.0.as_ref().unwrap() }
307 }
308}
309
310impl<'a> BorrowedECPoint<'a> {
311 /// Get the wrapped EC_POINT object.
312 pub fn get_point(&self) -> &EC_POINT {
313 // Safety: We only create BorrowedECPoint objects for valid EC_POINTs.
314 unsafe { self.data.as_ref().unwrap() }
315 }
316}
317
318impl Drop for OwnedECPoint {
319 fn drop(&mut self) {
320 // Safety: We only create OwnedECPoint objects for valid
321 // EC_POINTs and they are the sole owners of those points.
322 unsafe { EC_POINT_free(self.0) };
323 }
324}
325
326/// Calls the boringssl ECDH_compute_key function.
327pub fn ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error> {
328 let mut buf = ZVec::new(EC_MAX_BYTES)?;
Andrew Walbrana47698a2023-07-21 17:23:56 +0100329 let result =
Joel Galenson05914582021-01-08 09:30:41 -0800330 // Safety: Our ECDHComputeKey wrapper passes EC_MAX_BYES to ECDH_compute_key, which
331 // writes at most that many bytes to the output.
332 // The two keys are valid objects.
Joel Galenson05914582021-01-08 09:30:41 -0800333 unsafe { ECDHComputeKey(buf.as_mut_ptr() as *mut std::ffi::c_void, pub_key, priv_key.0) };
334 if result == -1 {
335 return Err(Error::ECDHComputeKeyFailed);
336 }
337 let out_len = result.try_into().unwrap();
338 // According to the boringssl API, this should never happen.
339 if out_len > buf.len() {
340 return Err(Error::ECDHComputeKeyFailed);
341 }
342 // ECDH_compute_key may write fewer than the maximum number of bytes, so we
343 // truncate the buffer.
344 buf.reduce_len(out_len);
345 Ok(buf)
346}
347
348/// Calls the boringssl EC_KEY_generate_key function.
349pub fn ec_key_generate_key() -> Result<ECKey, Error> {
350 // Safety: Creates a new key on its own.
351 let key = unsafe { ECKEYGenerateKey() };
352 if key.is_null() {
353 return Err(Error::ECKEYGenerateKeyFailed);
354 }
355 Ok(ECKey(key))
356}
357
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700358/// Calls the boringssl EC_KEY_marshal_private_key function.
359pub fn ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error> {
Paul Crowley52f017f2021-06-22 08:16:01 -0700360 let len = 73; // Empirically observed length of private key
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700361 let mut buf = ZVec::new(len)?;
362 // Safety: the key is valid.
363 // This will not write past the specified length of the buffer; if the
364 // len above is too short, it returns 0.
Charisee03e00842023-01-25 01:41:23 +0000365 let written_len = unsafe { ECKEYMarshalPrivateKey(key.0, buf.as_mut_ptr(), buf.len()) };
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700366 if written_len == len {
367 Ok(buf)
368 } else {
369 Err(Error::ECKEYMarshalPrivateKeyFailed)
Joel Galenson05914582021-01-08 09:30:41 -0800370 }
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700371}
372
373/// Calls the boringssl EC_KEY_parse_private_key function.
374pub fn ec_key_parse_private_key(buf: &[u8]) -> Result<ECKey, Error> {
375 // Safety: this will not read past the specified length of the buffer.
376 // It fails if less than the whole buffer is consumed.
377 let key = unsafe { ECKEYParsePrivateKey(buf.as_ptr(), buf.len()) };
378 if key.is_null() {
379 Err(Error::ECKEYParsePrivateKeyFailed)
380 } else {
381 Ok(ECKey(key))
382 }
Joel Galenson05914582021-01-08 09:30:41 -0800383}
384
385/// Calls the boringssl EC_KEY_get0_public_key function.
386pub fn ec_key_get0_public_key(key: &ECKey) -> BorrowedECPoint {
387 // Safety: The key is valid.
388 // This returns a pointer to a key, so we create an immutable variant.
389 BorrowedECPoint { data: unsafe { EC_KEY_get0_public_key(key.0) }, phantom: PhantomData }
390}
391
392/// Calls the boringssl EC_POINT_point2oct.
393pub fn ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error> {
Paul Crowley52f017f2021-06-22 08:16:01 -0700394 // We fix the length to 133 (1 + 2 * field_elem_size), as we get an error if it's too small.
395 let len = 133;
Joel Galenson05914582021-01-08 09:30:41 -0800396 let mut buf = vec![0; len];
397 // Safety: EC_POINT_point2oct writes at most len bytes. The point is valid.
398 let result = unsafe { ECPOINTPoint2Oct(point, buf.as_mut_ptr(), len) };
399 if result == 0 {
400 return Err(Error::ECPoint2OctFailed);
401 }
402 // According to the boringssl API, this should never happen.
403 if result > len {
404 return Err(Error::ECPoint2OctFailed);
405 }
406 buf.resize(result, 0);
407 Ok(buf)
408}
409
410/// Calls the boringssl EC_POINT_oct2point function.
411pub fn ec_point_oct_to_point(buf: &[u8]) -> Result<OwnedECPoint, Error> {
412 // Safety: The buffer is valid.
413 let result = unsafe { ECPOINTOct2Point(buf.as_ptr(), buf.len()) };
414 if result.is_null() {
415 return Err(Error::ECPoint2OctFailed);
416 }
417 // Our C wrapper creates a new EC_POINT, so we mark this mutable and free
418 // it on drop.
419 Ok(OwnedECPoint(result))
420}
421
Shawn Willden34120872021-02-24 21:56:30 -0700422/// Uses BoringSSL to extract the DER-encoded subject from a DER-encoded X.509 certificate.
423pub fn parse_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error> {
Shawn Willden8fde4c22021-02-14 13:58:22 -0700424 // Try with a 200-byte output buffer, should be enough in all but bizarre cases.
425 let mut retval = vec![0; 200];
Shawn Willden34120872021-02-24 21:56:30 -0700426
427 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf and
428 // writes at most retval.len() bytes to retval.
Shawn Willden8fde4c22021-02-14 13:58:22 -0700429 let mut size = unsafe {
430 extractSubjectFromCertificate(
431 cert_buf.as_ptr(),
432 cert_buf.len(),
433 retval.as_mut_ptr(),
434 retval.len(),
435 )
436 };
437
438 if size == 0 {
439 return Err(Error::ExtractSubjectFailed);
440 }
441
442 if size < 0 {
443 // Our buffer wasn't big enough. Make one that is just the right size and try again.
Shawn Willden34120872021-02-24 21:56:30 -0700444 let negated_size = usize::try_from(-size).map_err(|_e| Error::ExtractSubjectFailed)?;
445 retval = vec![0; negated_size];
Shawn Willden8fde4c22021-02-14 13:58:22 -0700446
Shawn Willden34120872021-02-24 21:56:30 -0700447 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf
448 // and writes at most retval.len() bytes to retval.
Shawn Willden8fde4c22021-02-14 13:58:22 -0700449 size = unsafe {
450 extractSubjectFromCertificate(
451 cert_buf.as_ptr(),
452 cert_buf.len(),
453 retval.as_mut_ptr(),
454 retval.len(),
455 )
456 };
457
458 if size <= 0 {
459 return Err(Error::ExtractSubjectFailed);
460 }
461 }
462
463 // Reduce buffer size to the amount written.
Shawn Willden34120872021-02-24 21:56:30 -0700464 let safe_size = usize::try_from(size).map_err(|_e| Error::ExtractSubjectFailed)?;
465 retval.truncate(safe_size);
Shawn Willden8fde4c22021-02-14 13:58:22 -0700466
467 Ok(retval)
468}
469
Joel Galensonca0efb12020-10-01 14:32:30 -0700470#[cfg(test)]
471mod tests {
472
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800473 use super::*;
Joel Galensonca0efb12020-10-01 14:32:30 -0700474 use keystore2_crypto_bindgen::{
475 generateKeyFromPassword, AES_gcm_decrypt, AES_gcm_encrypt, CreateKeyId,
476 };
477
478 #[test]
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800479 fn test_wrapper_roundtrip() {
480 let key = generate_aes256_key().unwrap();
481 let message = b"totally awesome message";
482 let (cipher_text, iv, tag) = aes_gcm_encrypt(message, &key).unwrap();
483 let message2 = aes_gcm_decrypt(&cipher_text, &iv, &tag, &key).unwrap();
484 assert_eq!(message[..], message2[..])
485 }
486
487 #[test]
Joel Galensonca0efb12020-10-01 14:32:30 -0700488 fn test_encrypt_decrypt() {
489 let input = vec![0; 16];
490 let mut out = vec![0; 16];
491 let mut out2 = vec![0; 16];
492 let key = vec![0; 16];
493 let iv = vec![0; 12];
494 let mut tag = vec![0; 16];
Andrew Walbrana47698a2023-07-21 17:23:56 +0100495 // SAFETY: The various pointers are obtained from references so they are valid, and
496 // `AES_gcm_encrypt` and `AES_gcm_decrypt` don't do anything with them after they return.
Joel Galensonca0efb12020-10-01 14:32:30 -0700497 unsafe {
498 let res = AES_gcm_encrypt(
499 input.as_ptr(),
500 out.as_mut_ptr(),
501 16,
502 key.as_ptr(),
503 16,
504 iv.as_ptr(),
505 tag.as_mut_ptr(),
506 );
507 assert!(res);
508 assert_ne!(out, input);
509 assert_ne!(tag, input);
510 let res = AES_gcm_decrypt(
511 out.as_ptr(),
512 out2.as_mut_ptr(),
513 16,
514 key.as_ptr(),
515 16,
516 iv.as_ptr(),
517 tag.as_ptr(),
518 );
519 assert!(res);
520 assert_eq!(out2, input);
521 }
522 }
523
524 #[test]
525 fn test_create_key_id() {
526 let blob = vec![0; 16];
527 let mut out: u64 = 0;
Andrew Walbrana47698a2023-07-21 17:23:56 +0100528 // SAFETY: The pointers are obtained from references so they are valid, the length matches
529 // the length of the array, and `CreateKeyId` doesn't access them after it returns.
Joel Galensonca0efb12020-10-01 14:32:30 -0700530 unsafe {
Andrew Walbrana47698a2023-07-21 17:23:56 +0100531 let res = CreateKeyId(blob.as_ptr(), blob.len(), &mut out);
Joel Galensonca0efb12020-10-01 14:32:30 -0700532 assert!(res);
533 assert_ne!(out, 0);
534 }
535 }
536
537 #[test]
538 fn test_generate_key_from_password() {
539 let mut key = vec![0; 16];
540 let pw = vec![0; 16];
David Drysdale6a0ec2c2022-04-19 08:11:18 +0100541 let salt = vec![0; 16];
Andrew Walbrana47698a2023-07-21 17:23:56 +0100542 // SAFETY: The pointers are obtained from references so they are valid, the salt is the
543 // expected length, the other lengths match the lengths of the arrays, and
544 // `generateKeyFromPassword` doesn't access them after it returns.
Joel Galensonca0efb12020-10-01 14:32:30 -0700545 unsafe {
Andrew Walbrana47698a2023-07-21 17:23:56 +0100546 generateKeyFromPassword(
547 key.as_mut_ptr(),
548 key.len(),
549 pw.as_ptr(),
550 pw.len(),
551 salt.as_ptr(),
552 );
Joel Galensonca0efb12020-10-01 14:32:30 -0700553 }
554 assert_ne!(key, vec![0; 16]);
555 }
Joel Galenson05914582021-01-08 09:30:41 -0800556
557 #[test]
558 fn test_hkdf() {
559 let result = hkdf_extract(&[0; 16], &[0; 16]);
560 assert!(result.is_ok());
561 for out_len in 4..=8 {
562 let result = hkdf_expand(out_len, &[0; 16], &[0; 16]);
563 assert!(result.is_ok());
564 assert_eq!(result.unwrap().len(), out_len);
565 }
566 }
567
568 #[test]
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700569 fn test_ec() -> Result<(), Error> {
570 let priv0 = ec_key_generate_key()?;
571 assert!(!priv0.0.is_null());
572 let pub0 = ec_key_get0_public_key(&priv0);
Joel Galenson05914582021-01-08 09:30:41 -0800573
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700574 let priv1 = ec_key_generate_key()?;
575 let pub1 = ec_key_get0_public_key(&priv1);
Joel Galenson05914582021-01-08 09:30:41 -0800576
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700577 let priv0s = ec_key_marshal_private_key(&priv0)?;
578 let pub0s = ec_point_point_to_oct(pub0.get_point())?;
579 let pub1s = ec_point_point_to_oct(pub1.get_point())?;
Joel Galenson05914582021-01-08 09:30:41 -0800580
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700581 let priv0 = ec_key_parse_private_key(&priv0s)?;
582 let pub0 = ec_point_oct_to_point(&pub0s)?;
583 let pub1 = ec_point_oct_to_point(&pub1s)?;
Joel Galenson05914582021-01-08 09:30:41 -0800584
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700585 let left_key = ecdh_compute_key(pub0.get_point(), &priv1)?;
586 let right_key = ecdh_compute_key(pub1.get_point(), &priv0)?;
Joel Galenson05914582021-01-08 09:30:41 -0800587
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700588 assert_eq!(left_key, right_key);
589 Ok(())
Joel Galenson05914582021-01-08 09:30:41 -0800590 }
David Drysdalec97eb9e2022-01-26 13:03:48 -0800591
592 #[test]
593 fn test_hmac_sha256() {
594 let key = b"This is the key";
595 let msg1 = b"This is a message";
596 let msg2 = b"This is another message";
597 let tag1a = hmac_sha256(key, msg1).unwrap();
598 assert_eq!(tag1a.len(), HMAC_SHA256_LEN);
599 let tag1b = hmac_sha256(key, msg1).unwrap();
600 assert_eq!(tag1a, tag1b);
601 let tag2 = hmac_sha256(key, msg2).unwrap();
602 assert_eq!(tag2.len(), HMAC_SHA256_LEN);
603 assert_ne!(tag1a, tag2);
604 }
Joel Galensonca0efb12020-10-01 14:32:30 -0700605}