M5Unit-CRYPTO 0.0.1 git rev:e7369a6
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 component_config(ccfg);
44 }
45 virtual ~UnitATECC608B()
46 {
47 }
48
49 virtual bool begin() override;
50
53
55 {
56 return _cfg;
57 }
59 inline void config(const config_t& cfg)
60 {
61 _cfg = cfg;
62 }
64
70 inline const uint8_t* revision() const
71 {
72 return _revision.data();
73 }
74
76 inline uint16_t getSlotSize(const atecc608::Slot slot) const
77 {
78 return _slotSize[m5::stl::to_underlying(slot)];
79 }
80
83
89 bool wakeup();
95 bool idle();
101 bool sleep();
103
106
113 inline bool readCounter(uint32_t& value, const uint8_t target)
114 {
115 return counter(value, target, 0 /*read*/);
116 }
124 inline bool incrementCounter(uint32_t& value, const uint8_t target)
125 {
126 return counter(value, target, 1 /* increment */);
127 }
129
132
137 bool readRevision(uint8_t data[4]);
147 bool readKeyValid(bool& valid, const atecc608::Slot slot);
165 bool readDeviceState(uint16_t& state);
167
170
179 bool createNonce(uint8_t output[32], const uint8_t input[20], const bool useRNG = true,
180 const bool updateSeed = true);
181
188 bool writeNonce32(const atecc608::Destination dest, const uint8_t input[32])
189 {
190 return write_nonce(dest, input, 32);
191 }
198 bool writeNonce64(const atecc608::Destination dest, const uint8_t input[64])
199 {
200 return write_nonce(dest, input, 64);
201 }
203
206
211 bool readRandomArray(uint8_t data[32], const bool updateSeed = true);
221 template <typename T, typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr>
222 bool readRandom(T& value, const T lower, const T upper)
223 {
224 static_assert(sizeof(T) <= 32, "readRandom only supports types up to 32 bytes");
225 value = lower;
226 if (upper <= lower) {
227 M5_LIB_LOGE("lower must be less than upper");
228 return false;
229 }
230
231 using U = typename std::make_unsigned<T>::type;
232 const U range = static_cast<U>(upper - lower);
233 const U limit = std::numeric_limits<U>::max() - (std::numeric_limits<U>::max() % range);
234 uint8_t rv[32]{};
235 uint_fast8_t offset{};
236 while (true) {
237 if (!readRandomArray(rv)) {
238 return false;
239 }
240 offset = 0;
241 while (offset + sizeof(U) <= 32) {
242 U raw{};
243 memcpy(&raw, rv + offset, sizeof(U));
244 offset += sizeof(U);
245
246 if (raw > limit) { // Rejection sampling
247 continue;
248 }
249 value = static_cast<T>(lower + (raw % range));
250 return true;
251 }
252 }
253 return false;
254 }
265 template <typename T, typename std::enable_if<std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
266 bool readRandom(T& value, const T lower, const T upper)
267 {
268 value = std::numeric_limits<T>::quiet_NaN();
269 if (upper <= lower) {
270 M5_LIB_LOGE("lower must be less than upper");
271 return false;
272 }
273 uint8_t rv[32]{};
274 if (!readRandomArray(rv)) {
275 return false;
276 }
277 uint32_t raw{};
278 memcpy(&raw, rv, sizeof(uint32_t)); // use first 4 bytes
279
280 // convert to [0.0, 1.0)
281 constexpr double norm = 1.0 / static_cast<double>(std::numeric_limits<uint32_t>::max());
282 double r = static_cast<double>(raw) * norm;
283 value = static_cast<T>(lower + r * static_cast<double>(upper - lower));
284 return std::isfinite(value);
285 }
293 template <typename T, typename std::enable_if<std::is_integral<T>::value, std::nullptr_t>::type = nullptr>
294 inline bool readRandom(T& value)
295 {
296 return readRandom(value, std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max());
297 }
305 template <typename T, typename std::enable_if<std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
306 inline bool readRandom(T& value)
307 {
308 return readRandom(value, std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max());
309 }
311
314
318 bool readConfigZone(uint8_t config[128]);
319
325 bool readSerialNumber(uint8_t sn[9]);
331 bool readSerialNumber(char str[19]);
332
339 bool readZoneLocked(bool& configLocked, bool& dataLocked);
345 bool readSlotLocked(uint16_t& slotLockedBits);
352 inline bool readSlotConfig(uint16_t& cfg, const atecc608::Slot slot)
353 {
354 constexpr uint8_t SLOT_CONFIG_BASE{20}; // Offset in ConfigZone
355 return read_slot_config_word(cfg, SLOT_CONFIG_BASE, slot);
356 }
363 inline bool readKeyConfig(uint16_t& cfg, const atecc608::Slot slot)
364 {
365 constexpr uint8_t KEY_CONFIG_BASE{96}; // Offset in ConfigZone
366 return read_slot_config_word(cfg, KEY_CONFIG_BASE, slot);
367 }
368
377 bool readDataZone(uint8_t* data, const uint16_t len, const atecc608::Slot slot);
378
384 bool readOTPZone(uint8_t otp[64]);
386
389
399 bool selfTest(uint8_t resultBits, const uint8_t testBits = 0x3D /* All */);
401
404
408 bool startSHA256();
415 bool updateSHA256(const uint8_t* msg, const uint32_t mlen);
422 bool finalizeSHA256(const atecc608::Destination dest, uint8_t digest[32]);
431 inline bool SHA256(const atecc608::Destination dest, uint8_t digest[32], const uint8_t* msg, const uint32_t mlen)
432 {
433 return startSHA256() && updateSHA256(msg, mlen) && finalizeSHA256(dest, digest);
434 }
436
440
447 inline bool ECDHStoredKey(uint8_t out[32], const atecc608::Slot slot, const uint8_t pubKey[64])
448 {
449 using namespace m5::unit::atecc608;
450 return ecdh_receive32(out, ECDH_MODE_SRC_SLOT | ECDH_MODE_OUTPUT_BUFFER, m5::stl::to_underlying(slot), pubKey);
451 }
460 inline bool ECDHStoredKey(uint8_t out[32], uint8_t nonce[32], const atecc608::Slot slot, const uint8_t pubKey[64])
461 {
462 using namespace m5::unit::atecc608;
463 return ecdh_receive32x2(out, nonce, ECDH_MODE_SRC_SLOT | ECDH_MODE_OUTPUT_BUFFER | ECDH_MODE_ENCRYPT,
464 m5::stl::to_underlying(slot), pubKey);
465 }
472 inline bool ECDHStoredKey(const atecc608::Slot slot, const uint8_t pubKey[64])
473 {
474 using namespace m5::unit::atecc608;
475 return ecdh_no_output(ECDH_MODE_SRC_SLOT | ECDH_MODE_OUTPUT_TEMPKEY, m5::stl::to_underlying(slot), pubKey);
476 }
484 inline bool ECDHTempKey(uint8_t out[32], const uint8_t pubKey[64])
485 {
486 using namespace m5::unit::atecc608;
487 return ecdh_receive32(out, ECDH_MODE_SRC_TEMPKEY | ECDH_MODE_OUTPUT_BUFFER, 0x0000, pubKey);
488 }
497 inline bool ECDHTempKey(uint8_t out[32], uint8_t nonce[32], const uint8_t pubKey[64])
498 {
499 using namespace m5::unit::atecc608;
500 return ecdh_receive32x2(out, nonce, ECDH_MODE_SRC_TEMPKEY | ECDH_MODE_OUTPUT_BUFFER | ECDH_MODE_ENCRYPT, 0x0000,
501 pubKey);
502 }
509 inline bool ECDHTempKey(const uint8_t pubKey[64])
510 {
511 using namespace m5::unit::atecc608;
512 return ecdh_no_output(ECDH_MODE_SRC_TEMPKEY | ECDH_MODE_OUTPUT_TEMPKEY, 0x0000, pubKey);
513 }
521 bool ECDHTempKey(const atecc608::Slot slot, const uint8_t pubKey[64])
522 {
523 using namespace m5::unit::atecc608;
524 return ecdh_no_output(ECDH_MODE_SRC_TEMPKEY | ECDH_MODE_OUTPUT_SLOT, m5::stl::to_underlying(slot), pubKey);
525 }
527
530
538 inline bool generatePrivateKey(const atecc608::Slot slot, uint8_t pubKey[64], const bool digest = false)
539 {
540 using namespace m5::unit::atecc608;
541 return generate_key(pubKey, GENKEY_MODE_PRIVATE | (digest ? GENKEY_MODE_DIGEST : 0x00),
542 m5::stl::to_underlying(slot));
543 }
549 bool generateKey(uint8_t pubKey[64]);
557 inline bool generatePublicKey(uint8_t pubKey[64], const atecc608::Slot slot, const bool digest = false)
558 {
559 using namespace m5::unit::atecc608;
560 return generate_key(pubKey, GENKEY_MODE_PUBLIC | (digest ? GENKEY_MODE_DIGEST : 0x00),
561 m5::stl::to_underlying(slot));
562 }
570 bool generatePublicKeyDigest(const atecc608::Slot slot, const uint8_t otherData[3] = nullptr);
572
575
584 inline bool signInternal(uint8_t signature[64], const atecc608::Slot slot, const atecc608::Source src,
585 const bool includeSerial = false)
586 {
587 using namespace m5::unit::atecc608;
588 return sign(signature, (SIGN_MODE_INTERNAL | (includeSerial ? SIGN_MODE_INCLUDE_SN : 0x00)),
589 m5::stl::to_underlying(slot), src);
590 }
600 inline bool signExternal(uint8_t signature[64], const atecc608::Slot slot, const atecc608::Source src,
601 const bool includeSerial = false)
602 {
603 using namespace m5::unit::atecc608;
604 return sign(signature, (SIGN_MODE_EXTERNAL | (includeSerial ? SIGN_MODE_INCLUDE_SN : 0x00)),
605 m5::stl::to_underlying(slot), src);
606 }
608
611
619 inline bool verifyExternal(uint8_t mac[32], const uint8_t signature[64], const uint8_t pubKey[64],
620 const atecc608::Source src)
621 {
622 using namespace m5::unit::atecc608;
623 return verify(mac, VERIFY_MODE_EXTERNAL | (mac ? VERIFY_MODE_MAC : 0x00), 0x0004 /* P256 */, signature, pubKey,
624 src);
625 }
634 inline bool verifyStored(uint8_t mac[32], const uint8_t signature[64], const atecc608::Slot slot,
635 const atecc608::Source src)
636 {
637 using namespace m5::unit::atecc608;
638 return verify(mac, VERIFY_MODE_STORED | (mac ? VERIFY_MODE_MAC : 0x00), m5::stl::to_underlying(slot), signature,
639 nullptr, src);
640 }
642
643 // @todo UpdateExtra, Write, AES, CheckMac, GenDig, KDF, MAC command support
644
645protected:
646 virtual bool begin_impl();
647
648 bool send_command(const uint8_t opcode, const uint8_t param1 = 0, const uint16_t param2 = 0,
649 const uint8_t* data = nullptr, uint32_t dlen = 0);
650 bool receive_response(uint8_t* data, const uint32_t dlen);
651
652 bool counter(uint32_t& value, const uint8_t counter, const uint8_t mode);
653
654 bool write_nonce(const atecc608::Destination dest, const uint8_t* input, const uint32_t ilen);
655
656 bool read_data(uint8_t* rbuf, const uint32_t rlen, const uint8_t zone, const uint16_t address,
657 const uint32_t delayMs = 3 /* read default */);
658 bool read_slot_config_word(uint16_t& cfg, const uint8_t baseOffset, const atecc608::Slot slot);
659
660 virtual bool ecdh_receive32(uint8_t out[32], const uint8_t mode, const uint16_t param2, const uint8_t pubKey[64]);
661 virtual bool ecdh_receive32x2(uint8_t out[32], uint8_t nonce[32], const uint8_t mode, const uint16_t param2,
662 const uint8_t pubKey[64]);
663 virtual bool ecdh_no_output(const uint8_t mode, const uint16_t param2, const uint8_t pubKey[64]);
664
665 virtual bool generate_key(uint8_t pubKey[64], const uint8_t mode, const uint16_t param2 = 0x0000,
666 const uint8_t* data = nullptr, const uint32_t dlen = 0);
667 virtual bool sign(uint8_t signature[64], const uint8_t mode, const uint16_t param2, const atecc608::Source src);
668
669 bool verify(uint8_t mac[32], const uint8_t mode, const uint16_t param2, const uint8_t signature[64],
670 const uint8_t pubKey[64], const atecc608::Source src);
671
672private:
673 config_t _cfg{};
674 std::array<uint8_t, 4> _revision{};
675 std::array<uint16_t, 16> _slotSize{
676 36, 36, 36, 36, 36, 36, 36, 36, // slot 0〜7
677 416, // slot 8
678 72, 72, 72, 72, 72, 72, 72 // slot 9〜15
679 };
680};
681
682} // namespace unit
683} // namespace m5
684#endif
ATECC608 definition.
Source
Data source.
Definition atecc608.hpp:48
Slot
Slot configuration summay.
Definition atecc608.hpp:26
bool ECDHStoredKey(const atecc608::Slot slot, const uint8_t pubKey[64])
ECDH (Stored in TempKey)
Definition unit_ATECC608B.hpp:472
bool readRandomArray(uint8_t data[32], const bool updateSeed=true)
Read TRNG output.
Definition unit_ATECC608B.cpp:172
bool incrementCounter(uint32_t &value, const uint8_t target)
Increment counter.
Definition unit_ATECC608B.hpp:124
bool readOTPZone(uint8_t otp[64])
Read the OTP zone @paran[out] Output buffer at least 64 bytes.
Definition unit_ATECC608B.cpp:298
bool updateSHA256(const uint8_t *msg, const uint32_t mlen)
Update calculate SHA256.
Definition unit_ATECC608B.cpp:442
bool writeNonce32(const atecc608::Destination dest, const uint8_t input[32])
write nonce 32 bytes
Definition unit_ATECC608B.hpp:188
bool readSerialNumber(uint8_t sn[9])
Read the serial number.
Definition unit_ATECC608B.cpp:190
bool readSlotConfig(uint16_t &cfg, const atecc608::Slot slot)
Read the SlotConfig.
Definition unit_ATECC608B.hpp:352
uint16_t getSlotSize(const atecc608::Slot slot) const
Gets the size of the specified data slot in bytes.
Definition unit_ATECC608B.hpp:76
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:557
bool ECDHTempKey(uint8_t out[32], uint8_t nonce[32], const uint8_t pubKey[64])
ECDH (Encrypted)
Definition unit_ATECC608B.hpp:497
bool ECDHTempKey(const atecc608::Slot slot, const uint8_t pubKey[64])
ECDH(Stored in slot)
Definition unit_ATECC608B.hpp:521
config_t config()
Gets the configration.
Definition unit_ATECC608B.hpp:54
bool readKeyConfig(uint16_t &cfg, const atecc608::Slot slot)
Read the KeyConfig.
Definition unit_ATECC608B.hpp:363
bool writeNonce64(const atecc608::Destination dest, const uint8_t input[64])
write nonce 64 bytes
Definition unit_ATECC608B.hpp:198
bool wakeup()
Device to active.
Definition unit_ATECC608B.cpp:81
bool ECDHTempKey(const uint8_t pubKey[64])
ECDH (Stored in to TempKey)
Definition unit_ATECC608B.hpp:509
bool readKeyValid(bool &valid, const atecc608::Slot slot)
Read the KeyValid.
Definition unit_ATECC608B.cpp:138
bool idle()
Device to idle.
Definition unit_ATECC608B.cpp:115
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:460
bool generateKey(uint8_t pubKey[64])
Make disposable private key to TempKey and output public key.
Definition unit_ATECC608B.cpp:384
bool ECDHTempKey(uint8_t out[32], const uint8_t pubKey[64])
ECDH (Plane text)
Definition unit_ATECC608B.hpp:484
bool readDataZone(uint8_t *data, const uint16_t len, const atecc608::Slot slot)
Read the data zone.
Definition unit_ATECC608B.cpp:269
bool finalizeSHA256(const atecc608::Destination dest, uint8_t digest[32])
Finalize calculate SHA256.
Definition unit_ATECC608B.cpp:491
bool readZoneLocked(bool &configLocked, bool &dataLocked)
Read the lock state for zone.
Definition unit_ATECC608B.cpp:222
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:538
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:584
bool sleep()
Device to sleep.
Definition unit_ATECC608B.cpp:110
bool SHA256(const atecc608::Destination dest, uint8_t digest[32], const uint8_t *msg, const uint32_t mlen)
Calculate SHA256.
Definition unit_ATECC608B.hpp:431
void config(const config_t &cfg)
Set the configration.
Definition unit_ATECC608B.hpp:59
bool readDeviceState(uint16_t &state)
Read the device state.
Definition unit_ATECC608B.cpp:155
bool selfTest(uint8_t resultBits, const uint8_t testBits=0x3D)
Self test.
Definition unit_ATECC608B.cpp:322
bool readRandom(T &value)
Generate a random integral value covering the entire valid range of type T.
Definition unit_ATECC608B.hpp:294
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:341
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:222
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:390
bool readConfigZone(uint8_t config[128])
Read the config zone.
Definition unit_ATECC608B.cpp:250
const uint8_t * revision() const
Get the revison.
Definition unit_ATECC608B.hpp:70
bool ECDHStoredKey(uint8_t out[32], const atecc608::Slot slot, const uint8_t pubKey[64])
ECDH (Plane text)
Definition unit_ATECC608B.hpp:447
bool readSlotLocked(uint16_t &slotLockedBits)
Read the lock state for data zone.
Definition unit_ATECC608B.cpp:235
bool verifyStored(uint8_t mac[32], const uint8_t signature[64], const atecc608::Slot slot, const atecc608::Source src)
Verify the stored publick key.
Definition unit_ATECC608B.hpp:634
bool readCounter(uint32_t &value, const uint8_t target)
Read the counter value.
Definition unit_ATECC608B.hpp:113
bool startSHA256()
Start calculate SHA256.
Definition unit_ATECC608B.cpp:428
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:619
bool readRevision(uint8_t data[4])
Read the revision.
Definition unit_ATECC608B.cpp:120
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:600
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