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, 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 challenge: Vec<u8>, 48 handle: Vec<u8>, 49 valid_time: u32, 50 start_time: Instant, 51 } 52 53 impl Crypto { 54 /// Create a crypto instance. build(key: SecretKey, valid_time: u32) -> Result<Self>55 pub fn build(key: SecretKey, valid_time: u32) -> Result<Self> { 56 Ok(Self { 57 key, 58 challenge: vec![0; CHALLENGE_LEN], 59 handle: vec![0; HANDLE_LEN], 60 valid_time, 61 start_time: Instant::now(), 62 }) 63 } 64 65 /// Init secret key and get challenge. init_key(&mut self) -> Result<&Vec<u8>>66 pub fn init_key(&mut self) -> Result<&Vec<u8>> { 67 let key_alias = HksBlob { size: self.key.alias().len() as u32, data: self.key.alias().as_ptr() }; 68 let mut challenge = OutBlob { size: self.challenge.len() as u32, data: self.challenge.as_mut_ptr() }; 69 let mut handle = OutBlob { size: self.handle.len() as u32, data: self.handle.as_mut_ptr() }; 70 let key_id = KeyId::new(self.key.calling_info().user_id(), key_alias, self.key.access_type()); 71 72 let ret = unsafe { 73 InitKey( 74 &key_id as *const KeyId, 75 self.valid_time, 76 &mut challenge as *mut OutBlob, 77 &mut handle as *mut OutBlob, 78 ) 79 }; 80 match ret { 81 SUCCESS => Ok(&self.challenge), 82 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)), 83 } 84 } 85 86 /// Decrypt data that requires user authentication. exec_crypt(&self, cipher: &Vec<u8>, aad: &Vec<u8>, auth_token: &Vec<u8>) -> Result<Vec<u8>>87 pub fn exec_crypt(&self, cipher: &Vec<u8>, aad: &Vec<u8>, auth_token: &Vec<u8>) -> Result<Vec<u8>> { 88 if cipher.len() <= (TAG_SIZE + NONCE_SIZE) { 89 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The cipher length is too short."); 90 } 91 92 let aad = HksBlob { size: aad.len() as u32, data: aad.as_ptr() }; 93 let auth_token = HksBlob { size: auth_token.len() as u32, data: auth_token.as_ptr() }; 94 let handle = HksBlob { size: self.handle.len() as u32, data: self.handle.as_ptr() }; 95 let in_data = HksBlob { size: cipher.len() as u32, data: cipher.as_ptr() }; 96 let mut msg: Vec<u8> = vec![0; cipher.len() - TAG_SIZE - NONCE_SIZE]; 97 let mut out_data = OutBlob { size: msg.len() as u32, data: msg.as_mut_ptr() }; 98 99 let ret = unsafe { 100 ExecCrypt( 101 &handle as *const HksBlob, 102 &aad as *const HksBlob, 103 &auth_token as *const HksBlob, 104 &in_data as *const HksBlob, 105 &mut out_data as *mut OutBlob, 106 ) 107 }; 108 match ret { 109 SUCCESS => Ok(msg), 110 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)), 111 } 112 } 113 114 /// Encrypt data at one-time. encrypt(key: &SecretKey, msg: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>>115 pub fn encrypt(key: &SecretKey, msg: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>> { 116 let mut cipher: Vec<u8> = vec![0; msg.len() + TAG_SIZE + NONCE_SIZE]; 117 let key_alias = HksBlob { size: key.alias().len() as u32, data: key.alias().as_ptr() }; 118 let aad_data = HksBlob { size: aad.len() as u32, data: aad.as_ptr() }; 119 let in_data = HksBlob { size: msg.len() as u32, data: msg.as_ptr() }; 120 let mut out_data = OutBlob { size: cipher.len() as u32, data: cipher.as_mut_ptr() }; 121 let key_id = KeyId::new(key.calling_info().user_id(), key_alias, key.access_type()); 122 123 let ret = unsafe { 124 EncryptData( 125 &key_id as *const KeyId, 126 &aad_data as *const HksBlob, 127 &in_data as *const HksBlob, 128 &mut out_data as *mut OutBlob, 129 ) 130 }; 131 match ret { 132 SUCCESS => Ok(cipher), 133 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)), 134 } 135 } 136 137 /// Encrypt data at one-time. decrypt(key: &SecretKey, cipher: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>>138 pub fn decrypt(key: &SecretKey, cipher: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>> { 139 if cipher.len() <= (TAG_SIZE + NONCE_SIZE) { 140 return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The cipher length is too short."); 141 } 142 143 let mut plain: Vec<u8> = vec![0; cipher.len() - TAG_SIZE - NONCE_SIZE]; 144 let key_alias = HksBlob { size: key.alias().len() as u32, data: key.alias().as_ptr() }; 145 let aad_data = HksBlob { size: aad.len() as u32, data: aad.as_ptr() }; 146 let in_data = HksBlob { size: cipher.len() as u32, data: cipher.as_ptr() }; 147 let mut out_data = OutBlob { size: plain.len() as u32, data: plain.as_mut_ptr() }; 148 let key_id = KeyId::new(key.calling_info().user_id(), key_alias, key.access_type()); 149 150 let ret = unsafe { 151 DecryptData( 152 &key_id as *const KeyId, 153 &aad_data as *const HksBlob, 154 &in_data as *const HksBlob, 155 &mut out_data as *mut OutBlob, 156 ) 157 }; 158 match ret { 159 SUCCESS => Ok(plain), 160 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)), 161 } 162 } 163 key(&self) -> &SecretKey164 pub(crate) fn key(&self) -> &SecretKey { 165 &self.key 166 } 167 challenge(&self) -> &Vec<u8>168 pub(crate) fn challenge(&self) -> &Vec<u8> { 169 &self.challenge 170 } 171 start_time(&self) -> &Instant172 pub(crate) fn start_time(&self) -> &Instant { 173 &self.start_time 174 } 175 valid_time(&self) -> u32176 pub(crate) fn valid_time(&self) -> u32 { 177 self.valid_time 178 } 179 } 180 181 impl Drop for Crypto { drop(&mut self)182 fn drop(&mut self) { 183 let handle = HksBlob { size: self.handle.len() as u32, data: self.handle.as_ptr() }; 184 unsafe { Drop(&handle as *const HksBlob) }; 185 } 186 } 187