M5Unit-CRYPTO 0.2.0 git rev:caebf23
Loading...
Searching...
No Matches
unit_ATECC608B.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_UNIT_ATECC608B_HPP
11#define M5_UNIT_CRYPTO_UNIT_ATECC608B_HPP
12
13#include "atecc608.hpp"
14#include <M5UnitComponent.hpp>
15#include <m5_utility/container/circular_buffer.hpp>
16#include <array>
17#include <limits>
18
19namespace m5 {
20namespace unit {
21
26class UnitATECC608B : public Component {
27 M5_UNIT_COMPONENT_HPP_BUILDER(UnitATECC608B, 0x35);
28
29public:
34 struct config_t {
36 bool idle{true};
37 };
38
39 explicit UnitATECC608B(const uint8_t addr = DEFAULT_ADDRESS) : Component(addr)
40 {
41 auto ccfg = component_config();
42 ccfg.clock = 400 * 1000U;
43 // ccfg.clock = 100 * 1000U;
44 component_config(ccfg);
45 }
46 virtual ~UnitATECC608B()
47 {
48 }
49
50 virtual bool begin() override;
51
54
56 {
57 return _cfg;
58 }
60 inline void config(const config_t& cfg)
61 {
62 _cfg = cfg;
63 }
65
71 inline const uint8_t* revision() const
72 {
73 return _revision.data();
74 }
75
77 inline uint16_t getSlotSize(const atecc608::Slot slot) const
78 {
79 return _slotSize[m5::stl::to_underlying(slot)];
80 }
81
84
90 bool wakeup();
96 bool idle();
102 bool sleep();
104
107
114 inline bool readCounter(uint32_t& value, const uint8_t target)
115 {
116 return counter(value, target, 0 /*read*/);
117 }
125 inline bool incrementCounter(uint32_t& value, const uint8_t target)
126 {
127 return counter(value, target, 1 /* increment */);
128 }
130
133
138 bool readRevision(uint8_t data[4]);
148 bool readKeyValid(bool& valid, const atecc608::Slot slot);
166 bool readDeviceState(uint16_t& state);
168
171
180 bool createNonce(uint8_t output[32], const uint8_t input[20], const bool useRNG = true,
181 const bool updateSeed = true);
182
189 bool writeNonce32(const atecc608::Destination dest, const uint8_t input[32])
190 {
191 return write_nonce(dest, input, 32);
192 }
199 bool writeNonce64(const atecc608::Destination dest, const uint8_t input[64])
200 {
201 return write_nonce(dest, input, 64);
202 }
204
207
213 virtual bool readRandomArray(uint8_t data[32], const bool updateSeed = true);
223 template <typename T, typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr>
224 bool readRandom(T& value, const T lower, const T upper)
225 {
226 static_assert(sizeof(T) <= 32, "readRandom only supports types up to 32 bytes");
227 value = lower;
228 if (upper <= lower) {
229 M5_LIB_LOGE("lower must be less than upper");
230 return false;
231 }
232
233 using U = typename std::make_unsigned<T>::type;
234 const U range = static_cast<U>(static_cast<U>(upper) - static_cast<U>(lower));
235 const U limit = std::numeric_limits<U>::max() - (std::numeric_limits<U>::max() % range);
236 uint8_t rv[32]{};
237 uint_fast8_t offset{};
238 while (true) {
239 if (!readRandomArray(rv)) {
240 return false;
241 }
242 offset = 0;
243 while (offset + sizeof(U) <= 32) {
244 U raw{};
245 memcpy(&raw, rv + offset, sizeof(U));
246 offset += sizeof(U);
247
248 if (raw >= limit) { // Rejection sampling
249 continue;
250 }
251 value = static_cast<T>(lower + (raw % range));
252 return true;
253 }
254 }
255 return false;
256 }
267 template <typename T, typename std::enable_if<std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
268 bool readRandom(T& value, const T lower, const T upper)
269 {
270 value = std::numeric_limits<T>::quiet_NaN();
271 if (upper <= lower) {
272 M5_LIB_LOGE("lower must be less than upper");
273 return false;
274 }
275 uint8_t rv[32]{};
276 if (!readRandomArray(rv)) {
277 return false;
278 }
279 uint32_t raw{};
280 memcpy(&raw, rv, sizeof(uint32_t)); // use first 4 bytes
281
282 // convert to [0.0, 1.0)
283 constexpr double norm = 1.0 / (static_cast<double>(std::numeric_limits<uint32_t>::max()) + 1.0);
284 double r = static_cast<double>(raw) * norm;
285 value = static_cast<T>(lower + r * static_cast<double>(upper - lower));
286 return std::isfinite(value);
287 }
295 template <typename T, typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr>
296 inline bool readRandom(T& value)
297 {
298 return readRandom(value, std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max());
299 }
307 template <typename T, typename std::enable_if<std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
308 inline bool readRandom(T& value)
309 {
310 return readRandom(value, std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max());
311 }
313
316
320 bool readConfigZone(uint8_t config[128]);
321
327 bool readSerialNumber(uint8_t sn[9]);
333 bool readSerialNumber(char str[19]);
334
341 bool readZoneLocked(bool& configLocked, bool& dataLocked);
347 bool readSlotLocked(uint16_t& slotLockedBits);
354 inline bool readSlotConfig(uint16_t& cfg, const atecc608::Slot slot)
355 {
356 constexpr uint8_t SLOT_CONFIG_BASE{20}; // Offset in ConfigZone
357 return read_slot_config_word(cfg, SLOT_CONFIG_BASE, slot);
358 }
365 inline bool readKeyConfig(uint16_t& cfg, const atecc608::Slot slot)
366 {
367 constexpr uint8_t KEY_CONFIG_BASE{96}; // Offset in ConfigZone
368 return read_slot_config_word(cfg, KEY_CONFIG_BASE, slot);
369 }
370
379 bool readDataZone(uint8_t* data, const uint16_t len, const atecc608::Slot slot);
380
390 bool writeGeneralData(const uint8_t* data, const uint16_t len, const uint16_t offset = 0);
399 bool readGeneralData(uint8_t* data, const uint16_t len, const uint16_t offset = 0);
400
406 bool readOTPZone(uint8_t otp[64]);
408
411
415 bool startSHA256();
422 bool updateSHA256(const uint8_t* msg, const uint32_t mlen);
429 bool finalizeSHA256(const atecc608::Destination dest, uint8_t digest[32]);
438 inline bool SHA256(const atecc608::Destination dest, uint8_t digest[32], const uint8_t* msg, const uint32_t mlen)
439 {
440 return startSHA256() && updateSHA256(msg, mlen) && finalizeSHA256(dest, digest);
441 }
443
447
454 inline bool ECDHStoredKey(uint8_t out[32], const atecc608::Slot slot, const uint8_t pubKey[64])
455 {
456 using namespace m5::unit::atecc608;
457 return ecdh_receive32(out, ECDH_MODE_SRC_SLOT | ECDH_MODE_OUTPUT_BUFFER, m5::stl::to_underlying(slot), pubKey);
458 }
467 inline bool ECDHStoredKey(uint8_t out[32], uint8_t nonce[32], const atecc608::Slot slot, const uint8_t pubKey[64])
468 {
469 using namespace m5::unit::atecc608;
470 return ecdh_receive32x2(out, nonce, ECDH_MODE_SRC_SLOT | ECDH_MODE_OUTPUT_BUFFER | ECDH_MODE_ENCRYPT,
471 m5::stl::to_underlying(slot), pubKey);
472 }
479 inline bool ECDHStoredKey(const atecc608::Slot slot, const uint8_t pubKey[64])
480 {
481 using namespace m5::unit::atecc608;
482 return ecdh_no_output(ECDH_MODE_SRC_SLOT | ECDH_MODE_OUTPUT_TEMPKEY, m5::stl::to_underlying(slot), pubKey);
483 }
491 inline bool ECDHTempKey(uint8_t out[32], const uint8_t pubKey[64])
492 {
493 using namespace m5::unit::atecc608;
494 return ecdh_receive32(out, ECDH_MODE_SRC_TEMPKEY | ECDH_MODE_OUTPUT_BUFFER, 0x0000, pubKey);
495 }
504 inline bool ECDHTempKey(uint8_t out[32], uint8_t nonce[32], const uint8_t pubKey[64])
505 {
506 using namespace m5::unit::atecc608;
507 return ecdh_receive32x2(out, nonce, ECDH_MODE_SRC_TEMPKEY | ECDH_MODE_OUTPUT_BUFFER | ECDH_MODE_ENCRYPT, 0x0000,
508 pubKey);
509 }
516 inline bool ECDHTempKey(const uint8_t pubKey[64])
517 {
518 using namespace m5::unit::atecc608;
519 return ecdh_no_output(ECDH_MODE_SRC_TEMPKEY | ECDH_MODE_OUTPUT_TEMPKEY, 0x0000, pubKey);
520 }
528 bool ECDHTempKey(const atecc608::Slot slot, const uint8_t pubKey[64])
529 {
530 using namespace m5::unit::atecc608;
531 return ecdh_no_output(ECDH_MODE_SRC_TEMPKEY | ECDH_MODE_OUTPUT_SLOT, m5::stl::to_underlying(slot), pubKey);
532 }
534
537
545 inline bool generatePrivateKey(const atecc608::Slot slot, uint8_t pubKey[64], const bool digest = false)
546 {
547 using namespace m5::unit::atecc608;
548 return generate_key(pubKey, GENKEY_MODE_PRIVATE | (digest ? GENKEY_MODE_DIGEST : 0x00),
549 m5::stl::to_underlying(slot));
550 }
556 bool generateKey(uint8_t pubKey[64]);
564 inline bool generatePublicKey(uint8_t pubKey[64], const atecc608::Slot slot, const bool digest = false)
565 {
566 using namespace m5::unit::atecc608;
567 return generate_key(pubKey, GENKEY_MODE_PUBLIC | (digest ? GENKEY_MODE_DIGEST : 0x00),
568 m5::stl::to_underlying(slot));
569 }
577 bool generatePublicKeyDigest(const atecc608::Slot slot, const uint8_t otherData[3] = nullptr);
579
582
591 inline bool signInternal(uint8_t signature[64], const atecc608::Slot slot, const atecc608::Source src,
592 const bool includeSerial = false)
593 {
594 using namespace m5::unit::atecc608;
595 return sign(signature, (SIGN_MODE_INTERNAL | (includeSerial ? SIGN_MODE_INCLUDE_SN : 0x00)),
596 m5::stl::to_underlying(slot), src);
597 }
607 inline bool signExternal(uint8_t signature[64], const atecc608::Slot slot, const atecc608::Source src,
608 const bool includeSerial = false)
609 {
610 using namespace m5::unit::atecc608;
611 return sign(signature, (SIGN_MODE_EXTERNAL | (includeSerial ? SIGN_MODE_INCLUDE_SN : 0x00)),
612 m5::stl::to_underlying(slot), src);
613 }
615
618
626 inline bool verifyExternal(uint8_t mac[32], const uint8_t signature[64], const uint8_t pubKey[64],
627 const atecc608::Source src)
628 {
629 using namespace m5::unit::atecc608;
630 return verify(mac, VERIFY_MODE_EXTERNAL | (mac ? VERIFY_MODE_MAC : 0x00), 0x0004 /* P256 */, signature, pubKey,
631 src);
632 }
641 inline bool verifyStored(uint8_t mac[32], const uint8_t signature[64], const atecc608::Slot slot,
642 const atecc608::Source src)
643 {
644 using namespace m5::unit::atecc608;
645 return verify(mac, VERIFY_MODE_STORED | (mac ? VERIFY_MODE_MAC : 0x00), m5::stl::to_underlying(slot), signature,
646 nullptr, src);
647 }
649
652
662 bool selfTest(uint8_t& resultBits, const uint8_t testBits = 0x3D /* All */);
664
665 // @todo UpdateExtra, Write, AES, CheckMac, GenDig, KDF, MAC command support
666
667protected:
668 virtual bool begin_impl();
669
670 bool send_command(const uint8_t opcode, const uint8_t param1 = 0, const uint16_t param2 = 0,
671 const uint8_t* data = nullptr, uint32_t dlen = 0);
672 bool receive_response(uint8_t* data, const uint32_t dlen);
673
674 bool counter(uint32_t& value, const uint8_t counter, const uint8_t mode);
675
676 bool write_nonce(const atecc608::Destination dest, const uint8_t* input, const uint32_t ilen);
677
678 bool read_data(uint8_t* rbuf, const uint32_t rlen, const uint8_t zone, const uint16_t address,
679 const uint32_t delayMs = 3 /* read default */);
680 bool read_slot_config_word(uint16_t& cfg, const uint8_t baseOffset, const atecc608::Slot slot);
681
682 virtual bool ecdh_receive32(uint8_t out[32], const uint8_t mode, const uint16_t param2, const uint8_t pubKey[64]);
683 virtual bool ecdh_receive32x2(uint8_t out[32], uint8_t nonce[32], const uint8_t mode, const uint16_t param2,
684 const uint8_t pubKey[64]);
685 virtual bool ecdh_no_output(const uint8_t mode, const uint16_t param2, const uint8_t pubKey[64]);
686
687 virtual bool generate_key(uint8_t pubKey[64], const uint8_t mode, const uint16_t param2 = 0x0000,
688 const uint8_t* data = nullptr, const uint32_t dlen = 0);
689 virtual bool sign(uint8_t signature[64], const uint8_t mode, const uint16_t param2, const atecc608::Source src);
690
691 bool verify(uint8_t mac[32], const uint8_t mode, const uint16_t param2, const uint8_t signature[64],
692 const uint8_t pubKey[64], const atecc608::Source src);
693
694private:
695 config_t _cfg{};
696 std::array<uint8_t, 4> _revision{};
697 std::array<uint16_t, 16> _slotSize{
698 36, 36, 36, 36, 36, 36, 36, 36, // slot 0〜7
699 416, // slot 8
700 72, 72, 72, 72, 72, 72, 72 // slot 9〜15
701 };
702};
703
704} // namespace unit
705} // namespace m5
706#endif
ATECC608 definition.
Source
Data source.
Definition atecc608.hpp:48
Slot
Slot configuration summary.
Definition atecc608.hpp:26
bool ECDHStoredKey(const atecc608::Slot slot, const uint8_t pubKey[64])
ECDH (Stored in TempKey)
Definition unit_ATECC608B.hpp:479
virtual bool readRandomArray(uint8_t data[32], const bool updateSeed=true)
Read TRNG output.
Definition unit_ATECC608B.cpp:227
bool incrementCounter(uint32_t &value, const uint8_t target)
Increment counter.
Definition unit_ATECC608B.hpp:125
bool readOTPZone(uint8_t otp[64])
Read the OTP zone.
Definition unit_ATECC608B.cpp:463
bool updateSHA256(const uint8_t *msg, const uint32_t mlen)
Update calculate SHA256.
Definition unit_ATECC608B.cpp:621
bool writeNonce32(const atecc608::Destination dest, const uint8_t input[32])
write nonce 32 bytes
Definition unit_ATECC608B.hpp:189
bool readSerialNumber(uint8_t sn[9])
Read the serial number.
Definition unit_ATECC608B.cpp:245
bool readSlotConfig(uint16_t &cfg, const atecc608::Slot slot)
Read the SlotConfig.
Definition unit_ATECC608B.hpp:354
uint16_t getSlotSize(const atecc608::Slot slot) const
Gets the size of the specified data slot in bytes.
Definition unit_ATECC608B.hpp:77
bool generatePublicKey(uint8_t pubKey[64], const atecc608::Slot slot, const bool digest=false)
Generate the public key from private key in slot.
Definition unit_ATECC608B.hpp:564
bool ECDHTempKey(uint8_t out[32], uint8_t nonce[32], const uint8_t pubKey[64])
ECDH (Encrypted)
Definition unit_ATECC608B.hpp:504
bool readGeneralData(uint8_t *data, const uint16_t len, const uint16_t offset=0)
Read data from GeneralData slot (Slot 8)
Definition unit_ATECC608B.cpp:416
bool ECDHTempKey(const atecc608::Slot slot, const uint8_t pubKey[64])
ECDH(Stored in slot)
Definition unit_ATECC608B.hpp:528
config_t config()
Gets the configuration.
Definition unit_ATECC608B.hpp:55
bool readKeyConfig(uint16_t &cfg, const atecc608::Slot slot)
Read the KeyConfig.
Definition unit_ATECC608B.hpp:365
bool writeNonce64(const atecc608::Destination dest, const uint8_t input[64])
write nonce 64 bytes
Definition unit_ATECC608B.hpp:199
bool wakeup()
Device to active.
Definition unit_ATECC608B.cpp:109
bool writeGeneralData(const uint8_t *data, const uint16_t len, const uint16_t offset=0)
Write data to GeneralData slot (Slot 8, clear text)
Definition unit_ATECC608B.cpp:359
bool ECDHTempKey(const uint8_t pubKey[64])
ECDH (Stored in TempKey)
Definition unit_ATECC608B.hpp:516
bool readKeyValid(bool &valid, const atecc608::Slot slot)
Read the KeyValid.
Definition unit_ATECC608B.cpp:193
bool idle()
Device to idle.
Definition unit_ATECC608B.cpp:169
bool ECDHStoredKey(uint8_t out[32], uint8_t nonce[32], const atecc608::Slot slot, const uint8_t pubKey[64])
ECDH (Encrypted)
Definition unit_ATECC608B.hpp:467
bool generateKey(uint8_t pubKey[64])
Make disposable private key to TempKey and output public key.
Definition unit_ATECC608B.cpp:563
bool ECDHTempKey(uint8_t out[32], const uint8_t pubKey[64])
ECDH (Plain text)
Definition unit_ATECC608B.hpp:491
bool selfTest(uint8_t &resultBits, const uint8_t testBits=0x3D)
Self test.
Definition unit_ATECC608B.cpp:501
bool readDataZone(uint8_t *data, const uint16_t len, const atecc608::Slot slot)
Read the data zone.
Definition unit_ATECC608B.cpp:330
bool finalizeSHA256(const atecc608::Destination dest, uint8_t digest[32])
Finalize calculate SHA256.
Definition unit_ATECC608B.cpp:669
bool readZoneLocked(bool &configLocked, bool &dataLocked)
Read the lock state for zone.
Definition unit_ATECC608B.cpp:282
bool generatePrivateKey(const atecc608::Slot slot, uint8_t pubKey[64], const bool digest=false)
Generate the private key stored in slot.
Definition unit_ATECC608B.hpp:545
bool signInternal(uint8_t signature[64], const atecc608::Slot slot, const atecc608::Source src, const bool includeSerial=false)
Sign internal message.
Definition unit_ATECC608B.hpp:591
bool sleep()
Device to sleep.
Definition unit_ATECC608B.cpp:163
bool SHA256(const atecc608::Destination dest, uint8_t digest[32], const uint8_t *msg, const uint32_t mlen)
Calculate SHA256.
Definition unit_ATECC608B.hpp:438
void config(const config_t &cfg)
Set the configuration.
Definition unit_ATECC608B.hpp:60
bool readDeviceState(uint16_t &state)
Read the device state.
Definition unit_ATECC608B.cpp:210
bool readRandom(T &value)
Generate a random integral value covering the entire valid range of type T.
Definition unit_ATECC608B.hpp:296
bool createNonce(uint8_t output[32], const uint8_t input[20], const bool useRNG=true, const bool updateSeed=true)
Create nonce to TempKey by input data with RNG or TempKey.
Definition unit_ATECC608B.cpp:520
bool readRandom(T &value, const T lower, const T upper)
Generate a random value of type T in the specified range.
Definition unit_ATECC608B.hpp:224
bool generatePublicKeyDigest(const atecc608::Slot slot, const uint8_t otherData[3]=nullptr)
Generate digest of a public key and stored in TempKey.
Definition unit_ATECC608B.cpp:569
bool readConfigZone(uint8_t config[128])
Read the config zone.
Definition unit_ATECC608B.cpp:310
const uint8_t * revision() const
Get the revision.
Definition unit_ATECC608B.hpp:71
bool ECDHStoredKey(uint8_t out[32], const atecc608::Slot slot, const uint8_t pubKey[64])
ECDH (Plain text)
Definition unit_ATECC608B.hpp:454
bool readSlotLocked(uint16_t &slotLockedBits)
Read the lock state for data zone.
Definition unit_ATECC608B.cpp:295
bool verifyStored(uint8_t mac[32], const uint8_t signature[64], const atecc608::Slot slot, const atecc608::Source src)
Verify the stored public key.
Definition unit_ATECC608B.hpp:641
bool readCounter(uint32_t &value, const uint8_t target)
Read the counter value.
Definition unit_ATECC608B.hpp:114
bool startSHA256()
Start calculate SHA256.
Definition unit_ATECC608B.cpp:607
bool verifyExternal(uint8_t mac[32], const uint8_t signature[64], const uint8_t pubKey[64], const atecc608::Source src)
Verify the external public key.
Definition unit_ATECC608B.hpp:626
bool readRevision(uint8_t data[4])
Read the revision.
Definition unit_ATECC608B.cpp:175
bool signExternal(uint8_t signature[64], const atecc608::Slot slot, const atecc608::Source src, const bool includeSerial=false)
Sign external message.
Definition unit_ATECC608B.hpp:607
Top level namespace of M5stack.
Unit-related namespace.
Settings for begin.
Definition unit_ATECC608B.hpp:34
bool idle
Device to idle on begin?
Definition unit_ATECC608B.hpp:36