• 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 pub mod zvec;
20 pub use error::Error;
21 use keystore2_crypto_bindgen::{
22     extractSubjectFromCertificate, generateKeyFromPassword, hmacSha256, randomBytes,
23     AES_gcm_decrypt, 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 /// Length of an HMAC-SHA256 tag in bytes.
43 pub const HMAC_SHA256_LEN: usize = 32;
44 
45 /// Older versions of keystore produced IVs with four extra
46 /// ignored zero bytes at the end; recognise and trim those.
47 pub const LEGACY_IV_LENGTH: usize = 16;
48 
49 /// Generate an AES256 key, essentially 32 random bytes from the underlying
50 /// boringssl library discretely stuffed into a ZVec.
generate_aes256_key() -> Result<ZVec, Error>51 pub fn generate_aes256_key() -> Result<ZVec, Error> {
52     // Safety: key has the same length as the requested number of random bytes.
53     let mut key = ZVec::new(AES_256_KEY_LENGTH)?;
54     if unsafe { randomBytes(key.as_mut_ptr(), AES_256_KEY_LENGTH) } {
55         Ok(key)
56     } else {
57         Err(Error::RandomNumberGenerationFailed)
58     }
59 }
60 
61 /// Generate a salt.
generate_salt() -> Result<Vec<u8>, Error>62 pub fn generate_salt() -> Result<Vec<u8>, Error> {
63     generate_random_data(SALT_LENGTH)
64 }
65 
66 /// Generate random data of the given size.
generate_random_data(size: usize) -> Result<Vec<u8>, Error>67 pub fn generate_random_data(size: usize) -> Result<Vec<u8>, Error> {
68     // Safety: data has the same length as the requested number of random bytes.
69     let mut data = vec![0; size];
70     if unsafe { randomBytes(data.as_mut_ptr(), size) } {
71         Ok(data)
72     } else {
73         Err(Error::RandomNumberGenerationFailed)
74     }
75 }
76 
77 /// Perform HMAC-SHA256.
hmac_sha256(key: &[u8], msg: &[u8]) -> Result<Vec<u8>, Error>78 pub 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 
92 /// 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.
aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error>99 pub fn aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error> {
100     // 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     };
107     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
119     // 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.
121     match unsafe {
122         AES_gcm_decrypt(
123             data.as_ptr(),
124             result.as_mut_ptr(),
125             data.len(),
126             key.as_ptr(),
127             key.len(),
128             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)`.
aes_gcm_encrypt(plaintext: &[u8], key: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Error>141 pub 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.
144     if !unsafe { randomBytes(iv.as_mut_ptr(), GCM_IV_LENGTH) } {
145         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 
153     let mut ciphertext: Vec<u8> = vec![0; plaintext.len()];
154     let mut tag: Vec<u8> = vec![0; TAG_LENGTH];
155     // 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 {
159         AES_gcm_encrypt(
160             plaintext.as_ptr(),
161             ciphertext.as_mut_ptr(),
162             plaintext.len(),
163             key.as_ptr(),
164             key.len(),
165             iv.as_ptr(),
166             tag.as_mut_ptr(),
167         )
168     } {
169         Ok((ciphertext, iv, tag))
170     } else {
171         Err(Error::EncryptionFailed)
172     }
173 }
174 
175 /// Represents a "password" that can be used to key the PBKDF2 algorithm.
176 pub 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 }
182 
183 impl<'a> From<&'a [u8]> for Password<'a> {
from(pw: &'a [u8]) -> Self184     fn from(pw: &'a [u8]) -> Self {
185         Self::Ref(pw)
186     }
187 }
188 
189 impl<'a> Password<'a> {
get_key(&'a self) -> &'a [u8]190     fn get_key(&'a self) -> &'a [u8] {
191         match self {
192             Self::Ref(b) => b,
193             Self::Owned(z) => &*z,
194         }
195     }
196 
197     /// 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.
derive_key(&self, salt: Option<&[u8]>, key_length: usize) -> Result<ZVec, Error>200     pub fn derive_key(&self, salt: Option<&[u8]>, key_length: usize) -> Result<ZVec, Error> {
201         let pw = self.get_key();
202 
203         let salt: *const u8 = match salt {
204             Some(s) => {
205                 if s.len() != SALT_LENGTH {
206                     return Err(Error::InvalidSaltLength);
207                 }
208                 s.as_ptr()
209             }
210             None => std::ptr::null(),
211         };
212 
213         match key_length {
214             AES_128_KEY_LENGTH | AES_256_KEY_LENGTH => {}
215             _ => return Err(Error::InvalidKeyLength),
216         }
217 
218         let mut result = ZVec::new(key_length)?;
219 
220         unsafe {
221             generateKeyFromPassword(
222                 result.as_mut_ptr(),
223                 result.len(),
224                 pw.as_ptr() as *const std::os::raw::c_char,
225                 pw.len(),
226                 salt,
227             )
228         };
229 
230         Ok(result)
231     }
232 
233     /// Try to make another Password object with the same data.
try_clone(&self) -> Result<Password<'static>, Error>234     pub fn try_clone(&self) -> Result<Password<'static>, Error> {
235         Ok(Password::Owned(ZVec::try_from(self.get_key())?))
236     }
237 }
238 
239 /// Calls the boringssl HKDF_extract function.
hkdf_extract(secret: &[u8], salt: &[u8]) -> Result<ZVec, Error>240 pub fn hkdf_extract(secret: &[u8], salt: &[u8]) -> Result<ZVec, Error> {
241     let max_size: usize = EVP_MAX_MD_SIZE.try_into().unwrap();
242     let mut buf = ZVec::new(max_size)?;
243     let mut out_len = 0;
244     // Safety: HKDF_extract writes at most EVP_MAX_MD_SIZE bytes.
245     // Secret and salt point to valid buffers.
246     let result = unsafe {
247         HKDFExtract(
248             buf.as_mut_ptr(),
249             &mut out_len,
250             secret.as_ptr(),
251             secret.len(),
252             salt.as_ptr(),
253             salt.len(),
254         )
255     };
256     if !result {
257         return Err(Error::HKDFExtractFailed);
258     }
259     // According to the boringssl API, this should never happen.
260     if out_len > max_size {
261         return Err(Error::HKDFExtractFailed);
262     }
263     // HKDF_extract may write fewer than the maximum number of bytes, so we
264     // truncate the buffer.
265     buf.reduce_len(out_len);
266     Ok(buf)
267 }
268 
269 /// Calls the boringssl HKDF_expand function.
hkdf_expand(out_len: usize, prk: &[u8], info: &[u8]) -> Result<ZVec, Error>270 pub fn hkdf_expand(out_len: usize, prk: &[u8], info: &[u8]) -> Result<ZVec, Error> {
271     let mut buf = ZVec::new(out_len)?;
272     // Safety: HKDF_expand writes out_len bytes to the buffer.
273     // prk and info are valid buffers.
274     let result = unsafe {
275         HKDFExpand(buf.as_mut_ptr(), out_len, prk.as_ptr(), prk.len(), info.as_ptr(), info.len())
276     };
277     if !result {
278         return Err(Error::HKDFExpandFailed);
279     }
280     Ok(buf)
281 }
282 
283 /// A wrapper around the boringssl EC_KEY type that frees it on drop.
284 pub struct ECKey(*mut EC_KEY);
285 
286 impl Drop for ECKey {
drop(&mut self)287     fn drop(&mut self) {
288         // Safety: We only create ECKey objects for valid EC_KEYs
289         // and they are the sole owners of those keys.
290         unsafe { EC_KEY_free(self.0) };
291     }
292 }
293 
294 // Wrappers around the boringssl EC_POINT type.
295 // The EC_POINT can either be owned (and therefore mutable) or a pointer to an
296 // EC_POINT owned by someone else (and thus immutable).  The former are freed
297 // on drop.
298 
299 /// An owned EC_POINT object.
300 pub struct OwnedECPoint(*mut EC_POINT);
301 
302 /// A pointer to an EC_POINT object.
303 pub struct BorrowedECPoint<'a> {
304     data: *const EC_POINT,
305     phantom: PhantomData<&'a EC_POINT>,
306 }
307 
308 impl OwnedECPoint {
309     /// Get the wrapped EC_POINT object.
get_point(&self) -> &EC_POINT310     pub fn get_point(&self) -> &EC_POINT {
311         // Safety: We only create OwnedECPoint objects for valid EC_POINTs.
312         unsafe { self.0.as_ref().unwrap() }
313     }
314 }
315 
316 impl<'a> BorrowedECPoint<'a> {
317     /// Get the wrapped EC_POINT object.
get_point(&self) -> &EC_POINT318     pub fn get_point(&self) -> &EC_POINT {
319         // Safety: We only create BorrowedECPoint objects for valid EC_POINTs.
320         unsafe { self.data.as_ref().unwrap() }
321     }
322 }
323 
324 impl Drop for OwnedECPoint {
drop(&mut self)325     fn drop(&mut self) {
326         // Safety: We only create OwnedECPoint objects for valid
327         // EC_POINTs and they are the sole owners of those points.
328         unsafe { EC_POINT_free(self.0) };
329     }
330 }
331 
332 /// Calls the boringssl ECDH_compute_key function.
ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error>333 pub fn ecdh_compute_key(pub_key: &EC_POINT, priv_key: &ECKey) -> Result<ZVec, Error> {
334     let mut buf = ZVec::new(EC_MAX_BYTES)?;
335     // Safety: Our ECDHComputeKey wrapper passes EC_MAX_BYES to ECDH_compute_key, which
336     // writes at most that many bytes to the output.
337     // The two keys are valid objects.
338     let result =
339         unsafe { ECDHComputeKey(buf.as_mut_ptr() as *mut std::ffi::c_void, pub_key, priv_key.0) };
340     if result == -1 {
341         return Err(Error::ECDHComputeKeyFailed);
342     }
343     let out_len = result.try_into().unwrap();
344     // According to the boringssl API, this should never happen.
345     if out_len > buf.len() {
346         return Err(Error::ECDHComputeKeyFailed);
347     }
348     // ECDH_compute_key may write fewer than the maximum number of bytes, so we
349     // truncate the buffer.
350     buf.reduce_len(out_len);
351     Ok(buf)
352 }
353 
354 /// Calls the boringssl EC_KEY_generate_key function.
ec_key_generate_key() -> Result<ECKey, Error>355 pub fn ec_key_generate_key() -> Result<ECKey, Error> {
356     // Safety: Creates a new key on its own.
357     let key = unsafe { ECKEYGenerateKey() };
358     if key.is_null() {
359         return Err(Error::ECKEYGenerateKeyFailed);
360     }
361     Ok(ECKey(key))
362 }
363 
364 /// Calls the boringssl EC_KEY_marshal_private_key function.
ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error>365 pub fn ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error> {
366     let len = 73; // Empirically observed length of private key
367     let mut buf = ZVec::new(len)?;
368     // Safety: the key is valid.
369     // This will not write past the specified length of the buffer; if the
370     // len above is too short, it returns 0.
371     let written_len =
372         unsafe { ECKEYMarshalPrivateKey(key.0, buf.as_mut_ptr(), buf.len()) } as usize;
373     if written_len == len {
374         Ok(buf)
375     } else {
376         Err(Error::ECKEYMarshalPrivateKeyFailed)
377     }
378 }
379 
380 /// Calls the boringssl EC_KEY_parse_private_key function.
ec_key_parse_private_key(buf: &[u8]) -> Result<ECKey, Error>381 pub fn ec_key_parse_private_key(buf: &[u8]) -> Result<ECKey, Error> {
382     // Safety: this will not read past the specified length of the buffer.
383     // It fails if less than the whole buffer is consumed.
384     let key = unsafe { ECKEYParsePrivateKey(buf.as_ptr(), buf.len()) };
385     if key.is_null() {
386         Err(Error::ECKEYParsePrivateKeyFailed)
387     } else {
388         Ok(ECKey(key))
389     }
390 }
391 
392 /// Calls the boringssl EC_KEY_get0_public_key function.
ec_key_get0_public_key(key: &ECKey) -> BorrowedECPoint393 pub fn ec_key_get0_public_key(key: &ECKey) -> BorrowedECPoint {
394     // Safety: The key is valid.
395     // This returns a pointer to a key, so we create an immutable variant.
396     BorrowedECPoint { data: unsafe { EC_KEY_get0_public_key(key.0) }, phantom: PhantomData }
397 }
398 
399 /// Calls the boringssl EC_POINT_point2oct.
ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error>400 pub fn ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error> {
401     // We fix the length to 133 (1 + 2 * field_elem_size), as we get an error if it's too small.
402     let len = 133;
403     let mut buf = vec![0; len];
404     // Safety: EC_POINT_point2oct writes at most len bytes. The point is valid.
405     let result = unsafe { ECPOINTPoint2Oct(point, buf.as_mut_ptr(), len) };
406     if result == 0 {
407         return Err(Error::ECPoint2OctFailed);
408     }
409     // According to the boringssl API, this should never happen.
410     if result > len {
411         return Err(Error::ECPoint2OctFailed);
412     }
413     buf.resize(result, 0);
414     Ok(buf)
415 }
416 
417 /// Calls the boringssl EC_POINT_oct2point function.
ec_point_oct_to_point(buf: &[u8]) -> Result<OwnedECPoint, Error>418 pub fn ec_point_oct_to_point(buf: &[u8]) -> Result<OwnedECPoint, Error> {
419     // Safety: The buffer is valid.
420     let result = unsafe { ECPOINTOct2Point(buf.as_ptr(), buf.len()) };
421     if result.is_null() {
422         return Err(Error::ECPoint2OctFailed);
423     }
424     // Our C wrapper creates a new EC_POINT, so we mark this mutable and free
425     // it on drop.
426     Ok(OwnedECPoint(result))
427 }
428 
429 /// 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>430 pub fn parse_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error> {
431     // Try with a 200-byte output buffer, should be enough in all but bizarre cases.
432     let mut retval = vec![0; 200];
433 
434     // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf and
435     // writes at most retval.len() bytes to retval.
436     let mut size = unsafe {
437         extractSubjectFromCertificate(
438             cert_buf.as_ptr(),
439             cert_buf.len(),
440             retval.as_mut_ptr(),
441             retval.len(),
442         )
443     };
444 
445     if size == 0 {
446         return Err(Error::ExtractSubjectFailed);
447     }
448 
449     if size < 0 {
450         // Our buffer wasn't big enough.  Make one that is just the right size and try again.
451         let negated_size = usize::try_from(-size).map_err(|_e| Error::ExtractSubjectFailed)?;
452         retval = vec![0; negated_size];
453 
454         // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf
455         // and writes at most retval.len() bytes to retval.
456         size = unsafe {
457             extractSubjectFromCertificate(
458                 cert_buf.as_ptr(),
459                 cert_buf.len(),
460                 retval.as_mut_ptr(),
461                 retval.len(),
462             )
463         };
464 
465         if size <= 0 {
466             return Err(Error::ExtractSubjectFailed);
467         }
468     }
469 
470     // Reduce buffer size to the amount written.
471     let safe_size = usize::try_from(size).map_err(|_e| Error::ExtractSubjectFailed)?;
472     retval.truncate(safe_size);
473 
474     Ok(retval)
475 }
476 
477 #[cfg(test)]
478 mod tests {
479 
480     use super::*;
481     use keystore2_crypto_bindgen::{
482         generateKeyFromPassword, AES_gcm_decrypt, AES_gcm_encrypt, CreateKeyId,
483     };
484 
485     #[test]
test_wrapper_roundtrip()486     fn test_wrapper_roundtrip() {
487         let key = generate_aes256_key().unwrap();
488         let message = b"totally awesome message";
489         let (cipher_text, iv, tag) = aes_gcm_encrypt(message, &key).unwrap();
490         let message2 = aes_gcm_decrypt(&cipher_text, &iv, &tag, &key).unwrap();
491         assert_eq!(message[..], message2[..])
492     }
493 
494     #[test]
test_encrypt_decrypt()495     fn test_encrypt_decrypt() {
496         let input = vec![0; 16];
497         let mut out = vec![0; 16];
498         let mut out2 = vec![0; 16];
499         let key = vec![0; 16];
500         let iv = vec![0; 12];
501         let mut tag = vec![0; 16];
502         unsafe {
503             let res = AES_gcm_encrypt(
504                 input.as_ptr(),
505                 out.as_mut_ptr(),
506                 16,
507                 key.as_ptr(),
508                 16,
509                 iv.as_ptr(),
510                 tag.as_mut_ptr(),
511             );
512             assert!(res);
513             assert_ne!(out, input);
514             assert_ne!(tag, input);
515             let res = AES_gcm_decrypt(
516                 out.as_ptr(),
517                 out2.as_mut_ptr(),
518                 16,
519                 key.as_ptr(),
520                 16,
521                 iv.as_ptr(),
522                 tag.as_ptr(),
523             );
524             assert!(res);
525             assert_eq!(out2, input);
526         }
527     }
528 
529     #[test]
test_create_key_id()530     fn test_create_key_id() {
531         let blob = vec![0; 16];
532         let mut out: u64 = 0;
533         unsafe {
534             let res = CreateKeyId(blob.as_ptr(), 16, &mut out);
535             assert!(res);
536             assert_ne!(out, 0);
537         }
538     }
539 
540     #[test]
test_generate_key_from_password()541     fn test_generate_key_from_password() {
542         let mut key = vec![0; 16];
543         let pw = vec![0; 16];
544         let mut salt = vec![0; 16];
545         unsafe {
546             generateKeyFromPassword(key.as_mut_ptr(), 16, pw.as_ptr(), 16, salt.as_mut_ptr());
547         }
548         assert_ne!(key, vec![0; 16]);
549     }
550 
551     #[test]
test_hkdf()552     fn test_hkdf() {
553         let result = hkdf_extract(&[0; 16], &[0; 16]);
554         assert!(result.is_ok());
555         for out_len in 4..=8 {
556             let result = hkdf_expand(out_len, &[0; 16], &[0; 16]);
557             assert!(result.is_ok());
558             assert_eq!(result.unwrap().len(), out_len);
559         }
560     }
561 
562     #[test]
test_ec() -> Result<(), Error>563     fn test_ec() -> Result<(), Error> {
564         let priv0 = ec_key_generate_key()?;
565         assert!(!priv0.0.is_null());
566         let pub0 = ec_key_get0_public_key(&priv0);
567 
568         let priv1 = ec_key_generate_key()?;
569         let pub1 = ec_key_get0_public_key(&priv1);
570 
571         let priv0s = ec_key_marshal_private_key(&priv0)?;
572         let pub0s = ec_point_point_to_oct(pub0.get_point())?;
573         let pub1s = ec_point_point_to_oct(pub1.get_point())?;
574 
575         let priv0 = ec_key_parse_private_key(&priv0s)?;
576         let pub0 = ec_point_oct_to_point(&pub0s)?;
577         let pub1 = ec_point_oct_to_point(&pub1s)?;
578 
579         let left_key = ecdh_compute_key(pub0.get_point(), &priv1)?;
580         let right_key = ecdh_compute_key(pub1.get_point(), &priv0)?;
581 
582         assert_eq!(left_key, right_key);
583         Ok(())
584     }
585 
586     #[test]
test_hmac_sha256()587     fn test_hmac_sha256() {
588         let key = b"This is the key";
589         let msg1 = b"This is a message";
590         let msg2 = b"This is another message";
591         let tag1a = hmac_sha256(key, msg1).unwrap();
592         assert_eq!(tag1a.len(), HMAC_SHA256_LEN);
593         let tag1b = hmac_sha256(key, msg1).unwrap();
594         assert_eq!(tag1a, tag1b);
595         let tag2 = hmac_sha256(key, msg2).unwrap();
596         assert_eq!(tag2.len(), HMAC_SHA256_LEN);
597         assert_ne!(tag1a, tag2);
598     }
599 }
600