33# SPDX-License-Identifier: MIT
44
55from machine import I2C
6- from .pahub import PAHUBUnit
7- from .unit_helper import UnitError
6+ from unit .pahub import PAHUBUnit
7+ from unit .unit_helper import UnitError
88import binascii
99import struct
10+ import time
1011
1112from driver .atecc608b_tngtls .atecc import ATECC
1213from driver .atecc608b_tngtls .atecc_cert_util import CSR
@@ -24,7 +25,6 @@ def __init__(self, i2c: I2C | PAHUBUnit, address: int = _I2C_ADDR) -> None:
2425 self ._i2c_addr = address
2526 if address not in self ._i2c .scan ():
2627 raise UnitError ("ID unit maybe not found in Grove" )
27-
2828 self .atecc = ATECC (self ._i2c , self ._i2c_addr )
2929
3030 def get_revision_number (self ) -> int :
@@ -55,14 +55,34 @@ def uniform(self, min: float = 0, max: float = 0) -> float:
5555 min , max = (max , min ) if min > max else (min , max )
5656 return min + (max - min ) * self .random ()
5757
58- def get_generate_key (self , slot_num : int , private_key : bool = False ) -> bytearray :
58+ def get_generate_key (self , slot_num : int , private_key : bool = False ):
5959 #! Generates a private or public key.
6060 assert 0 <= slot_num <= 4 , "Provided slot must be between 0 and 4."
6161 # Create a new key
6262 key = bytearray (64 )
6363 self .atecc .gen_key (key , slot_num , private_key )
6464 return key
6565
66+ def ecdh_stored_key (self , slot_num : int , mode : int , external_public_key : bytearray = None ):
67+ if external_public_key is None :
68+ external_public_key = bytearray (64 )
69+ self .atecc .gen_key (external_public_key , 0 , private_key = False )
70+
71+ if len (external_public_key ) != 64 :
72+ raise ValueError ("External public key must be exactly 64 bytes." )
73+
74+ self .atecc ._send_command (
75+ opcode = 0x43 , param_1 = mode , param_2 = slot_num , data = external_public_key
76+ )
77+
78+ if mode in (0x0C , 0x08 ):
79+ time .sleep (1 )
80+ res = bytearray (32 )
81+ self .atecc ._get_response (res )
82+ return res
83+ else :
84+ return None
85+
6686 def get_ecdsa_sign (self , slot : int , message : str | list | bytearray ) -> bytearray | None :
6787 #! Generates and returns a signature using the ECDSA algorithm.
6888 if len (message ) == 32 :
@@ -120,3 +140,66 @@ def set_certificate_signing_request(
120140 )
121141 with open (file_path , "w+" ) as pem_file :
122142 pem_file .write (pem_content )
143+
144+ # ref: ATECC608A-TFLXTLS 4.4.1 Table 4-5
145+ def read_data_zone (self , data_zone : int ):
146+ self .atecc ._send_command (
147+ opcode = 0x02 ,
148+ param_1 = 0x00 ,
149+ param_2 = data_zone ,
150+ )
151+ time .sleep (0.1 )
152+ temp = bytearray (4 )
153+ self .atecc ._get_response (temp )
154+ return temp
155+
156+ def write_data_zone (self , data_zone : int , data : bytearray ):
157+ self .atecc ._send_command (
158+ opcode = 0x12 ,
159+ param_1 = 0x02 ,
160+ param_2 = data_zone ,
161+ data = data ,
162+ )
163+
164+ def aes_ecb_encrypt (self , position : int , data : bytearray ):
165+ if len (data ) != 16 :
166+ raise ValueError ("Data must be 16 bytes" )
167+ self .atecc ._send_command (
168+ opcode = 0x51 ,
169+ param_1 = (position << 6 ),
170+ param_2 = 0x09 , # ATECC608B AES Key only stored in slot 9
171+ data = data ,
172+ )
173+ time .sleep (1 )
174+ res = bytearray (16 )
175+ self .atecc ._get_response (res )
176+ return res
177+
178+ def aes_ecb_decrypt (self , position : int , data : bytearray ):
179+ if len (data ) != 16 :
180+ raise ValueError ("Data must be 16 bytes" )
181+ self .atecc ._send_command (
182+ opcode = 0x51 ,
183+ param_1 = (position << 6 ) + 1 ,
184+ param_2 = 0x09 , # ATECC608B AES Key only stored in slot 9
185+ data = data ,
186+ )
187+ time .sleep (1 )
188+ res = bytearray (16 )
189+ self .atecc ._get_response (res )
190+ return res
191+
192+ def get_h_field (self ):
193+ zero_block = bytearray ([0x00 ] * 16 )
194+ return self .aes_ecb_encrypt (0x00 , zero_block )
195+
196+ def aes_gfm_encrypt (self , data : bytearray ):
197+ if len (data ) != 16 :
198+ raise ValueError ("Data must be 16 bytes" )
199+ data = self .get_h_field () + data
200+ time .sleep (1 )
201+ self .atecc ._send_command (opcode = 0x51 , param_1 = 0x03 , param_2 = 0x00 , data = data )
202+ time .sleep (1 )
203+ res = bytearray (16 )
204+ self .atecc ._get_response (res )
205+ return res
0 commit comments