blob: 5f8a2ef24c3056d0820d44b86d0279f8e39c55d1 [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;
19mod zvec;
20pub use error::Error;
21use keystore2_crypto_bindgen::{
Shawn Willden8fde4c22021-02-14 13:58:22 -070022 extractSubjectFromCertificate, generateKeyFromPassword, randomBytes, AES_gcm_decrypt,
Paul Crowley7bb5edd2021-03-20 20:26:43 -070023 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,
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;
42
Paul Crowley9a7f5a52021-04-23 16:12:08 -070043/// Older versions of keystore produced IVs with four extra
44/// ignored zero bytes at the end; recognise and trim those.
45pub const LEGACY_IV_LENGTH: usize = 16;
Janis Danisevskis9d90b812020-11-25 21:02:11 -080046
47/// Generate an AES256 key, essentially 32 random bytes from the underlying
48/// boringssl library discretely stuffed into a ZVec.
49pub 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)?;
Joel Galenson05914582021-01-08 09:30:41 -080052 if unsafe { randomBytes(key.as_mut_ptr(), AES_256_KEY_LENGTH) } {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080053 Ok(key)
54 } else {
55 Err(Error::RandomNumberGenerationFailed)
56 }
57}
58
59/// Generate a salt.
60pub fn generate_salt() -> Result<Vec<u8>, Error> {
David Drysdale0e45a612021-02-25 17:24:36 +000061 generate_random_data(SALT_LENGTH)
62}
63
64/// Generate random data of the given size.
65pub 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)
Janis Danisevskis9d90b812020-11-25 21:02:11 -080070 } 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.
82pub fn aes_gcm_decrypt(data: &[u8], iv: &[u8], tag: &[u8], key: &[u8]) -> Result<ZVec, Error> {
Paul Crowley9a7f5a52021-04-23 16:12:08 -070083 // 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 };
Janis Danisevskis9d90b812020-11-25 21:02:11 -080090 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
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700102 // 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.
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800104 match unsafe {
105 AES_gcm_decrypt(
106 data.as_ptr(),
107 result.as_mut_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800108 data.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800109 key.as_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800110 key.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800111 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)`.
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700124pub 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.
Joel Galenson05914582021-01-08 09:30:41 -0800127 if !unsafe { randomBytes(iv.as_mut_ptr(), GCM_IV_LENGTH) } {
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800128 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
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700136 let mut ciphertext: Vec<u8> = vec![0; plaintext.len()];
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800137 let mut tag: Vec<u8> = vec![0; TAG_LENGTH];
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700138 // 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 {
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800142 AES_gcm_encrypt(
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700143 plaintext.as_ptr(),
144 ciphertext.as_mut_ptr(),
145 plaintext.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800146 key.as_ptr(),
Joel Galenson05914582021-01-08 09:30:41 -0800147 key.len(),
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800148 iv.as_ptr(),
149 tag.as_mut_ptr(),
150 )
151 } {
Paul Crowley9a7f5a52021-04-23 16:12:08 -0700152 Ok((ciphertext, iv, tag))
153 } else {
154 Err(Error::EncryptionFailed)
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800155 }
156}
157
Paul Crowleyf61fee72021-03-17 14:38:44 -0700158/// Represents a "password" that can be used to key the PBKDF2 algorithm.
159pub 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}
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800165
Paul Crowleyf61fee72021-03-17 14:38:44 -0700166impl<'a> From<&'a [u8]> for Password<'a> {
167 fn from(pw: &'a [u8]) -> Self {
168 Self::Ref(pw)
169 }
170}
171
172impl<'a> Password<'a> {
173 fn get_key(&'a self) -> &'a [u8] {
174 match self {
175 Self::Ref(b) => b,
176 Self::Owned(z) => &*z,
177 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800178 }
179
Paul Crowleyf61fee72021-03-17 14:38:44 -0700180 /// 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.
183 pub fn derive_key(&self, salt: Option<&[u8]>, key_length: usize) -> Result<ZVec, Error> {
184 let pw = self.get_key();
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800185
Paul Crowleyf61fee72021-03-17 14:38:44 -0700186 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 };
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800195
Paul Crowleyf61fee72021-03-17 14:38:44 -0700196 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.
217 pub fn try_clone(&self) -> Result<Password<'static>, Error> {
218 Ok(Password::Owned(ZVec::try_from(self.get_key())?))
219 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800220}
Joel Galenson46d6fd02020-11-19 17:58:33 -0800221
Joel Galenson05914582021-01-08 09:30:41 -0800222/// Calls the boringssl HKDF_extract function.
223pub 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.
253pub 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.
267pub struct ECKey(*mut EC_KEY);
268
269impl Drop for ECKey {
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.
283pub struct OwnedECPoint(*mut EC_POINT);
284
285/// A pointer to an EC_POINT object.
286pub struct BorrowedECPoint<'a> {
287 data: *const EC_POINT,
288 phantom: PhantomData<&'a EC_POINT>,
289}
290
291impl OwnedECPoint {
292 /// Get the wrapped EC_POINT object.
293 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
299impl<'a> BorrowedECPoint<'a> {
300 /// Get the wrapped EC_POINT object.
301 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
307impl Drop for OwnedECPoint {
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.
316pub 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.
338pub 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
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700347/// Calls the boringssl EC_KEY_marshal_private_key function.
348pub fn ec_key_marshal_private_key(key: &ECKey) -> Result<ZVec, Error> {
Paul Crowley52f017f2021-06-22 08:16:01 -0700349 let len = 73; // Empirically observed length of private key
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700350 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)
Joel Galenson05914582021-01-08 09:30:41 -0800360 }
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700361}
362
363/// Calls the boringssl EC_KEY_parse_private_key function.
364pub 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 }
Joel Galenson05914582021-01-08 09:30:41 -0800373}
374
375/// Calls the boringssl EC_KEY_get0_public_key function.
376pub 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.
383pub fn ec_point_point_to_oct(point: &EC_POINT) -> Result<Vec<u8>, Error> {
Paul Crowley52f017f2021-06-22 08:16:01 -0700384 // 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;
Joel Galenson05914582021-01-08 09:30:41 -0800386 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.
401pub 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
Shawn Willden34120872021-02-24 21:56:30 -0700412/// Uses BoringSSL to extract the DER-encoded subject from a DER-encoded X.509 certificate.
413pub fn parse_subject_from_certificate(cert_buf: &[u8]) -> Result<Vec<u8>, Error> {
Shawn Willden8fde4c22021-02-14 13:58:22 -0700414 // Try with a 200-byte output buffer, should be enough in all but bizarre cases.
415 let mut retval = vec![0; 200];
Shawn Willden34120872021-02-24 21:56:30 -0700416
417 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf and
418 // writes at most retval.len() bytes to retval.
Shawn Willden8fde4c22021-02-14 13:58:22 -0700419 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.
Shawn Willden34120872021-02-24 21:56:30 -0700434 let negated_size = usize::try_from(-size).map_err(|_e| Error::ExtractSubjectFailed)?;
435 retval = vec![0; negated_size];
Shawn Willden8fde4c22021-02-14 13:58:22 -0700436
Shawn Willden34120872021-02-24 21:56:30 -0700437 // Safety: extractSubjectFromCertificate reads at most cert_buf.len() bytes from cert_buf
438 // and writes at most retval.len() bytes to retval.
Shawn Willden8fde4c22021-02-14 13:58:22 -0700439 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.
Shawn Willden34120872021-02-24 21:56:30 -0700454 let safe_size = usize::try_from(size).map_err(|_e| Error::ExtractSubjectFailed)?;
455 retval.truncate(safe_size);
Shawn Willden8fde4c22021-02-14 13:58:22 -0700456
457 Ok(retval)
458}
459
Joel Galensonca0efb12020-10-01 14:32:30 -0700460#[cfg(test)]
461mod tests {
462
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800463 use super::*;
Joel Galensonca0efb12020-10-01 14:32:30 -0700464 use keystore2_crypto_bindgen::{
465 generateKeyFromPassword, AES_gcm_decrypt, AES_gcm_encrypt, CreateKeyId,
466 };
467
468 #[test]
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800469 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]
Joel Galensonca0efb12020-10-01 14:32:30 -0700478 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]
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]
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 }
Joel Galenson05914582021-01-08 09:30:41 -0800533
534 #[test]
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]
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700546 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);
Joel Galenson05914582021-01-08 09:30:41 -0800550
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700551 let priv1 = ec_key_generate_key()?;
552 let pub1 = ec_key_get0_public_key(&priv1);
Joel Galenson05914582021-01-08 09:30:41 -0800553
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700554 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())?;
Joel Galenson05914582021-01-08 09:30:41 -0800557
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700558 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)?;
Joel Galenson05914582021-01-08 09:30:41 -0800561
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700562 let left_key = ecdh_compute_key(pub0.get_point(), &priv1)?;
563 let right_key = ecdh_compute_key(pub1.get_point(), &priv0)?;
Joel Galenson05914582021-01-08 09:30:41 -0800564
Paul Crowley7bb5edd2021-03-20 20:26:43 -0700565 assert_eq!(left_key, right_key);
566 Ok(())
Joel Galenson05914582021-01-08 09:30:41 -0800567 }
Joel Galensonca0efb12020-10-01 14:32:30 -0700568}