M5Unit-CRYPTO 0.2.0 git rev:caebf23
Loading...
Searching...
No Matches
atecc608.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_CRYPTO_ATECC608_HPP
11#define M5_UNIT_CRYPTO_ATECC608_HPP
12
13#include <cstdint>
14
15namespace m5 {
16namespace unit {
21namespace atecc608 {
43
48enum class Source : uint8_t {
49 TempKey,
53};
58using Destination = Source;
59
62constexpr uint8_t ZONE_CONFIG{0x00};
63constexpr uint8_t ZONE_OTP{0x01};
64constexpr uint8_t ZONE_DATA{0x02};
66
71enum Error : uint8_t {
72 CHECK_MAC_OR_VERIFY_ERROR = 0x01,
73 PARSE_ERROR = 0x03,
74 ECC_FAULT = 0x05,
75 SELF_TEST_ERROR = 0x07,
76 HEALTH_TEST_ERROR = 0x08,
77 EXECUTION_ERROR = 0x0F,
78 AFTER_WAKE_PRIOR_ERROR = 0X11,
79 WATCH_DOG_ERROR = 0xEE,
80 CRC_OR_COMMUNICATION_ERROR = 0XFF,
81};
82
86constexpr uint32_t DELAY_READ{3};
87constexpr uint32_t DELAY_WRITE{45};
88constexpr uint32_t DELAY_INFO{2};
89constexpr uint32_t DELAY_NONCE{16};
90constexpr uint32_t DELAY_SELFTEST{200};
91constexpr uint32_t DELAY_RANDOM{23};
92constexpr uint32_t DELAY_COUNTER{20};
93constexpr uint32_t DELAY_GENKEY{115};
94constexpr uint32_t DELAY_SIGN{70};
95constexpr uint32_t DELAY_SHA{9};
96constexpr uint32_t DELAY_ECDH{58};
97constexpr uint32_t DELAY_VERIFY{120};
99
102constexpr uint8_t WORD_VALUE_RESET{0x00};
103constexpr uint8_t WORD_ADDRESS_VALUE_SLEEP{0x01};
104constexpr uint8_t WORD_ADDRESS_VALUE_IDLE{0x02};
105constexpr uint8_t WORD_ADDRESS_VALUE_COMMAND{0x03};
107
110constexpr uint8_t OPCODE_READ{0x02};
111constexpr uint8_t OPCODE_WRITE{0x12};
112constexpr uint8_t OPCODE_NONCE{0x16};
113// constexpr uint8_t OPCODE_LOCK{0x17};
114constexpr uint8_t OPCODE_RANDOM{0x1B};
115constexpr uint8_t OPCODE_COUNTER{0x24};
116constexpr uint8_t OPCODE_INFO{0x30};
117constexpr uint8_t OPCODE_GENKEY{0x40};
118constexpr uint8_t OPCODE_SIGN{0x41};
119constexpr uint8_t OPCODE_ECDH{0x43};
120constexpr uint8_t OPCODE_VERIFY{0x45};
121constexpr uint8_t OPCODE_SHA{0x47};
122constexpr uint8_t OPCODE_SELFTEST{0x77};
124
127constexpr uint8_t INFO_MODE_REVISION{0x00};
128constexpr uint8_t INFO_MODE_KEYVALID{0x01};
129constexpr uint8_t INFO_MODE_DEVICE_STATE{0x02};
131
134constexpr uint8_t NONCE_MODE_RANDOM_UPDATE_SEED{0x00};
135constexpr uint8_t NONCE_MODE_RANDOM_NOT_UPDATE_SEED{0x01};
136constexpr uint8_t NONCE_MODE_PASSTHROUGH{0x03};
137constexpr uint8_t NONCE_MODE_INPUT_64{0x20};
138
139constexpr uint8_t NONCE_MODE_TARGET_TEMPKEY{0x00};
140constexpr uint8_t NONCE_MODE_TARGET_DIGEST{0x40};
141constexpr uint8_t NONCE_MODE_TARGET_ALTKEY{0x80};
142
143constexpr uint16_t NONCE_USE_TRNG{0x0000};
144constexpr uint16_t NONCE_USE_TEMPKEY{0x8000};
146
149constexpr uint8_t RANDOM_MODE_UPDATE_SEED{0x00};
150constexpr uint8_t RANDOM_MODE_NOT_UPDATE_SEED{0x01};
152
155constexpr uint8_t SHA_MODE_START{0x00};
156constexpr uint8_t SHA_MODE_UPDATE{0x01};
157constexpr uint8_t SHA_MODE_FINALIZE{0x02};
158constexpr uint8_t SHA_MODE_OUTPUT_TEMPKEY{0x00};
159constexpr uint8_t SHA_MODE_OUTPUT_DIGEST{0x40};
160constexpr uint8_t SHA_MODE_OUTPUT_BUFFER{0xC0};
162
165// constexpr uint8_t ECDH_MODE_SLOT{0x04};
166constexpr uint8_t ECDH_MODE_SRC_SLOT{0x00};
167constexpr uint8_t ECDH_MODE_SRC_TEMPKEY{0x01};
168
169constexpr uint8_t ECDH_MODE_ENCRYPT{0x02};
170
171constexpr uint8_t ECDH_MODE_OUTPUT_TEMPKEY{0x08};
172constexpr uint8_t ECDH_MODE_OUTPUT_BUFFER{0x0C};
173constexpr uint8_t ECDH_MODE_OUTPUT_SLOT{0x04};
175
178constexpr uint8_t GENKEY_MODE_PUBLIC{0x00};
179constexpr uint8_t GENKEY_MODE_PRIVATE{0x04};
180constexpr uint8_t GENKEY_MODE_DIGEST{0x08};
181constexpr uint8_t GENKEY_MODE_PUBLIC_DIGEST{0x10};
183
186constexpr uint8_t SIGN_MODE_INTERNAL{0x00};
187constexpr uint8_t SIGN_MODE_INCLUDE_SN{0x40};
188constexpr uint8_t SIGN_MODE_EXTERNAL{0x80};
189
190constexpr uint8_t SIGN_MODE_TEMPKEY{0x00};
191constexpr uint8_t SIGN_MODE_DIGEST{0x20};
193
196constexpr uint8_t VERIFY_MODE_STORED{0x00};
197constexpr uint8_t VERIFY_MODE_EXTERNAL{0x02};
198
199constexpr uint8_t VERIFY_MODE_TEMPKEY{0x00};
200constexpr uint8_t VERIFY_MODE_DIGEST{0x20};
201
202constexpr uint8_t VERIFY_MODE_MAC{0x80};
205
207inline uint16_t offset_to_param2_for_config(const uint8_t offset)
208{
209 const uint8_t block = (offset >> 5) & 0x03; // 0〜3
210 const uint8_t index = ((offset & 31) >> 2) & 0x07; // 0〜7
211 return (block << 3) | index;
212}
214inline uint16_t slot_block_to_param2(const uint8_t slot, const uint16_t offset)
215{
216 const uint8_t block = offset >> 5; // 0〜2
217 const uint8_t word_offset = (offset & 31) >> 2; // 0〜7
218 return (slot << 3) | (block << 8) | word_offset;
219}
220
222constexpr inline uint32_t encoded_base64_length(const uint32_t ilen)
223{
224 return ((ilen + 2) / 3) * 4;
225}
226
228bool convertToPEM(char* out, const uint32_t out_len, const uint8_t* der, uint32_t dlen,
229 const char* header = "CERTIFICATE", const char* footer = "CERTIFICATE");
230
232extern const uint8_t template_for_device[];
233extern const uint8_t template_for_signer[];
234extern const uint32_t template_for_device_size;
235extern const uint32_t template_for_signer_size;
237
242class CompCertAccessor {
243public:
244 struct DateTime {
245 int tm_sec; // 0 to 59
246 int tm_min; // 0 to 59
247 int tm_hour; // 0 to 23
248 int tm_mday; // 1 to 31
249 int tm_mon; // 0 to 11
250 int tm_year; // years since 1900
251 };
252
253 explicit CompCertAccessor(const uint8_t* data) : _data(data)
254 {
255 if (_data) {
256 _issue_date = get_issue_date();
257 _expire_date = get_expire_date();
258 }
259 }
260
261 inline uint8_t format_version() const
262 {
263 return _data[70] & 0x0F;
264 }
265 inline uint8_t template_id() const
266 {
267 return (_data[69] >> 4) & 0x0F;
268 }
269 inline uint8_t chain_id() const
270 {
271 return _data[69] & 0x0F;
272 }
273 inline uint8_t sn_source() const
274 {
275 return (_data[70] >> 4) & 0x0F;
276 }
277
278 inline const uint8_t* signer_id() const
279 {
280 return _data + 67;
281 }
282
283 inline const uint8_t* signature() const
284 {
285 return _data + 0;
286 }
287 inline const uint8_t* signature_r() const
288 {
289 return _data + 0;
290 }
291 inline const uint8_t* signature_s() const
292 {
293 return _data + 32;
294 }
295
296 inline DateTime issue_date() const
297 {
298 return _issue_date;
299 }
300 inline DateTime expire_date() const
301 {
302 return _expire_date;
303 }
304
305private:
306 const uint8_t* _data{};
307 DateTime _issue_date{}, _expire_date{};
308
309 DateTime get_issue_date() const
310 {
311 DateTime dt{};
312 uint8_t b64 = _data[64];
313 uint8_t b65 = _data[65];
314 uint8_t b66 = _data[66];
315 uint8_t b71 = _data[71];
316 uint8_t fmt_ver = format_version();
317
318 if (fmt_ver == 1 || fmt_ver == 2) {
319 dt.tm_year = ((((b71 & 0xC0) >> 1) | ((b64 >> 3) & 0x1F)) + 100);
320 } else {
321 dt.tm_year = ((b64 >> 3) + 100);
322 }
323 dt.tm_mon = (((b64 & 0x07) << 1) | ((b65 & 0x80) >> 7)) - 1;
324 dt.tm_mday = (b65 & 0x7C) >> 2;
325 dt.tm_hour = ((b65 & 0x03) << 3) | ((b66 & 0xE0) >> 5);
326 dt.tm_min = 0;
327 dt.tm_sec = 0;
328 return dt;
329 }
330
331 DateTime get_expire_date() const
332 {
333 DateTime dt = issue_date();
334 uint8_t b66 = _data[66];
335 uint8_t b71 = _data[71];
336 uint8_t fmt_ver = format_version();
337 uint8_t expire_years{};
338
339 if (fmt_ver == 1 || fmt_ver == 2) {
340 expire_years = (b66 & 0x1F) | ((b71 & 0x30) << 1);
341 } else {
342 expire_years = b66 & 0x1F;
343 }
344
345 if (expire_years != 0) {
346 dt.tm_year += expire_years;
347 } else {
348 // indefinite
349 dt.tm_year = 9999 - 1900;
350 dt.tm_mon = 11;
351 dt.tm_mday = 31;
352 dt.tm_hour = 23;
353 dt.tm_min = 59;
354 dt.tm_sec = 59;
355 }
356 return dt;
357 }
358};
359
360} // namespace atecc608
361} // namespace unit
362} // namespace m5
363#endif
364
365#if 0
3667:01:52.557 > [ 899][E][unit_ATECC608B.cpp:1186] receive_response(): CRC error: C76B != FFFF (count:35 max_read:35)
36717:01:52.563 > DUMP:0x3ffb2080 35 bytes
36817:01:52.572 > 0x3ffb2080| 23 8F 0F 8F 8F 0F 0F 8F 0F 0F 8F 0F 8F 0F 8F 8F |#...............
36917:01:52.578 > 0x3ffb2090| 8F 8F 8F 9F FF FF FF FF FF FF FF FF FF FF FF FF |................
37017:01:52.583 > 0x3ffb20a0| FF FF FF |...
37117:01:52.589 > [ 923][E][PlotToSerial.cpp:237] setup(): readConfigZone NG
37217:01:52.590 > [ 936][E][unit_ATECC608B.cpp:1210] read_data(): Failed send_command:01 0002
37317:01:52.596 > [ 941][E][PlotToSerial.cpp:242] setup(): readOTPZone NG
37417:01:52.607 > [ 941][W][unit_ATECC608B.cpp:596] wakeup_i2c_class(): Wakeup retry 0 err:-5 resp:00,00,00,00
37517:01:52.620 > [ 962][W][unit_ATECC608B.cpp:596] wakeup_i2c_class(): Wakeup retry 1 err:-5 resp:00,00,00,00
37617:01:52.631 > [ 972][E][unit_ATECC608B.cpp:1186] receive_response(): CRC error: 2C9E != FFFF (count:35 max_read:35)
37717:01:52.637 > DUMP:0x3ffb1ed0 35 bytes
37817:01:52.646 > 0x3ffb1ed0| 23 07 31 00 64 FE AF 6E A0 7A 2F F5 96 55 AA 6B |#.1.d..n.z/..U.k
37917:01:52.652 > 0x3ffb1ee0| 11 AF 44 A3 1E DF DD 2E 57 E3 96 F0 FF FF FF FF |..D.....W.......
38017:01:52.657 > 0x3ffb1ef0| FF FF FF |...
38117:01:52.663 > [ 997][E][PlotToSerial.cpp:247] setup(): readDataZone NG
38217:01:52.671 > [ 1013][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
38317:01:52.677 > [ 1018][E][PlotToSerial.cpp:253] setup(): readKeyValid[1] NG
38417:01:52.682 > [ 1022][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
38517:01:52.688 > [ 1027][E][PlotToSerial.cpp:253] setup(): readKeyValid[2] NG
38617:01:52.693 > [ 1040][W][unit_ATECC608B.cpp:596] wakeup_i2c_class(): Wakeup retry 0 err:-5 resp:00,00,00,00
38717:01:52.705 > [ 1048][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
38817:01:52.710 > [ 1053][E][PlotToSerial.cpp:253] setup(): readKeyValid[4] NG
38917:01:52.716 > [ 1057][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
39017:01:52.727 > [ 1062][E][PlotToSerial.cpp:253] setup(): readKeyValid[5] NG
39117:01:52.732 > [ 1071][E][unit_ATECC608B.cpp:1186] receive_response(): CRC error: 0F0E != FFFF (count:7 max_read:7)
39217:01:52.738 > DUMP:0x3ffb1f30 7 bytes
39317:01:52.747 > 0x3ffb1f30| 07 00 00 0F FF FF FF |.......
39417:01:52.753 > [ 1086][E][PlotToSerial.cpp:253] setup(): readKeyValid[6] NG
39517:01:52.760 > [ 1104][E][PlotToSerial.cpp:253] setup(): readKeyValid[8] NG
39617:01:52.765 > [ 1104][W][unit_ATECC608B.cpp:596] wakeup_i2c_class(): Wakeup retry 0 err:-5 resp:00,00,00,00
39717:01:52.771 > [ 1113][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
39817:01:52.776 > [ 1118][E][PlotToSerial.cpp:253] setup(): readKeyValid[9] NG
39917:01:52.787 > [ 1129][W][unit_ATECC608B.cpp:596] wakeup_i2c_class(): Wakeup retry 0 err:-5 resp:00,00,00,00
40017:01:52.793 > [ 1138][E][PlotToSerial.cpp:253] setup(): readKeyValid[11] NG
40117:01:52.798 > [ 1138][W][unit_ATECC608B.cpp:596] wakeup_i2c_class(): Wakeup retry 0 err:-5 resp:00,00,00,00
40217:01:52.810 > [ 1150][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
40317:01:52.815 > [ 1155][E][PlotToSerial.cpp:253] setup(): readKeyValid[12] NG
40417:01:52.821 > [ 1162][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
40517:01:52.832 > [ 1167][E][PlotToSerial.cpp:253] setup(): readKeyValid[13] NG
40617:01:52.837 > [ 1176][E][unit_ATECC608B.cpp:1186] receive_response(): CRC error: 2552 != 0000 (count:31 max_read:7)
40717:01:52.843 > DUMP:0x3ffb1f30 7 bytes
40817:01:52.852 > 0x3ffb1f30| 1F FF FF FF FF FF FF |.......
40917:01:52.858 > [ 1191][E][PlotToSerial.cpp:253] setup(): readKeyValid[14] NG
41017:01:52.866 > [ 1208][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
41117:01:52.872 > [ 1213][E][PlotToSerial.cpp:259] setup(): readCounter(0) NG
41217:01:52.877 > [ 1218][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
41317:01:52.883 > [ 1223][E][PlotToSerial.cpp:262] setup(): readCounter(1) NG
41417:01:52.888 > [ 1230][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
41517:01:52.900 > [ 1235][E][PlotToSerial.cpp:267] setup(): readDeviceState NG
41617:01:53.099 > [ 1441][E][unit_ATECC608B.cpp:1173] receive_response(): Failed to read response
41717:01:53.105 > [ 1446][E][PlotToSerial.cpp:272] setup(): selfTest NG
418#endif
Source
Data source.
Definition atecc608.hpp:48
@ AlternateKeyBuffer
Alternate Key Buffer.
@ MsgDigestBuffer
Message digest buffer.
Slot
Slot configuration summary.
Definition atecc608.hpp:26
@ SecondaryPrivateKey1
Secondary private key for other uses.
@ MACAddress
IEEE EUI-48 MAC Address.
@ PrimaryPrivateKey
Primary authentication key.
@ SignerPublicKey
Public key for the CA (signer) that signed the device cert.
@ SecondaryPrivateKey3
Secondary private key for other uses.
@ DeviceCompressedCertificate
Certificate primary public key in the CryptoAuthentication compressed format.
@ IOProtectionKey
Key used to protect the I2C bus communication (IO) of certain commands.
@ SecondaryPrivateKey2
Secondary private key for other uses.
@ GeneralData
General purpose data storage (416 bytes)
@ AESKey
Intermediate key storage for ECDH and KDF output.
uint16_t slot_block_to_param2(const uint8_t slot, const uint16_t offset)
Conversion slot and block to address for Data zone.
Definition atecc608.hpp:214
constexpr uint32_t encoded_base64_length(const uint32_t ilen)
Calculate encoded size (no line break)
Definition atecc608.hpp:222
uint16_t offset_to_param2_for_config(const uint8_t offset)
Conversion offset to address for Config,OTP zone.
Definition atecc608.hpp:207
Error
Error status.
Definition atecc608.hpp:71
Compressed certificate accessor.
For ATECC608.
Top level namespace of M5stack.
Unit-related namespace.