rust_cryptoauthlib/hw_impl/
mac.rs1use std::cmp::min;
2use std::mem::MaybeUninit;
3
4use super::{AtcaDeviceType, AtcaStatus, AteccDevice, KeyType, MacParam, NonceTarget};
5
6use super::{
7 ATCA_AES_DATA_SIZE, ATCA_AES_KEY_SIZE, ATCA_ATECC_SLOTS_COUNT, ATCA_ATECC_TEMPKEY_KEYID,
8 ATCA_NONCE_SIZE, ATCA_SHA2_256_DIGEST_SIZE, SHA_MODE_TARGET_TEMPKEY,
9};
10
11use cryptoauthlib_sys::atca_aes_cmac_ctx_t;
12
13impl AteccDevice {
14 pub(crate) fn compute_mac_hmac_sha256(
16 &self,
17 mac_param: MacParam,
18 slot_id: u8,
19 data: &[u8],
20 ) -> Result<Vec<u8>, AtcaStatus> {
21 let mut mac_length: u8 = ATCA_SHA2_256_DIGEST_SIZE as u8;
22 if let Some(val) = &mac_param.mac_length {
23 mac_length = *val
24 };
25
26 let mac = self.common_mac_hmac_sha256(mac_param, slot_id, data, mac_length as usize)?;
27
28 Ok(mac)
29 } pub(crate) fn verify_mac_hmac_sha256(
33 &self,
34 mac_param: MacParam,
35 slot_id: u8,
36 data: &[u8],
37 ) -> Result<bool, AtcaStatus> {
38 let mac_to_check: Vec<u8>;
39
40 if let Some(val) = mac_param.mac.clone() {
41 mac_to_check = val;
42 } else {
43 return Err(AtcaStatus::AtcaBadParam);
44 }
45
46 let mac = self.common_mac_hmac_sha256(mac_param, slot_id, data, mac_to_check.len())?;
47
48 Ok(mac == mac_to_check)
49 } fn common_mac_hmac_sha256(
53 &self,
54 mac_param: MacParam,
55 slot_id: u8,
56 data: &[u8],
57 mac_length: usize,
58 ) -> Result<Vec<u8>, AtcaStatus> {
59 let result = self.common_mac_hmac(mac_param, slot_id);
60 if result != AtcaStatus::AtcaSuccess {
61 return Err(result);
62 }
63 let mut slot = slot_id as u16;
64 if slot_id == ATCA_ATECC_SLOTS_COUNT {
65 slot = ATCA_ATECC_TEMPKEY_KEYID;
66 }
67
68 let mut mac: [u8; ATCA_SHA2_256_DIGEST_SIZE] = [0x00; ATCA_SHA2_256_DIGEST_SIZE];
69
70 let result = AtcaStatus::from(unsafe {
71 let _guard = self
72 .api_mutex
73 .lock()
74 .expect("Could not lock atcab API mutex");
75 cryptoauthlib_sys::atcab_sha_hmac(
76 data.as_ptr(),
77 data.len() as u64,
78 slot,
79 mac.as_mut_ptr(),
80 SHA_MODE_TARGET_TEMPKEY,
81 )
82 });
83
84 match result {
85 AtcaStatus::AtcaSuccess => Ok({
86 let mut out_mac: Vec<u8> = vec![0x00; mac_length as usize];
87 out_mac.copy_from_slice(&mac[..mac_length as usize]);
88 out_mac
89 }),
90 _ => Err(result),
91 }
92 } pub(crate) fn compute_mac_cmac(
96 &self,
97 mac_param: MacParam,
98 slot_id: u8,
99 data: &[u8],
100 ) -> Result<Vec<u8>, AtcaStatus> {
101 let mut mac_length: u8 = ATCA_AES_DATA_SIZE as u8;
102 if let Some(val) = &mac_param.mac_length {
103 mac_length = *val
104 };
105
106 let mac = self.common_mac_cmac(mac_param, slot_id, data, mac_length as usize)?;
107
108 Ok(mac)
109 } pub(crate) fn verify_mac_cmac(
113 &self,
114 mac_param: MacParam,
115 slot_id: u8,
116 data: &[u8],
117 ) -> Result<bool, AtcaStatus> {
118 let mac_to_check: Vec<u8>;
119
120 if let Some(val) = mac_param.mac.clone() {
121 mac_to_check = val;
122 } else {
123 return Err(AtcaStatus::AtcaBadParam);
124 }
125
126 let mac = self.common_mac_cmac(mac_param, slot_id, data, mac_to_check.len())?;
127
128 Ok(mac == mac_to_check)
129 } fn common_mac_cmac(
133 &self,
134 mac_param: MacParam,
135 slot_id: u8,
136 data: &[u8],
137 mac_length: usize,
138 ) -> Result<Vec<u8>, AtcaStatus> {
139 let result = self.common_mac(mac_param, slot_id);
140 if result != AtcaStatus::AtcaSuccess {
141 return Err(result);
142 }
143
144 let mut ctx = self.aes_cmac_init(slot_id)?;
145
146 let mut start_pos: usize = 0;
147 let mut shift: usize = min(data.len(), ATCA_AES_DATA_SIZE);
148 while shift > 0 {
149 let block = &data[start_pos..(start_pos + shift)];
150 ctx = self.aes_cmac_update(ctx, block)?;
151 start_pos += shift;
152 let remaining_bytes = data.len() - start_pos;
153 if remaining_bytes < ATCA_AES_DATA_SIZE {
154 shift = remaining_bytes
155 }
156 }
157
158 let mac = self.aes_cmac_finish(ctx, mac_length as u8)?;
159 Ok(mac)
160 } pub(crate) fn compute_mac_cbcmac(
165 &self,
166 mac_param: MacParam,
167 slot_id: u8,
168 data: &[u8],
169 ) -> Result<Vec<u8>, AtcaStatus> {
170 let mut mac_length: u8 = ATCA_AES_DATA_SIZE as u8;
171 if let Some(val) = &mac_param.mac_length {
172 mac_length = *val
173 };
174
175 let mac = self.common_mac_cbcmac(mac_param, slot_id, data, mac_length as usize)?;
176
177 Ok(mac)
178 } pub(crate) fn verify_mac_cbcmac(
183 &self,
184 mac_param: MacParam,
185 slot_id: u8,
186 data: &[u8],
187 ) -> Result<bool, AtcaStatus> {
188 let mac_to_check: Vec<u8>;
189
190 if let Some(val) = mac_param.mac.clone() {
191 mac_to_check = val;
192 } else {
193 return Err(AtcaStatus::AtcaBadParam);
194 }
195
196 let mac = self.common_mac_cbcmac(mac_param, slot_id, data, mac_to_check.len())?;
197
198 Ok(mac == mac_to_check)
199 } fn common_mac_cbcmac(
203 &self,
204 mac_param: MacParam,
205 slot_id: u8,
206 data: &[u8],
207 mac_length: usize,
208 ) -> Result<Vec<u8>, AtcaStatus> {
209 let result = self.common_mac(mac_param, slot_id);
210 if result != AtcaStatus::AtcaSuccess {
211 return Err(result);
212 }
213
214 let mut ctx = self.aes_cbcmac_init(slot_id);
215
216 let mut start_pos: usize = 0;
217 let mut shift: usize = min(data.len(), ATCA_AES_DATA_SIZE);
218 while shift > 0 {
219 let block = &data[start_pos..(start_pos + shift)];
220 ctx = self.aes_cbcmac_update(ctx, block)?;
221 start_pos += shift;
222 let remaining_bytes = data.len() - start_pos;
223 if remaining_bytes < ATCA_AES_DATA_SIZE {
224 shift = remaining_bytes
225 }
226 }
227
228 let mac = self.aes_cbcmac_finish(ctx, mac_length)?;
229 Ok(mac)
230 } fn aes_cmac_init(&self, slot_id: u8) -> Result<atca_aes_cmac_ctx_t, AtcaStatus> {
234 const BLOCK_IDX: u8 = 0;
235
236 let mut slot = slot_id as u16;
237 if slot_id == ATCA_ATECC_SLOTS_COUNT {
238 slot = ATCA_ATECC_TEMPKEY_KEYID;
239 }
240
241 let ctx: atca_aes_cmac_ctx_t = {
242 let ctx = MaybeUninit::<atca_aes_cmac_ctx_t>::zeroed();
243 unsafe { ctx.assume_init() }
244 };
245 let ctx_ptr = Box::into_raw(Box::new(ctx));
246
247 let result = AtcaStatus::from(unsafe {
248 let _guard = self
249 .api_mutex
250 .lock()
251 .expect("Could not lock atcab API mutex");
252 cryptoauthlib_sys::atcab_aes_cmac_init(ctx_ptr, slot, BLOCK_IDX)
253 });
254
255 match result {
256 AtcaStatus::AtcaSuccess => Ok({
257 let result = unsafe { *ctx_ptr };
258 unsafe { Box::from_raw(ctx_ptr) };
259 result
260 }),
261 _ => Err(result),
262 }
263 } fn aes_cmac_update(
267 &self,
268 ctx: atca_aes_cmac_ctx_t,
269 data: &[u8],
270 ) -> Result<atca_aes_cmac_ctx_t, AtcaStatus> {
271 if data.len() > ATCA_AES_DATA_SIZE {
272 return Err(AtcaStatus::AtcaInvalidSize);
273 }
274
275 let ctx_ptr = Box::into_raw(Box::new(ctx));
276
277 let result = AtcaStatus::from(unsafe {
278 let _guard = self
279 .api_mutex
280 .lock()
281 .expect("Could not lock atcab API mutex");
282 cryptoauthlib_sys::atcab_aes_cmac_update(ctx_ptr, data.as_ptr(), data.len() as u32)
283 });
284
285 let ctx = unsafe { *ctx_ptr };
286 unsafe { Box::from_raw(ctx_ptr) };
287
288 match result {
289 AtcaStatus::AtcaSuccess => Ok(ctx),
290 _ => Err(result),
291 }
292 } fn aes_cmac_finish(
296 &self,
297 ctx: atca_aes_cmac_ctx_t,
298 mac_length: u8,
299 ) -> Result<Vec<u8>, AtcaStatus> {
300 let ctx_ptr = Box::into_raw(Box::new(ctx));
301 let mut mac: [u8; ATCA_AES_DATA_SIZE] = [0; ATCA_AES_DATA_SIZE];
302
303 let result = AtcaStatus::from(unsafe {
304 let _guard = self
305 .api_mutex
306 .lock()
307 .expect("Could not lock atcab API mutex");
308 cryptoauthlib_sys::atcab_aes_cmac_finish(ctx_ptr, mac.as_mut_ptr(), mac_length as u32)
309 });
310
311 unsafe { Box::from_raw(ctx_ptr) };
312
313 match result {
314 AtcaStatus::AtcaSuccess => Ok({
315 let mut out_mac: Vec<u8> = vec![0x00; mac_length as usize];
316 out_mac.copy_from_slice(&mac[..mac_length as usize]);
317 out_mac
318 }),
319 _ => Err(result),
320 }
321 } pub(crate) fn aes_cbcmac_init(&self, slot_id: u8) -> atca_aes_cmac_ctx_t {
325 let mut slot = slot_id as u16;
326 if slot_id == ATCA_ATECC_SLOTS_COUNT {
327 slot = ATCA_ATECC_TEMPKEY_KEYID;
328 }
329
330 let mut ctx: atca_aes_cmac_ctx_t = {
331 let ctx = MaybeUninit::<atca_aes_cmac_ctx_t>::zeroed();
332 unsafe { ctx.assume_init() }
333 };
334
335 ctx.cbc_ctx.key_id = slot;
336 ctx.cbc_ctx.key_block = 0x00;
337
338 ctx
339 } pub(crate) fn aes_cbcmac_update(
344 &self,
345 ctx: atca_aes_cmac_ctx_t,
346 data: &[u8],
347 ) -> Result<atca_aes_cmac_ctx_t, AtcaStatus> {
348 if data.is_empty() {
349 return Ok(ctx);
351 }
352
353 let mut temp_ctx = ctx;
355 let mut idx: usize = 0;
356 let mut buffer: [u8; ATCA_AES_DATA_SIZE] = [0x00; ATCA_AES_DATA_SIZE];
357
358 for i in 0..(data.len() / ATCA_AES_DATA_SIZE) {
359 let start_pos = i * ATCA_AES_DATA_SIZE;
360 let end_pos = start_pos + ATCA_AES_DATA_SIZE;
361 idx += 1;
362
363 temp_ctx.cbc_ctx = self.aes_cbc_encrypt_block(
364 temp_ctx.cbc_ctx,
365 &data[start_pos..end_pos],
366 &mut buffer,
367 )?;
368 }
369
370 let start_pos = idx * ATCA_AES_DATA_SIZE;
372 match start_pos < data.len() {
373 true => {
374 temp_ctx.block_size = (data.len() - start_pos) as u32;
375 temp_ctx.block[..(temp_ctx.block_size as usize)]
376 .copy_from_slice(&data[start_pos..(start_pos + temp_ctx.block_size as usize)]);
377 }
378 false => temp_ctx.block_size = 0,
379 }
380
381 Ok(temp_ctx)
382 } pub(crate) fn aes_cbcmac_finish(
388 &self,
389 ctx: atca_aes_cmac_ctx_t,
390 tag_size: usize,
391 ) -> Result<Vec<u8>, AtcaStatus> {
392 let mut tag: Vec<u8> = vec![0x00; ATCA_AES_DATA_SIZE];
393 if tag_size > ATCA_AES_DATA_SIZE {
394 return Err(AtcaStatus::AtcaBadParam);
395 }
396
397 if ctx.block_size != 0 {
399 return Err(AtcaStatus::AtcaInvalidSize); }
401
402 tag[..tag_size].copy_from_slice(&ctx.cbc_ctx.ciphertext[..tag_size]);
404 tag.resize(tag_size, 0x00);
405 tag.shrink_to_fit();
406 Ok(tag)
407 } fn common_mac(&self, mac_param: MacParam, slot_id: u8) -> AtcaStatus {
411 const MIN_MAC_SIZE: usize = 1;
412 const MAX_MAC_SIZE: usize = ATCA_AES_DATA_SIZE;
413
414 if (slot_id > ATCA_ATECC_SLOTS_COUNT)
415 || ((slot_id < ATCA_ATECC_SLOTS_COUNT)
416 && (self.slots[slot_id as usize].config.key_type != KeyType::Aes))
417 {
418 return AtcaStatus::AtcaInvalidId;
419 }
420 if (ATCA_ATECC_SLOTS_COUNT == slot_id) && mac_param.key.is_none()
421 || (mac_param.mac_length.is_some() && mac_param.mac.is_some())
422 {
423 return AtcaStatus::AtcaBadParam;
424 }
425 if (mac_param.mac_length.is_some()
426 && ((mac_param.mac_length < Some(MIN_MAC_SIZE as u8))
427 || (mac_param.mac_length > Some(MAX_MAC_SIZE as u8))))
428 || (mac_param.mac.is_some()
429 && ((mac_param.mac.as_ref().unwrap().len() < MIN_MAC_SIZE)
430 || (mac_param.mac.as_ref().unwrap().len() > MAX_MAC_SIZE)))
431 || (mac_param.key.is_some()
432 && (mac_param.key.as_ref().unwrap().len() != ATCA_AES_KEY_SIZE))
433 {
434 return AtcaStatus::AtcaInvalidSize;
435 }
436
437 if let Some(mut key) = mac_param.key {
438 key.resize(ATCA_NONCE_SIZE, 0x00);
439 let result = self.nonce(NonceTarget::TempKey, &key);
440 if AtcaStatus::AtcaSuccess != result {
441 return result;
442 }
443 }
444
445 AtcaStatus::AtcaSuccess
446 }
447
448 fn common_mac_hmac(&self, mac_param: MacParam, slot_id: u8) -> AtcaStatus {
450 const MIN_MAC_SIZE: usize = 1;
451 const MAX_MAC_SIZE: usize = ATCA_SHA2_256_DIGEST_SIZE;
452
453 if (slot_id > ATCA_ATECC_SLOTS_COUNT)
454 || ((slot_id < ATCA_ATECC_SLOTS_COUNT)
455 && (self.slots[slot_id as usize].config.key_type != KeyType::ShaOrText))
456 {
457 return AtcaStatus::AtcaInvalidId;
458 }
459 if (ATCA_ATECC_SLOTS_COUNT == slot_id)
460 && (mac_param.key.is_none() || (self.get_device_type() != AtcaDeviceType::ATECC608A))
461 || (mac_param.mac_length.is_some() && mac_param.mac.is_some())
462 {
463 return AtcaStatus::AtcaBadParam;
464 }
465 if (mac_param.mac_length.is_some()
466 && ((mac_param.mac_length < Some(MIN_MAC_SIZE as u8))
467 || (mac_param.mac_length > Some(MAX_MAC_SIZE as u8))))
468 || (mac_param.mac.is_some()
469 && ((mac_param.mac.as_ref().unwrap().len() < MIN_MAC_SIZE)
470 || (mac_param.mac.as_ref().unwrap().len() > MAX_MAC_SIZE)))
471 || (mac_param.key.is_some()
472 && (mac_param.key.as_ref().unwrap().len() > ATCA_SHA2_256_DIGEST_SIZE))
473 {
474 return AtcaStatus::AtcaInvalidSize;
475 }
476
477 if let Some(mut key) = mac_param.key {
478 key.resize(ATCA_NONCE_SIZE, 0x00);
479 let result = self.nonce(NonceTarget::TempKey, &key);
480 if AtcaStatus::AtcaSuccess != result {
481 return result;
482 }
483 }
484
485 AtcaStatus::AtcaSuccess
486 }
487}