1dfe32fa1Soh_ci/*
2dfe32fa1Soh_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3dfe32fa1Soh_ci * Licensed under the Apache License, Version 2.0 (the "License");
4dfe32fa1Soh_ci * you may not use this file except in compliance with the License.
5dfe32fa1Soh_ci * You may obtain a copy of the License at
6dfe32fa1Soh_ci *
7dfe32fa1Soh_ci *     http://www.apache.org/licenses/LICENSE-2.0
8dfe32fa1Soh_ci *
9dfe32fa1Soh_ci * Unless required by applicable law or agreed to in writing, software
10dfe32fa1Soh_ci * distributed under the License is distributed on an "AS IS" BASIS,
11dfe32fa1Soh_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12dfe32fa1Soh_ci * See the License for the specific language governing permissions and
13dfe32fa1Soh_ci * limitations under the License.
14dfe32fa1Soh_ci */
15dfe32fa1Soh_ci
16dfe32fa1Soh_ci//! This module is used to implement cryptographic algorithm operations, including key usage.
17dfe32fa1Soh_ci
18dfe32fa1Soh_ciuse std::time::Instant;
19dfe32fa1Soh_ci
20dfe32fa1Soh_ciuse asset_common::{transfer_error_code, CallingInfo, SUCCESS};
21dfe32fa1Soh_ciuse asset_definition::{log_throw_error, ErrCode, Result};
22dfe32fa1Soh_ci
23dfe32fa1Soh_ciuse crate::{secret_key::SecretKey, HksBlob, KeyId, OutBlob};
24dfe32fa1Soh_ci
25dfe32fa1Soh_ciextern "C" {
26dfe32fa1Soh_ci    fn EncryptData(keyId: *const KeyId, aad: *const HksBlob, in_data: *const HksBlob, out_data: *mut OutBlob) -> i32;
27dfe32fa1Soh_ci    fn DecryptData(keyId: *const KeyId, aad: *const HksBlob, in_data: *const HksBlob, out_data: *mut OutBlob) -> i32;
28dfe32fa1Soh_ci    fn InitKey(keyId: *const KeyId, valid_time: u32, challenge: *mut OutBlob, handle: *mut OutBlob) -> i32;
29dfe32fa1Soh_ci    fn ExecCrypt(
30dfe32fa1Soh_ci        handle: *const HksBlob,
31dfe32fa1Soh_ci        aad: *const HksBlob,
32dfe32fa1Soh_ci        auth_token: *const HksBlob,
33dfe32fa1Soh_ci        in_data: *const HksBlob,
34dfe32fa1Soh_ci        out_data: *mut OutBlob,
35dfe32fa1Soh_ci    ) -> i32;
36dfe32fa1Soh_ci    fn Drop(handle: *const HksBlob) -> i32;
37dfe32fa1Soh_ci}
38dfe32fa1Soh_ci
39dfe32fa1Soh_ciconst NONCE_SIZE: usize = 12;
40dfe32fa1Soh_ciconst TAG_SIZE: usize = 16;
41dfe32fa1Soh_ciconst HANDLE_LEN: usize = 8;
42dfe32fa1Soh_ciconst CHALLENGE_LEN: usize = 32;
43dfe32fa1Soh_ci
44dfe32fa1Soh_ci/// Crypto for storing key attributes that require user authentication.
45dfe32fa1Soh_cipub struct Crypto {
46dfe32fa1Soh_ci    key: SecretKey,
47dfe32fa1Soh_ci    calling_info: CallingInfo,
48dfe32fa1Soh_ci    challenge: Vec<u8>,
49dfe32fa1Soh_ci    handle: Vec<u8>,
50dfe32fa1Soh_ci    valid_time: u32,
51dfe32fa1Soh_ci    start_time: Instant,
52dfe32fa1Soh_ci}
53dfe32fa1Soh_ci
54dfe32fa1Soh_ciimpl Crypto {
55dfe32fa1Soh_ci    /// Create a crypto instance.
56dfe32fa1Soh_ci    pub fn build(key: SecretKey, calling_info: CallingInfo, valid_time: u32) -> Result<Self> {
57dfe32fa1Soh_ci        Ok(Self {
58dfe32fa1Soh_ci            key,
59dfe32fa1Soh_ci            calling_info,
60dfe32fa1Soh_ci            challenge: vec![0; CHALLENGE_LEN],
61dfe32fa1Soh_ci            handle: vec![0; HANDLE_LEN],
62dfe32fa1Soh_ci            valid_time,
63dfe32fa1Soh_ci            start_time: Instant::now(),
64dfe32fa1Soh_ci        })
65dfe32fa1Soh_ci    }
66dfe32fa1Soh_ci
67dfe32fa1Soh_ci    /// Init secret key and get challenge.
68dfe32fa1Soh_ci    pub fn init_key(&mut self) -> Result<&Vec<u8>> {
69dfe32fa1Soh_ci        let key_alias = HksBlob { size: self.key.alias().len() as u32, data: self.key.alias().as_ptr() };
70dfe32fa1Soh_ci        let mut challenge = OutBlob { size: self.challenge.len() as u32, data: self.challenge.as_mut_ptr() };
71dfe32fa1Soh_ci        let mut handle = OutBlob { size: self.handle.len() as u32, data: self.handle.as_mut_ptr() };
72dfe32fa1Soh_ci        let key_id = KeyId::new(self.key.user_id(), key_alias, self.key.access_type());
73dfe32fa1Soh_ci
74dfe32fa1Soh_ci        let ret = unsafe {
75dfe32fa1Soh_ci            InitKey(
76dfe32fa1Soh_ci                &key_id as *const KeyId,
77dfe32fa1Soh_ci                self.valid_time,
78dfe32fa1Soh_ci                &mut challenge as *mut OutBlob,
79dfe32fa1Soh_ci                &mut handle as *mut OutBlob,
80dfe32fa1Soh_ci            )
81dfe32fa1Soh_ci        };
82dfe32fa1Soh_ci        match ret {
83dfe32fa1Soh_ci            SUCCESS => Ok(&self.challenge),
84dfe32fa1Soh_ci            _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
85dfe32fa1Soh_ci        }
86dfe32fa1Soh_ci    }
87dfe32fa1Soh_ci
88dfe32fa1Soh_ci    /// Decrypt data that requires user authentication.
89dfe32fa1Soh_ci    pub fn exec_crypt(&self, cipher: &Vec<u8>, aad: &Vec<u8>, auth_token: &Vec<u8>) -> Result<Vec<u8>> {
90dfe32fa1Soh_ci        if cipher.len() <= (TAG_SIZE + NONCE_SIZE) {
91dfe32fa1Soh_ci            return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The cipher length is too short.");
92dfe32fa1Soh_ci        }
93dfe32fa1Soh_ci
94dfe32fa1Soh_ci        let aad = HksBlob { size: aad.len() as u32, data: aad.as_ptr() };
95dfe32fa1Soh_ci        let auth_token = HksBlob { size: auth_token.len() as u32, data: auth_token.as_ptr() };
96dfe32fa1Soh_ci        let handle = HksBlob { size: self.handle.len() as u32, data: self.handle.as_ptr() };
97dfe32fa1Soh_ci        let in_data = HksBlob { size: cipher.len() as u32, data: cipher.as_ptr() };
98dfe32fa1Soh_ci        let mut msg: Vec<u8> = vec![0; cipher.len() - TAG_SIZE - NONCE_SIZE];
99dfe32fa1Soh_ci        let mut out_data = OutBlob { size: msg.len() as u32, data: msg.as_mut_ptr() };
100dfe32fa1Soh_ci
101dfe32fa1Soh_ci        let ret = unsafe {
102dfe32fa1Soh_ci            ExecCrypt(
103dfe32fa1Soh_ci                &handle as *const HksBlob,
104dfe32fa1Soh_ci                &aad as *const HksBlob,
105dfe32fa1Soh_ci                &auth_token as *const HksBlob,
106dfe32fa1Soh_ci                &in_data as *const HksBlob,
107dfe32fa1Soh_ci                &mut out_data as *mut OutBlob,
108dfe32fa1Soh_ci            )
109dfe32fa1Soh_ci        };
110dfe32fa1Soh_ci        match ret {
111dfe32fa1Soh_ci            SUCCESS => Ok(msg),
112dfe32fa1Soh_ci            _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
113dfe32fa1Soh_ci        }
114dfe32fa1Soh_ci    }
115dfe32fa1Soh_ci
116dfe32fa1Soh_ci    /// Encrypt data at one-time.
117dfe32fa1Soh_ci    pub fn encrypt(key: &SecretKey, msg: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>> {
118dfe32fa1Soh_ci        let mut cipher: Vec<u8> = vec![0; msg.len() + TAG_SIZE + NONCE_SIZE];
119dfe32fa1Soh_ci        let key_alias = HksBlob { size: key.alias().len() as u32, data: key.alias().as_ptr() };
120dfe32fa1Soh_ci        let aad_data = HksBlob { size: aad.len() as u32, data: aad.as_ptr() };
121dfe32fa1Soh_ci        let in_data = HksBlob { size: msg.len() as u32, data: msg.as_ptr() };
122dfe32fa1Soh_ci        let mut out_data = OutBlob { size: cipher.len() as u32, data: cipher.as_mut_ptr() };
123dfe32fa1Soh_ci        let key_id = KeyId::new(key.user_id(), key_alias, key.access_type());
124dfe32fa1Soh_ci
125dfe32fa1Soh_ci        let ret = unsafe {
126dfe32fa1Soh_ci            EncryptData(
127dfe32fa1Soh_ci                &key_id as *const KeyId,
128dfe32fa1Soh_ci                &aad_data as *const HksBlob,
129dfe32fa1Soh_ci                &in_data as *const HksBlob,
130dfe32fa1Soh_ci                &mut out_data as *mut OutBlob,
131dfe32fa1Soh_ci            )
132dfe32fa1Soh_ci        };
133dfe32fa1Soh_ci        match ret {
134dfe32fa1Soh_ci            SUCCESS => Ok(cipher),
135dfe32fa1Soh_ci            _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
136dfe32fa1Soh_ci        }
137dfe32fa1Soh_ci    }
138dfe32fa1Soh_ci
139dfe32fa1Soh_ci    /// Encrypt data at one-time.
140dfe32fa1Soh_ci    pub fn decrypt(key: &SecretKey, cipher: &Vec<u8>, aad: &Vec<u8>) -> Result<Vec<u8>> {
141dfe32fa1Soh_ci        if cipher.len() <= (TAG_SIZE + NONCE_SIZE) {
142dfe32fa1Soh_ci            return log_throw_error!(ErrCode::InvalidArgument, "[FATAL]The cipher length is too short.");
143dfe32fa1Soh_ci        }
144dfe32fa1Soh_ci
145dfe32fa1Soh_ci        let mut plain: Vec<u8> = vec![0; cipher.len() - TAG_SIZE - NONCE_SIZE];
146dfe32fa1Soh_ci        let key_alias = HksBlob { size: key.alias().len() as u32, data: key.alias().as_ptr() };
147dfe32fa1Soh_ci        let aad_data = HksBlob { size: aad.len() as u32, data: aad.as_ptr() };
148dfe32fa1Soh_ci        let in_data = HksBlob { size: cipher.len() as u32, data: cipher.as_ptr() };
149dfe32fa1Soh_ci        let mut out_data = OutBlob { size: plain.len() as u32, data: plain.as_mut_ptr() };
150dfe32fa1Soh_ci        let key_id = KeyId::new(key.user_id(), key_alias, key.access_type());
151dfe32fa1Soh_ci
152dfe32fa1Soh_ci        let ret = unsafe {
153dfe32fa1Soh_ci            DecryptData(
154dfe32fa1Soh_ci                &key_id as *const KeyId,
155dfe32fa1Soh_ci                &aad_data as *const HksBlob,
156dfe32fa1Soh_ci                &in_data as *const HksBlob,
157dfe32fa1Soh_ci                &mut out_data as *mut OutBlob,
158dfe32fa1Soh_ci            )
159dfe32fa1Soh_ci        };
160dfe32fa1Soh_ci        match ret {
161dfe32fa1Soh_ci            SUCCESS => Ok(plain),
162dfe32fa1Soh_ci            _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
163dfe32fa1Soh_ci        }
164dfe32fa1Soh_ci    }
165dfe32fa1Soh_ci
166dfe32fa1Soh_ci    pub(crate) fn key(&self) -> &SecretKey {
167dfe32fa1Soh_ci        &self.key
168dfe32fa1Soh_ci    }
169dfe32fa1Soh_ci
170dfe32fa1Soh_ci    pub(crate) fn calling_info(&self) -> &CallingInfo {
171dfe32fa1Soh_ci        &self.calling_info
172dfe32fa1Soh_ci    }
173dfe32fa1Soh_ci
174dfe32fa1Soh_ci    pub(crate) fn challenge(&self) -> &Vec<u8> {
175dfe32fa1Soh_ci        &self.challenge
176dfe32fa1Soh_ci    }
177dfe32fa1Soh_ci
178dfe32fa1Soh_ci    pub(crate) fn start_time(&self) -> &Instant {
179dfe32fa1Soh_ci        &self.start_time
180dfe32fa1Soh_ci    }
181dfe32fa1Soh_ci
182dfe32fa1Soh_ci    pub(crate) fn valid_time(&self) -> u32 {
183dfe32fa1Soh_ci        self.valid_time
184dfe32fa1Soh_ci    }
185dfe32fa1Soh_ci}
186dfe32fa1Soh_ci
187dfe32fa1Soh_ciimpl Drop for Crypto {
188dfe32fa1Soh_ci    fn drop(&mut self) {
189dfe32fa1Soh_ci        let handle = HksBlob { size: self.handle.len() as u32, data: self.handle.as_ptr() };
190dfe32fa1Soh_ci        unsafe { Drop(&handle as *const HksBlob) };
191dfe32fa1Soh_ci    }
192dfe32fa1Soh_ci}
193