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 manage crypto in cache.
17 
18 use std::{
19     cmp::max,
20     sync::{Arc, Mutex},
21 };
22 
23 use asset_common::CallingInfo;
24 use asset_definition::{log_throw_error, ErrCode, Result};
25 
26 use crate::crypto::Crypto;
27 
28 const CRYPTO_CAPACITY: usize = 16;
29 
30 /// Manages the crypto that required user authentication.
31 pub struct CryptoManager {
32     cryptos: Vec<Crypto>,
33 }
34 
35 impl CryptoManager {
new() -> Self36     fn new() -> Self {
37         Self { cryptos: vec![] }
38     }
39 
40     /// Get the single instance of CryptoManager.
get_instance() -> Arc<Mutex<CryptoManager>>41     pub fn get_instance() -> Arc<Mutex<CryptoManager>> {
42         static mut INSTANCE: Option<Arc<Mutex<CryptoManager>>> = None;
43         unsafe { INSTANCE.get_or_insert_with(|| Arc::new(Mutex::new(CryptoManager::new()))).clone() }
44     }
45 
46     /// Add the crypto to manager.
add(&mut self, crypto: Crypto) -> Result<()>47     pub fn add(&mut self, crypto: Crypto) -> Result<()> {
48         self.remove_expired_crypto()?;
49         if self.cryptos.len() >= CRYPTO_CAPACITY {
50             log_throw_error!(ErrCode::LimitExceeded, "The number of cryptos exceeds the upper limit.")
51         } else {
52             self.cryptos.push(crypto);
53             Ok(())
54         }
55     }
56 
57     /// Find the crypto with the specified alias and challenge slice from manager.
find(&mut self, calling_info: &CallingInfo, challenge: &Vec<u8>) -> Result<&Crypto>58     pub fn find(&mut self, calling_info: &CallingInfo, challenge: &Vec<u8>) -> Result<&Crypto> {
59         self.remove_expired_crypto()?;
60         for crypto in self.cryptos.iter() {
61             if crypto.challenge().eq(challenge) && crypto.calling_info().eq(calling_info) {
62                 return Ok(crypto);
63             }
64         }
65         log_throw_error!(ErrCode::NotFound, "The crypto expires or does not exist. Call the preQuery first.")
66     }
67 
68     /// Remove the crypto from manager.
remove(&mut self, calling_info: &CallingInfo, challenge: &Vec<u8>)69     pub fn remove(&mut self, calling_info: &CallingInfo, challenge: &Vec<u8>) {
70         self.cryptos.retain(|crypto| crypto.calling_info() != calling_info || !crypto.challenge().eq(challenge));
71     }
72 
73     /// Remove the crypto by calling info.
remove_by_calling_info(&mut self, calling_info: &CallingInfo)74     pub fn remove_by_calling_info(&mut self, calling_info: &CallingInfo) {
75         self.cryptos.retain(|crypto| crypto.calling_info() != calling_info);
76     }
77 
78     /// Remove cryptos that required device to be unlocked.
remove_need_device_unlocked(&mut self)79     pub fn remove_need_device_unlocked(&mut self) {
80         self.cryptos.retain(|crypto| !crypto.key().need_device_unlock());
81     }
82 
83     /// Get last crypto expire time.
max_crypto_expire_duration(&mut self) -> u6484     pub fn max_crypto_expire_duration(&mut self) -> u64 {
85         self.remove_expired_crypto().unwrap();
86         let mut max_time = 0;
87         for crypto in &self.cryptos {
88             max_time = max(crypto.valid_time() as u64 - crypto.start_time().elapsed().as_secs(), max_time)
89         }
90         max_time
91     }
92 
remove_expired_crypto(&mut self) -> Result<()>93     fn remove_expired_crypto(&mut self) -> Result<()> {
94         self.cryptos.retain(|crypto| crypto.start_time().elapsed().as_secs() <= crypto.valid_time() as u64);
95         Ok(())
96     }
97 }
98