1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
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 
16 //! This module is used to implement cryptographic algorithm operations, including key usage.
17 
18 use std::time::Instant;
19 
20 use asset_common::{transfer_error_code, CallingInfo, SUCCESS};
21 use asset_definition::{log_throw_error, ErrCode, Result};
22 
23 use crate::{secret_key::SecretKey, HksBlob, KeyId, OutBlob};
24 
25 extern "C" {
EncryptData(keyId: *const KeyId, aad: *const HksBlob, in_data: *const HksBlob, out_data: *mut OutBlob) -> i3226     fn EncryptData(keyId: *const KeyId, aad: *const HksBlob, in_data: *const HksBlob, out_data: *mut OutBlob) -> i32;
DecryptData(keyId: *const KeyId, aad: *const HksBlob, in_data: *const HksBlob, out_data: *mut OutBlob) -> i3227     fn DecryptData(keyId: *const KeyId, aad: *const HksBlob, in_data: *const HksBlob, out_data: *mut OutBlob) -> i32;
InitKey(keyId: *const KeyId, valid_time: u32, challenge: *mut OutBlob, handle: *mut OutBlob) -> i3228     fn InitKey(keyId: *const KeyId, valid_time: u32, challenge: *mut OutBlob, handle: *mut OutBlob) -> i32;
ExecCrypt( handle: *const HksBlob, aad: *const HksBlob, auth_token: *const HksBlob, in_data: *const HksBlob, out_data: *mut OutBlob, ) -> i3229     fn ExecCrypt(
30         handle: *const HksBlob,
31         aad: *const HksBlob,
32         auth_token: *const HksBlob,
33         in_data: *const HksBlob,
34         out_data: *mut OutBlob,
35     ) -> i32;
Drop(handle: *const HksBlob) -> i3236     fn Drop(handle: *const HksBlob) -> i32;
37 }
38 
39 const NONCE_SIZE: usize = 12;
40 const TAG_SIZE: usize = 16;
41 const HANDLE_LEN: usize = 8;
42 const CHALLENGE_LEN: usize = 32;
43 
44 /// Crypto for storing key attributes that require user authentication.
45 pub struct Crypto {
46     key: SecretKey,
47     calling_info: CallingInfo,
48     challenge: Vec<u8>,
49     handle: Vec<u8>,
50     valid_time: u32,
51     start_time: Instant,
52 }
53 
54 impl Crypto {
55     /// Create a crypto instance.
build(key: SecretKey, calling_info: CallingInfo, valid_time: u32) -> Result<Self>56     pub fn build(key: SecretKey, calling_info: CallingInfo, valid_time: u32) -> Result<Self> {
57         Ok(Self {
58             key,
59             calling_info,
60             challenge: vec![0; CHALLENGE_LEN],
61             handle: vec![0; HANDLE_LEN],
62             valid_time,
63             start_time: Instant::now(),
64         })
65     }
66 
67     /// Init secret key and get challenge.
init_key(&mut self) -> Result<&Vec<u8>>68     pub fn init_key(&mut self) -> Result<&Vec<u8>> {
69         let key_alias = HksBlob { size: self.key.alias().len() as u32, data: self.key.alias().as_ptr() };
70         let mut challenge = OutBlob { size: self.challenge.len() as u32, data: self.challenge.as_mut_ptr() };
71         let mut handle = OutBlob { size: self.handle.len() as u32, data: self.handle.as_mut_ptr() };
72         let key_id = KeyId::new(self.key.user_id(), key_alias, self.key.access_type());
73 
74         let ret = unsafe {
75             InitKey(
76                 &key_id as *const KeyId,
77                 self.valid_time,
78                 &mut challenge as *mut OutBlob,
79                 &mut handle as *mut OutBlob,
80             )
81         };
82         match ret {
83             SUCCESS => Ok(&self.challenge),
84             _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
85         }
86     }
87 
88     /// Decrypt data that requires user authentication.
exec_crypt(&self, cipher: &Vec<u8>, aad: &Vec<u8>, auth_token: &Vec<u8>) -> Result<Vec<u8>>89     pub fn exec_crypt(&self, cipher: &Vec<u8>, aad: &Vec<u8>, auth_token: &Vec<u8>) -> Result<Vec<u8>> {
90         if cipher.len() <= (TAG_SIZE + NONCE_SIZE) {
91             return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The cipher length is too short.");
92         }
93 
94         let aad = HksBlob { size: aad.len() as u32, data: aad.as_ptr() };
95         let auth_token = HksBlob { size: auth_token.len() as u32, data: auth_token.as_ptr() };
96         let handle = HksBlob { size: self.handle.len() as u32, data: self.handle.as_ptr() };
97         let in_data = HksBlob { size: cipher.len() as u32, data: cipher.as_ptr() };
98         let mut msg: Vec<u8> = vec![0; cipher.len() - TAG_SIZE - NONCE_SIZE];
99         let mut out_data = OutBlob { size: msg.len() as u32, data: msg.as_mut_ptr() };
100 
101         let ret = unsafe {
102             ExecCrypt(
103                 &handle as *const HksBlob,
104                 &aad as *const HksBlob,
105                 &auth_token as *const HksBlob,
106                 &in_data as *const HksBlob,
107                 &mut out_data as *mut OutBlob,
108             )
109         };
110         match ret {
111             SUCCESS => Ok(msg),
112             _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
113         }
114     }
115 
116     /// Encrypt data at one-time.
encrypt(key: &SecretKey, msg: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>>117     pub fn encrypt(key: &SecretKey, msg: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>> {
118         let mut cipher: Vec<u8> = vec![0; msg.len() + TAG_SIZE + NONCE_SIZE];
119         let key_alias = HksBlob { size: key.alias().len() as u32, data: key.alias().as_ptr() };
120         let aad_data = HksBlob { size: aad.len() as u32, data: aad.as_ptr() };
121         let in_data = HksBlob { size: msg.len() as u32, data: msg.as_ptr() };
122         let mut out_data = OutBlob { size: cipher.len() as u32, data: cipher.as_mut_ptr() };
123         let key_id = KeyId::new(key.user_id(), key_alias, key.access_type());
124 
125         let ret = unsafe {
126             EncryptData(
127                 &key_id as *const KeyId,
128                 &aad_data as *const HksBlob,
129                 &in_data as *const HksBlob,
130                 &mut out_data as *mut OutBlob,
131             )
132         };
133         match ret {
134             SUCCESS => Ok(cipher),
135             _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
136         }
137     }
138 
139     /// Encrypt data at one-time.
decrypt(key: &SecretKey, cipher: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>>140     pub fn decrypt(key: &SecretKey, cipher: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>> {
141         if cipher.len() <= (TAG_SIZE + NONCE_SIZE) {
142             return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The cipher length is too short.");
143         }
144 
145         let mut plain: Vec<u8> = vec![0; cipher.len() - TAG_SIZE - NONCE_SIZE];
146         let key_alias = HksBlob { size: key.alias().len() as u32, data: key.alias().as_ptr() };
147         let aad_data = HksBlob { size: aad.len() as u32, data: aad.as_ptr() };
148         let in_data = HksBlob { size: cipher.len() as u32, data: cipher.as_ptr() };
149         let mut out_data = OutBlob { size: plain.len() as u32, data: plain.as_mut_ptr() };
150         let key_id = KeyId::new(key.user_id(), key_alias, key.access_type());
151 
152         let ret = unsafe {
153             DecryptData(
154                 &key_id as *const KeyId,
155                 &aad_data as *const HksBlob,
156                 &in_data as *const HksBlob,
157                 &mut out_data as *mut OutBlob,
158             )
159         };
160         match ret {
161             SUCCESS => Ok(plain),
162             _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
163         }
164     }
165 
key(&self) -> &SecretKey166     pub(crate) fn key(&self) -> &SecretKey {
167         &self.key
168     }
169 
calling_info(&self) -> &CallingInfo170     pub(crate) fn calling_info(&self) -> &CallingInfo {
171         &self.calling_info
172     }
173 
challenge(&self) -> &Vec<u8>174     pub(crate) fn challenge(&self) -> &Vec<u8> {
175         &self.challenge
176     }
177 
start_time(&self) -> &Instant178     pub(crate) fn start_time(&self) -> &Instant {
179         &self.start_time
180     }
181 
valid_time(&self) -> u32182     pub(crate) fn valid_time(&self) -> u32 {
183         self.valid_time
184     }
185 }
186 
187 impl Drop for Crypto {
drop(&mut self)188     fn drop(&mut self) {
189         let handle = HksBlob { size: self.handle.len() as u32, data: self.handle.as_ptr() };
190         unsafe { Drop(&handle as *const HksBlob) };
191     }
192 }
193