• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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