1 // 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
15 //! This module implements safe wrappers for some crypto operations required by
16 //! Keystore 2.0.
17
18 mod error;
19 mod zvec;
20 pub use error::Error;
21 use keystore2_crypto_bindgen::{
22 extractSubjectFromCertificate, generateKeyFromPassword, randomBytes, AES_gcm_decrypt,
23 AES_gcm_encrypt, ECDHComputeKey, ECKEYGenerateKey, ECKEYMarshalPrivateKey,
24 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,
26 };
27 use std::convert::TryFrom;
28 use std::convert::TryInto;
29 use std::marker::PhantomData;
30 pub use zvec::ZVec;
31
32 /// Length of the expected initialization vector.
33 pub const GCM_IV_LENGTH: usize = 12;
34 /// Length of the expected AEAD TAG.
35 pub const TAG_LENGTH: usize = 16;
36 /// Length of an AES 256 key in bytes.
37 pub const AES_256_KEY_LENGTH: usize = 32;
38 /// Length of an AES 128 key in bytes.
39 pub const AES_128_KEY_LENGTH: usize = 16;
40 /// Length of the expected salt for key from password generation.
41 pub const SALT_LENGTH: usize = 16;
42
43 /// Older versions of keystore produced IVs with four extra
44 /// ignored zero bytes at the end; recognise and trim those.
45 pub const LEGACY_IV_LENGTH: usize = 16;
46
47 /// Generate an AES256 key, essentially 32 random bytes from the underlying
48 /// boringssl library discretely stuffed into a ZVec.
generate_aes256_key() -> Result<ZVec, Error>49 pub fn generate_aes256_key() -> Result<ZVec, Error> {
50 // Safety: key has the same length as the requested number of random bytes.
51 let mut key = ZVec::new(AES_256_KEY_LENGTH)?;
52 if unsafe { randomBytes(key.as_mut_ptr(), AES_256_KEY_LENGTH) } {
53 Ok(key)
54 } else {
55 Err(Error::RandomNumberGenerationFailed)
56 }
57 }
58
59 /// Generate a salt.
generate_salt() -> Result<Vec<u8>, Error>60 pub fn generate_salt() -> Result<Vec<u8>, Error> {
61 generate_random_data(SALT_LENGTH)
62 }
63
64 /// Generate random data of the given size.
generate_random_data(size: usize) -> Result<Vec<u8>, Error>65 pub fn generate_random_data(size: usize) -> Result<Vec<u8>, Error> {
66 // Safety: data has the same length as the requested number of random bytes.
67 let mut data = vec![0; size];
68 if unsafe { randomBytes(data.as_mut_ptr(), size) } {
69 Ok(data)
70 } else {
71 Err(Error::RandomNumberGenerationFailed)
72 }
73 }
74
75 /// Uses AES GCM to decipher a message given an initialization vector, aead tag, and key.
76 /// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based
77 /// on the key length.
78 /// This function returns the plaintext message in a ZVec because it is assumed that
79 /// it contains sensitive information that should be zeroed from memory before its buffer is
80 /// freed. Input key is taken as a slice for flexibility, but it is recommended that it is held
81 /// in a ZVec as well.
aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error>82 pub fn aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error> {
83 // Old versions of aes_gcm_encrypt produced 16 byte IVs, but the last four bytes were ignored
84 // so trim these to the correct size.
85 let iv = match iv.len() {
86 GCM_IV_LENGTH => iv,
87 LEGACY_IV_LENGTH => &iv[..GCM_IV_LENGTH],
88 _ => return Err(Error::InvalidIvLength),
89 };
90 if tag.len() != TAG_LENGTH {
91 return Err(Error::InvalidAeadTagLength);
92 }
93
94 match key.len() {
95 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
96 _ => return Err(Error::InvalidKeyLength),
97 }
98
99 let mut result = ZVec::new(data.len())?;
100
101 // Safety: The first two arguments must point to buffers with a size given by the third
102 // argument. We pass the length of the key buffer along with the key.
103 // The `iv` buffer must be 12 bytes and the `tag` buffer 16, which we check above.
104 match unsafe {
105 AES_gcm_decrypt(
106 data.as_ptr(),
107 result.as_mut_ptr(),
108 data.len(),
109 key.as_ptr(),
110 key.len(),
111 iv.as_ptr(),
112 tag.as_ptr(),
113 )
114 } {
115 true => Ok(result),
116 false => Err(Error::DecryptionFailed),
117 }
118 }
119
120 /// Uses AES GCM to encrypt a message given a key.
121 /// This function accepts 128 and 256-bit keys and uses AES128 and AES256 respectively based on
122 /// the key length. The function generates an initialization vector. The return value is a tuple
123 /// of `(ciphertext, iv, tag)`.
aes_gcm_encrypt(plaintext: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Error>124 pub fn aes_gcm_encrypt(plaintext: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Error> {
125 let mut iv = vec![0; GCM_IV_LENGTH];
126 // Safety: iv is GCM_IV_LENGTH bytes long.
127 if !unsafe { randomBytes(iv.as_mut_ptr(), GCM_IV_LENGTH) } {
128 return Err(Error::RandomNumberGenerationFailed);
129 }
130
131 match key.len() {
132 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
133 _ => return Err(Error::InvalidKeyLength),
134 }
135
136 let mut ciphertext: Vec<u8> = vec![0; plaintext.len()];
137 let mut tag: Vec<u8> = vec![0; TAG_LENGTH];
138 // Safety: The first two arguments must point to buffers with a size given by the third
139 // argument. We pass the length of the key buffer along with the key.
140 // The `iv` buffer must be 12 bytes and the `tag` buffer 16, which we check above.
141 if unsafe {
142 AES_gcm_encrypt(
143 plaintext.as_ptr(),
144 ciphertext.as_mut_ptr(),
145 plaintext.len(),
146 key.as_ptr(),
147 key.len(),
148 iv.as_ptr(),
149 tag.as_mut_ptr(),
150 )
151 } {
152 Ok((ciphertext, iv, tag))
153 } else {
154 Err(Error::EncryptionFailed)
155 }
156 }
157
158 /// Represents a "password" that can be used to key the PBKDF2 algorithm.
159 pub enum Password<'a> {
160 /// Borrow an existing byte array
161 Ref(&'a [u8]),
162 /// Use an owned ZVec to store the key
163 Owned(ZVec),
164 }
165
166 impl<'a> From<&'a [u8]> for Password<'a> {
from(pw: &'a [u8]) -> Self167 fn from(pw: &'a [u8]) -> Self {
168 Self::Ref(pw)
169 }
170 }
171
172 impl<'a> Password<'a> {
get_key(&'a self) -> &'a [u8]173 fn get_key(&'a self) -> &'a [u8] {
174 match self {
175 Self::Ref(b) => b,
176 Self::Owned(z) => &*z,
177 }
178 }
179
180 /// Generate a key from the given password and salt.
181 /// The salt must be exactly 16 bytes long.
182 /// Two key sizes are accepted: 16 and 32 bytes.
derive_key(&self, salt: Option<&[u8]>, key_length: usize) -> Result<ZVec, Error>183 pub fn derive_key(&self, salt: Option<&[u8]>, key_length: usize) -> Result<ZVec, Error> {
184 let pw = self.get_key();
185
186 let salt: *const u8 = match salt {
187 Some(s) => {
188 if s.len() != SALT_LENGTH {
189 return Err(Error::InvalidSaltLength);
190 }
191 s.as_ptr()
192 }
193 None => std::ptr::null(),
194 };
195
196 match key_length {
197 AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
198 _ => return Err(Error::InvalidKeyLength),
199 }
200
201 let mut result = ZVec::new(key_length)?;
202
203 unsafe {
204 generateKeyFromPassword(
205 result.as_mut_ptr(),
206 result.len(),
207 pw.as_ptr() as *const std::os::raw::c_char,
208 pw.len(),
209 salt,
210 )
211 };
212
213 Ok(result)
214 }
215
216 /// Try to make another Password object with the same data.
try_clone(&self) -> Result<Password<'static>, Error>217 pub fn try_clone(&self) -> Result<Password<'static>, Error> {
218 Ok(Password::Owned(ZVec::try_from(self.get_key())?))
219 }
220 }
221
222 /// Calls the boringssl HKDF_extract function.
hkdf_extract(secret: &[u8], salt: &[u8]) -> Result<ZVec, Error>223 pub fn hkdf_extract(secret: &[u8], salt: &[u8]) -> Result<ZVec, Error> {
224 let max_size: usize = EVP_MAX_MD_SIZE.try_into().unwrap();
225 let mut buf = ZVec::new(max_size)?;
226 let mut out_len = 0;
227 // Safety: HKDF_extract writes at most EVP_MAX_MD_SIZE bytes.
228 // Secret and salt point to valid buffers.
229 let result = unsafe {
230 HKDFExtract(
231 buf.as_mut_ptr(),
232 &mut out_len,
233 secret.as_ptr(),
234 secret.len(),
235 salt.as_ptr(),
236 salt.len(),
237 )
238 };
239 if !result {
240 return Err(Error::HKDFExtractFailed);
241 }
242 // According to the boringssl API, this should never happen.
243 if out_len > max_size {
244 return Err(Error::HKDFExtractFailed);
245 }
246 // HKDF_extract may write fewer than the maximum number of bytes, so we
247 // truncate the buffer.
248 buf.reduce_len(out_len);
249 Ok(buf)
250 }
251
252 /// Calls the boringssl HKDF_expand function.
hkdf_expand(out_len: usize, prk: &[u8], info: &[u8]) -> Result<ZVec, Error>253 pub fn hkdf_expand(out_len: usize, prk: &[u8], info: &[u8]) -> Result<ZVec, Error> {
254 let mut buf = ZVec::new(out_len)?;
255 // Safety: HKDF_expand writes out_len bytes to the buffer.
256 // prk and info are valid buffers.
257 let result = unsafe {
258 HKDFExpand(buf.as_mut_ptr(), out_len, prk.as_ptr(), prk.len(), info.as_ptr(), info.len())
259 };
260 if !result {
261 return Err(Error::HKDFExpandFailed);
262 }
263 Ok(buf)
264 }
265
266 /// A wrapper around the boringssl EC_KEY type that frees it on drop.
267 pub struct ECKey(*mut EC_KEY);
268
269 impl Drop for ECKey {
drop(&mut self)270 fn drop(&mut self) {
271 // Safety: We only create ECKey objects for valid EC_KEYs
272 // and they are the sole owners of those keys.
273 unsafe { EC_KEY_free(self.0) };
274 }
275 }
276
277 // Wrappers around the boringssl EC_POINT type.
278 // The EC_POINT can either be owned (and therefore mutable) or a pointer to an
279 // EC_POINT owned by someone else (and thus immutable). The former are freed
280 // on drop.
281
282 /// An owned EC_POINT object.
283 pub struct OwnedECPoint(*mut EC_POINT);
284
285 /// A pointer to an EC_POINT object.
286 pub struct BorrowedECPoint<'a> {
287 data: *const EC_POINT,
288 phantom: PhantomData<&'a EC_POINT>,
289 }
290
291 impl OwnedECPoint {
292 /// Get the wrapped EC_POINT object.
get_point(&self) -> &EC_POINT293 pub fn get_point(&self) -> &EC_POINT {
294 // Safety: We only create OwnedECPoint objects for valid EC_POINTs.
295 unsafe { self.0.as_ref().unwrap() }
296 }
297 }
298
299 impl<'a> BorrowedECPoint<'a> {
300 /// Get the wrapped EC_POINT object.
get_point(&self) -> &EC_POINT301 pub fn get_point(&self) -> &EC_POINT {
302 // Safety: We only create BorrowedECPoint objects for valid EC_POINTs.
303 unsafe { self.data.as_ref().unwrap() }
304 }
305 }
306
307 impl Drop for OwnedECPoint {
drop(&mut self)308 fn drop(&mut self) {
309 // Safety: We only create OwnedECPoint objects for valid
310 // EC_POINTs and they are the sole owners of those points.
311 unsafe { EC_POINT_free(self.0) };
312 }
313 }
314
315 /// Calls the boringssl ECDH_compute_key function.
ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error>316 pub fn ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error> {
317 let mut buf = ZVec::new(EC_MAX_BYTES)?;
318 // Safety: Our ECDHComputeKey wrapper passes EC_MAX_BYES to ECDH_compute_key, which
319 // writes at most that many bytes to the output.
320 // The two keys are valid objects.
321 let result =
322 unsafe { ECDHComputeKey(buf.as_mut_ptr() as *mut std::ffi::c_void, pub_key, priv_key.0) };
323 if result == -1 {
324 return Err(Error::ECDHComputeKeyFailed);
325 }
326 let out_len = result.try_into().unwrap();
327 // According to the boringssl API, this should never happen.
328 if out_len > buf.len() {
329 return Err(Error::ECDHComputeKeyFailed);
330 }
331 // ECDH_compute_key may write fewer than the maximum number of bytes, so we
332 // truncate the buffer.
333 buf.reduce_len(out_len);
334 Ok(buf)
335 }
336
337 /// Calls the boringssl EC_KEY_generate_key function.
ec_key_generate_key() -> Result<ECKey, Error>338 pub fn ec_key_generate_key() -> Result<ECKey, Error> {
339 // Safety: Creates a new key on its own.
340 let key = unsafe { ECKEYGenerateKey() };
341 if key.is_null() {
342 return Err(Error::ECKEYGenerateKeyFailed);
343 }
344 Ok(ECKey(key))
345 }
346
347 /// Calls the boringssl EC_KEY_marshal_private_key function.
ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error>348 pub fn ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error> {
349 let len = 73; // Empirically observed length of private key
350 let mut buf = ZVec::new(len)?;
351 // Safety: the key is valid.
352 // This will not write past the specified length of the buffer; if the
353 // len above is too short, it returns 0.
354 let written_len =
355 unsafe { ECKEYMarshalPrivateKey(key.0, buf.as_mut_ptr(), buf.len()) } as usize;
356 if written_len == len {
357 Ok(buf)
358 } else {
359 Err(Error::ECKEYMarshalPrivateKeyFailed)
360 }
361 }
362
363 /// Calls the boringssl EC_KEY_parse_private_key function.
ec_key_parse_private_key(buf: &[u8]) -> Result<ECKey, Error>364 pub fn ec_key_parse_private_key(buf: &[u8]) -> Result<ECKey, Error> {
365 // Safety: this will not read past the specified length of the buffer.
366 // It fails if less than the whole buffer is consumed.
367 let key = unsafe { ECKEYParsePrivateKey(buf.as_ptr(), buf.len()) };
368 if key.is_null() {
369 Err(Error::ECKEYParsePrivateKeyFailed)
370 } else {
371 Ok(ECKey(key))
372 }
373 }
374
375 /// Calls the boringssl EC_KEY_get0_public_key function.
ec_key_get0_public_key(key: &ECKey) -> BorrowedECPoint376 pub fn ec_key_get0_public_key(key: &ECKey) -> BorrowedECPoint {
377 // Safety: The key is valid.
378 // This returns a pointer to a key, so we create an immutable variant.
379 BorrowedECPoint { data: unsafe { EC_KEY_get0_public_key(key.0) }, phantom: PhantomData }
380 }
381
382 /// Calls the boringssl EC_POINT_point2oct.
ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error>383 pub fn ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error> {
384 // We fix the length to 133 (1 + 2 * field_elem_size), as we get an error if it's too small.
385 let len = 133;
386 let mut buf = vec![0; len];
387 // Safety: EC_POINT_point2oct writes at most len bytes. The point is valid.
388 let result = unsafe { ECPOINTPoint2Oct(point, buf.as_mut_ptr(), len) };
389 if result == 0 {
390 return Err(Error::ECPoint2OctFailed);
391 }
392 // According to the boringssl API, this should never happen.
393 if result > len {
394 return Err(Error::ECPoint2OctFailed);
395 }
396 buf.resize(result, 0);
397 Ok(buf)
398 }
399
400 /// Calls the boringssl EC_POINT_oct2point function.
ec_point_oct_to_point(buf: &[u8]) -> Result<OwnedECPoint, Error>401 pub fn ec_point_oct_to_point(buf: &[u8]) -> Result<OwnedECPoint, Error> {
402 // Safety: The buffer is valid.
403 let result = unsafe { ECPOINTOct2Point(buf.as_ptr(), buf.len()) };
404 if result.is_null() {
405 return Err(Error::ECPoint2OctFailed);
406 }
407 // Our C wrapper creates a new EC_POINT, so we mark this mutable and free
408 // it on drop.
409 Ok(OwnedECPoint(result))
410 }
411
412 /// Uses BoringSSL to extract the DER-encoded subject from a DER-encoded X.509 certificate.
parse_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error>413 pub fn parse_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error> {
414 // Try with a 200-byte output buffer, should be enough in all but bizarre cases.
415 let mut retval = vec![0; 200];
416
417 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf and
418 // writes at most retval.len() bytes to retval.
419 let mut size = unsafe {
420 extractSubjectFromCertificate(
421 cert_buf.as_ptr(),
422 cert_buf.len(),
423 retval.as_mut_ptr(),
424 retval.len(),
425 )
426 };
427
428 if size == 0 {
429 return Err(Error::ExtractSubjectFailed);
430 }
431
432 if size < 0 {
433 // Our buffer wasn't big enough. Make one that is just the right size and try again.
434 let negated_size = usize::try_from(-size).map_err(|_e| Error::ExtractSubjectFailed)?;
435 retval = vec![0; negated_size];
436
437 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf
438 // and writes at most retval.len() bytes to retval.
439 size = unsafe {
440 extractSubjectFromCertificate(
441 cert_buf.as_ptr(),
442 cert_buf.len(),
443 retval.as_mut_ptr(),
444 retval.len(),
445 )
446 };
447
448 if size <= 0 {
449 return Err(Error::ExtractSubjectFailed);
450 }
451 }
452
453 // Reduce buffer size to the amount written.
454 let safe_size = usize::try_from(size).map_err(|_e| Error::ExtractSubjectFailed)?;
455 retval.truncate(safe_size);
456
457 Ok(retval)
458 }
459
460 #[cfg(test)]
461 mod tests {
462
463 use super::*;
464 use keystore2_crypto_bindgen::{
465 generateKeyFromPassword, AES_gcm_decrypt, AES_gcm_encrypt, CreateKeyId,
466 };
467
468 #[test]
test_wrapper_roundtrip()469 fn test_wrapper_roundtrip() {
470 let key = generate_aes256_key().unwrap();
471 let message = b"totally awesome message";
472 let (cipher_text, iv, tag) = aes_gcm_encrypt(message, &key).unwrap();
473 let message2 = aes_gcm_decrypt(&cipher_text, &iv, &tag, &key).unwrap();
474 assert_eq!(message[..], message2[..])
475 }
476
477 #[test]
test_encrypt_decrypt()478 fn test_encrypt_decrypt() {
479 let input = vec![0; 16];
480 let mut out = vec![0; 16];
481 let mut out2 = vec![0; 16];
482 let key = vec![0; 16];
483 let iv = vec![0; 12];
484 let mut tag = vec![0; 16];
485 unsafe {
486 let res = AES_gcm_encrypt(
487 input.as_ptr(),
488 out.as_mut_ptr(),
489 16,
490 key.as_ptr(),
491 16,
492 iv.as_ptr(),
493 tag.as_mut_ptr(),
494 );
495 assert!(res);
496 assert_ne!(out, input);
497 assert_ne!(tag, input);
498 let res = AES_gcm_decrypt(
499 out.as_ptr(),
500 out2.as_mut_ptr(),
501 16,
502 key.as_ptr(),
503 16,
504 iv.as_ptr(),
505 tag.as_ptr(),
506 );
507 assert!(res);
508 assert_eq!(out2, input);
509 }
510 }
511
512 #[test]
test_create_key_id()513 fn test_create_key_id() {
514 let blob = vec![0; 16];
515 let mut out: u64 = 0;
516 unsafe {
517 let res = CreateKeyId(blob.as_ptr(), 16, &mut out);
518 assert!(res);
519 assert_ne!(out, 0);
520 }
521 }
522
523 #[test]
test_generate_key_from_password()524 fn test_generate_key_from_password() {
525 let mut key = vec![0; 16];
526 let pw = vec![0; 16];
527 let mut salt = vec![0; 16];
528 unsafe {
529 generateKeyFromPassword(key.as_mut_ptr(), 16, pw.as_ptr(), 16, salt.as_mut_ptr());
530 }
531 assert_ne!(key, vec![0; 16]);
532 }
533
534 #[test]
test_hkdf()535 fn test_hkdf() {
536 let result = hkdf_extract(&[0; 16], &[0; 16]);
537 assert!(result.is_ok());
538 for out_len in 4..=8 {
539 let result = hkdf_expand(out_len, &[0; 16], &[0; 16]);
540 assert!(result.is_ok());
541 assert_eq!(result.unwrap().len(), out_len);
542 }
543 }
544
545 #[test]
test_ec() -> Result<(), Error>546 fn test_ec() -> Result<(), Error> {
547 let priv0 = ec_key_generate_key()?;
548 assert!(!priv0.0.is_null());
549 let pub0 = ec_key_get0_public_key(&priv0);
550
551 let priv1 = ec_key_generate_key()?;
552 let pub1 = ec_key_get0_public_key(&priv1);
553
554 let priv0s = ec_key_marshal_private_key(&priv0)?;
555 let pub0s = ec_point_point_to_oct(pub0.get_point())?;
556 let pub1s = ec_point_point_to_oct(pub1.get_point())?;
557
558 let priv0 = ec_key_parse_private_key(&priv0s)?;
559 let pub0 = ec_point_oct_to_point(&pub0s)?;
560 let pub1 = ec_point_oct_to_point(&pub1s)?;
561
562 let left_key = ecdh_compute_key(pub0.get_point(), &priv1)?;
563 let right_key = ecdh_compute_key(pub1.get_point(), &priv0)?;
564
565 assert_eq!(left_key, right_key);
566 Ok(())
567 }
568 }
569