rust_cryptoauthlib/
lib.rs

1#![allow(clippy::upper_case_acronyms)]
2
3#[macro_use]
4extern crate strum_macros; // 0.10.0
5#[macro_use]
6extern crate lazy_static;
7
8include!("types.rs");
9include!("constants.rs");
10
11mod atca_iface_cfg;
12mod hw_impl;
13mod sw_impl;
14#[cfg(test)]
15mod unit_tests;
16
17#[cfg(test)]
18use cryptoauthlib_sys::atca_aes_cbc_ctx_t;
19
20pub trait AteccDeviceTrait {
21    /// Request ATECC to generate a vector of random bytes
22    fn random(&self, rand_out: &mut Vec<u8>) -> AtcaStatus;
23    /// Request ATECC to compute a message hash (SHA256)
24    fn sha(&self, message: Vec<u8>, digest: &mut Vec<u8>) -> AtcaStatus;
25    /// Execute a Nonce command in pass-through mode to load one of the
26    /// device's internal buffers with a fixed value.
27    /// For the ATECC608A, available targets are TempKey (32 or 64 bytes), Message
28    /// Digest Buffer (32 or 64 bytes), or the Alternate Key Buffer (32 bytes). For
29    /// all other devices, only TempKey (32 bytes) is available.
30    fn nonce(&self, target: NonceTarget, data: &[u8]) -> AtcaStatus;
31    /// Execute a Nonce command to generate a random nonce combining a host
32    /// nonce and a device random number.
33    fn nonce_rand(&self, host_nonce: &[u8], rand_out: &mut Vec<u8>) -> AtcaStatus;
34    /// Request ATECC to generate a cryptographic key
35    fn gen_key(&self, key_type: KeyType, slot_id: u8) -> AtcaStatus;
36    /// Request ATECC to import a cryptographic key
37    fn import_key(&self, key_type: KeyType, key_data: &[u8], slot_id: u8) -> AtcaStatus;
38    /// Request ATECC to export a cryptographic key.
39    /// For cryptographic security reasons,
40    /// with KeyType = P256EccKey this function exports only public key
41    fn export_key(&self, key_type: KeyType, key_data: &mut Vec<u8>, slot_id: u8) -> AtcaStatus;
42    /// Depending on the socket configuration, this function calculates
43    /// public key based on an existing private key in the socket
44    /// or exports the public key directly
45    fn get_public_key(&self, slot_id: u8, public_key: &mut Vec<u8>) -> AtcaStatus;
46    /// Request ATECC to generate an ECDSA signature
47    fn sign_hash(&self, mode: SignMode, slot_id: u8, signature: &mut Vec<u8>) -> AtcaStatus;
48    /// Request ATECC to verify ECDSA signature
49    fn verify_hash(
50        &self,
51        mode: VerifyMode,
52        hash: &[u8],
53        signature: &[u8],
54    ) -> Result<bool, AtcaStatus>;
55    /// Data encryption function in AES unauthenticated cipher alhorithms modes
56    fn cipher_encrypt(
57        &self,
58        algorithm: CipherAlgorithm,
59        slot_id: u8,
60        data: &mut Vec<u8>,
61    ) -> AtcaStatus;
62    /// Data decryption function in AES unauthenticated cipher alhorithms modes
63    fn cipher_decrypt(
64        &self,
65        algorithm: CipherAlgorithm,
66        slot_id: u8,
67        data: &mut Vec<u8>,
68    ) -> AtcaStatus;
69    /// Data encryption function in AES AEAD (authenticated encryption with associated data) modes
70    fn aead_encrypt(
71        &self,
72        algorithm: AeadAlgorithm,
73        slot_id: u8,
74        data: &mut Vec<u8>,
75    ) -> Result<Vec<u8>, AtcaStatus>;
76    /// Data decryption function in AES AEAD (authenticated encryption with associated data) modes
77    fn aead_decrypt(
78        &self,
79        algorithm: AeadAlgorithm,
80        slot_id: u8,
81        data: &mut Vec<u8>,
82    ) -> Result<bool, AtcaStatus>;
83    /// A function that calculates the MAC (Message Authentication Code) value for a message
84    fn mac_compute(
85        &self,
86        algorithm: MacAlgorithm,
87        slot_id: u8,
88        data: &[u8],
89    ) -> Result<Vec<u8>, AtcaStatus>;
90    /// A function that verifies the value of MAC (Message Authentication Code) for a message
91    fn mac_verify(
92        &self,
93        algorithm: MacAlgorithm,
94        slot_id: u8,
95        data: &[u8],
96    ) -> Result<bool, AtcaStatus>;
97    /// KDF command function, which derives a new key in PRF, AES, or HKDF modes.
98    /// According to RFC-5869, the HKDF mode consists of two steps, extract and expand.
99    /// The "HMAC-Hash" base operation is implemented in the ATECC608x chip,
100    /// so to perform full HKDF operation, proceed as described in chapter 2 of RFC-5869,
101    /// first calculate PRK = HMAC-Hash(salt, IKM) and then use obtained PRK
102    /// to obtain the resulting OKM, again using the same "HMAC-Hash" function,
103    /// i.e. this "fn kdf", according to the algorithm from section 2.3 of RFC-5869.
104    fn kdf(
105        &self,
106        algorithm: KdfAlgorithm,
107        parameters: KdfParams,
108        message: Option<&[u8]>,
109        message_length: usize,
110    ) -> Result<KdfResult, AtcaStatus>;
111    /// Function for generating premaster secret key using ECDH
112    fn ecdh(
113        &self,
114        parameters: EcdhParams,
115        peer_public_key: &[u8],
116    ) -> Result<EcdhResult, AtcaStatus>;
117    /// Execute this command prevents future modifications of the Configuration zone.
118    /// This command fails if the designated area is already locked.
119    fn lock_config_zone(&self) -> AtcaStatus;
120    /// Execute this command prevents future modifications of the Data and OTP zones.
121    /// This command fails if the designated area is already locked.
122    fn lock_data_zone(&self) -> AtcaStatus;
123    /// Lock an individual slot in the data zone on an ATECC device. Not available for ATSHA devices.
124    /// Slot must be configured to be slot lockable slots[slot_idx].config.lockable = true.
125    /// This command fails if the designated area is already locked.
126    fn lock_slot(&self, slot_id: u8) -> AtcaStatus;
127    /// Function for uploading configuration to the chip.
128    /// First 16 bytes of data are skipped as they are not writable. LockValue and LockConfig
129    /// are also skipped and can only be changed via the Lock command.
130    /// This command may fail if UserExtra and/or Selector bytes have already been set to non-zero values.
131    fn load_config_into_chip(&self, config: &[u8]) -> AtcaStatus;
132    /// Request ATECC to return own device type
133    fn get_device_type(&self) -> AtcaDeviceType;
134    /// Request ATECC to check if its configuration is locked.
135    /// If true, a chip can be used for cryptographic operations
136    fn is_configuration_locked(&self) -> bool;
137    /// Request ATECC to check if its Data Zone is locked.
138    /// If true, a chip can be used for cryptographic operations
139    fn is_data_zone_locked(&self) -> bool;
140    /// Returns a structure containing configuration data read from ATECC
141    /// during initialization of the AteccDevice object.
142    fn get_config(&self, atca_slots: &mut Vec<AtcaSlot>) -> AtcaStatus;
143    /// Command accesses some static or dynamic information from the ATECC chip
144    fn info_cmd(&self, _command: InfoCmdType) -> Result<Vec<u8>, AtcaStatus>;
145    /// A function that adds an encryption key for securely reading or writing data
146    /// that is located in a specific slot on the ATECCx08 chip.
147    /// Data is not written to the ATECCx08 chip, but to the AteccDevice structure
148    fn add_access_key(&self, slot_id: u8, encryption_key: &[u8]) -> AtcaStatus;
149    /// A function that deletes all encryption keys for secure read or write operations
150    /// performed by the ATECCx08 chip
151    fn flush_access_keys(&self) -> AtcaStatus;
152    /// Get serial number of the ATECC device
153    fn get_serial_number(&self) -> [u8; ATCA_SERIAL_NUM_SIZE];
154    /// Checks if the chip supports AES encryption.
155    /// (only relevant for the ATECC608x chip)
156    fn is_aes_enabled(&self) -> bool;
157    /// Checks if the chip supports AES for KDF operations
158    /// (only relevant for the ATECC608x chip)
159    fn is_kdf_aes_enabled(&self) -> bool;
160    /// Checks if the special KDF Initialization Vector function is enabled
161    /// (only relevant for the ATECC608x chip)
162    fn is_kdf_iv_enabled(&self) -> bool;
163    /// Checks whether transmission between chip and host is to be encrypted
164    /// (IO encryption is only possible for ATECC608x chip)
165    fn is_io_protection_key_enabled(&self) -> bool;
166    /// Function that reads the read security settings of the ECDH function from chip
167    /// (only relevant for the ATECC608x chip)
168    fn get_ecdh_output_protection_state(&self) -> OutputProtectionState;
169    /// Function that reads the read security settings of the KDF function from chip
170    /// (only relevant for the ATECC608x chip)
171    fn get_kdf_output_protection_state(&self) -> OutputProtectionState;
172    /// wakeup the CryptoAuth device
173    fn wakeup(&self) -> AtcaStatus;
174    /// invoke sleep on the CryptoAuth device
175    fn sleep(&self) -> AtcaStatus;
176    /// ATECC device instance destructor
177    fn release(&self) -> AtcaStatus;
178
179    //--------------------------------------------------
180    //
181    // Functions available only during testing
182    //
183    //--------------------------------------------------
184
185    /// A generic function that reads data from the chip
186    #[cfg(test)]
187    fn read_zone(&self, zone: u8, slot: u16, block: u8, offset: u8, data: &mut [u8]) -> AtcaStatus;
188    /// Request ATECC to read and return own configuration zone.
189    /// Note: this function returns raw data, function get_config(..) implements a more
190    /// structured return value.
191    #[cfg(test)]
192    fn read_config_zone(&self, config_data: &mut Vec<u8>) -> AtcaStatus;
193    /// Compare internal config zone contents vs. config_data.
194    /// Diagnostic function.
195    #[cfg(test)]
196    fn cmp_config_zone(&self, config_data: &mut [u8]) -> Result<bool, AtcaStatus>;
197    /// A function that takes an encryption key for securely reading or writing data
198    /// that is located in a specific slot on an ATECCx08 chip.
199    /// Data is not taken directly from the ATECCx08 chip, but from the AteccDevice structure
200    #[cfg(test)]
201    fn get_access_key(&self, slot_id: u8, key: &mut Vec<u8>) -> AtcaStatus;
202    /// Perform an AES-128 encrypt operation with a key in the device
203    #[cfg(test)]
204    fn aes_encrypt_block(
205        &self,
206        key_id: u16,
207        key_block: u8,
208        input: &[u8],
209    ) -> Result<[u8; ATCA_AES_DATA_SIZE], AtcaStatus>;
210    /// Perform an AES-128 decrypt operation with a key in the device
211    #[cfg(test)]
212    fn aes_decrypt_block(
213        &self,
214        key_id: u16,
215        key_block: u8,
216        input: &[u8],
217    ) -> Result<[u8; ATCA_AES_DATA_SIZE], AtcaStatus>;
218    /// Initialize context for AES CTR operation with an existing IV, which
219    /// is common when start a decrypt operation
220    #[cfg(test)]
221    fn aes_ctr_init(
222        &self,
223        slot_id: u8,
224        counter_size: u8,
225        iv: &[u8],
226    ) -> Result<atca_aes_ctr_ctx_t, AtcaStatus>;
227    /// Increments AES CTR counter value
228    #[cfg(test)]
229    fn aes_ctr_increment(&self, ctx: atca_aes_ctr_ctx_t) -> Result<atca_aes_ctr_ctx_t, AtcaStatus>;
230    /// Initialize context for AES CBC operation.
231    #[cfg(test)]
232    fn aes_cbc_init(&self, slot_id: u8, iv: &[u8]) -> Result<atca_aes_cbc_ctx_t, AtcaStatus>;
233    /// A helper function that returns number of blocks and bytes of data
234    /// available for a given socket
235    #[cfg(test)]
236    fn get_slot_capacity(&self, slot_id: u8) -> AtcaSlotCapacity;
237}
238
239pub type AteccDevice = Box<dyn AteccDeviceTrait + Send + Sync>;
240
241pub fn setup_atecc_device(r_iface_cfg: AtcaIfaceCfg) -> Result<AteccDevice, String> {
242    match r_iface_cfg.devtype {
243        AtcaDeviceType::AtcaTestDevSuccess
244        | AtcaDeviceType::AtcaTestDevFail
245        | AtcaDeviceType::AtcaTestDevFailUnimplemented => {
246            match sw_impl::AteccDevice::new(r_iface_cfg) {
247                Ok(x) => Ok(Box::new(x)),
248                Err(err) => Err(err),
249            }
250        }
251        AtcaDeviceType::AtcaDevUnknown => {
252            Err(String::from("Attempting to create an unknown device type"))
253        }
254        _ => match hw_impl::AteccDevice::new(r_iface_cfg) {
255            Ok(x) => Ok(Box::new(x)),
256            Err(err) => Err(err),
257        },
258    }
259}
260
261impl AtcaSlot {
262    pub fn is_valid(self) -> bool {
263        // As long as exclusive range is experimental, this should work.
264        // self.id is always greater than 0
265        self.id < ATCA_ATECC_SLOTS_COUNT
266    }
267}