Device interface library for multiple platforms including Mbed.

Dependents:   DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#

Maxim Interface is a library framework focused on providing flexible and expressive hardware interfaces. Both communication interfaces such as I2C and 1-Wire and device interfaces such as DS18B20 are supported. Modern C++ concepts are used extensively while keeping compatibility with C++98/C++03 and requiring no external dependencies. The embedded-friendly design does not depend on exceptions or RTTI.

The full version of the project is hosted on GitLab: https://gitlab.com/iabenz/MaximInterface

Committer:
IanBenzMaxim
Date:
Fri May 29 16:19:22 2020 -0500
Revision:
12:7eb41621ba22
Parent:
11:3f3bf6bf5e6c
Updated to version 2.2.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 7:9cd16581b578 1 /*******************************************************************************
IanBenzMaxim 8:5ea891c7d1a1 2 * Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved.
IanBenzMaxim 7:9cd16581b578 3 *
IanBenzMaxim 7:9cd16581b578 4 * Permission is hereby granted, free of charge, to any person obtaining a
IanBenzMaxim 7:9cd16581b578 5 * copy of this software and associated documentation files (the "Software"),
IanBenzMaxim 7:9cd16581b578 6 * to deal in the Software without restriction, including without limitation
IanBenzMaxim 7:9cd16581b578 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
IanBenzMaxim 7:9cd16581b578 8 * and/or sell copies of the Software, and to permit persons to whom the
IanBenzMaxim 7:9cd16581b578 9 * Software is furnished to do so, subject to the following conditions:
IanBenzMaxim 7:9cd16581b578 10 *
IanBenzMaxim 7:9cd16581b578 11 * The above copyright notice and this permission notice shall be included
IanBenzMaxim 7:9cd16581b578 12 * in all copies or substantial portions of the Software.
IanBenzMaxim 7:9cd16581b578 13 *
IanBenzMaxim 7:9cd16581b578 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
IanBenzMaxim 7:9cd16581b578 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
IanBenzMaxim 7:9cd16581b578 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IanBenzMaxim 7:9cd16581b578 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
IanBenzMaxim 7:9cd16581b578 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
IanBenzMaxim 7:9cd16581b578 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
IanBenzMaxim 7:9cd16581b578 20 * OTHER DEALINGS IN THE SOFTWARE.
IanBenzMaxim 7:9cd16581b578 21 *
IanBenzMaxim 7:9cd16581b578 22 * Except as contained in this notice, the name of Maxim Integrated
IanBenzMaxim 7:9cd16581b578 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
IanBenzMaxim 7:9cd16581b578 24 * Products, Inc. Branding Policy.
IanBenzMaxim 7:9cd16581b578 25 *
IanBenzMaxim 7:9cd16581b578 26 * The mere transfer of this software does not imply any licenses
IanBenzMaxim 7:9cd16581b578 27 * of trade secrets, proprietary technology, copyrights, patents,
IanBenzMaxim 7:9cd16581b578 28 * trademarks, maskwork rights, or any other form of intellectual
IanBenzMaxim 7:9cd16581b578 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
IanBenzMaxim 7:9cd16581b578 30 * ownership rights.
IanBenzMaxim 7:9cd16581b578 31 *******************************************************************************/
IanBenzMaxim 7:9cd16581b578 32
IanBenzMaxim 7:9cd16581b578 33 #include <stddef.h>
IanBenzMaxim 7:9cd16581b578 34 #include <algorithm>
IanBenzMaxim 7:9cd16581b578 35 #include <MaximInterfaceCore/Error.hpp>
IanBenzMaxim 7:9cd16581b578 36 #include "DS28E83_DS28E84.hpp"
IanBenzMaxim 7:9cd16581b578 37
IanBenzMaxim 7:9cd16581b578 38 namespace MaximInterfaceDevices {
IanBenzMaxim 7:9cd16581b578 39
IanBenzMaxim 7:9cd16581b578 40 using namespace Core;
IanBenzMaxim 7:9cd16581b578 41 using std::copy;
IanBenzMaxim 8:5ea891c7d1a1 42 using std::pair;
IanBenzMaxim 7:9cd16581b578 43
IanBenzMaxim 7:9cd16581b578 44 static const int readMemoryTimeMs = 2;
IanBenzMaxim 7:9cd16581b578 45 static const int writeMemoryTimeMs = 100;
IanBenzMaxim 7:9cd16581b578 46 static const int writeStateTimeMs = 15;
IanBenzMaxim 7:9cd16581b578 47 static const int generateEccKeyPairTimeMs = 350;
IanBenzMaxim 7:9cd16581b578 48 static const int generateEcdsaSignatureTimeMs = 80;
IanBenzMaxim 7:9cd16581b578 49 static const int computeTimeMs = 4;
IanBenzMaxim 7:9cd16581b578 50 static const int verifyEcdsaTimeMs = 160;
IanBenzMaxim 7:9cd16581b578 51 static const int trngGenerationTimeMs = 40;
IanBenzMaxim 7:9cd16581b578 52 static const int trngOnDemandCheckTimeMs = 65;
IanBenzMaxim 7:9cd16581b578 53
IanBenzMaxim 7:9cd16581b578 54 static const uint_least8_t computeAndReadPageAuthenticationCmd = 0xA5;
IanBenzMaxim 7:9cd16581b578 55 static const uint_least8_t readRngCmd = 0xD2;
IanBenzMaxim 7:9cd16581b578 56
IanBenzMaxim 7:9cd16581b578 57 static const int memoryPages =
IanBenzMaxim 7:9cd16581b578 58 MaximInterfaceCore_MAX(DS28E83::memoryPages, DS28E84::memoryPages);
IanBenzMaxim 7:9cd16581b578 59 static const int protectionBlocks = MaximInterfaceCore_MAX(
IanBenzMaxim 7:9cd16581b578 60 DS28E83::protectionBlocks, DS28E84::protectionBlocks);
IanBenzMaxim 7:9cd16581b578 61
IanBenzMaxim 7:9cd16581b578 62 const int DS28E83_DS28E84::publicKeyAxPage;
IanBenzMaxim 7:9cd16581b578 63 const int DS28E83_DS28E84::publicKeyAyPage;
IanBenzMaxim 7:9cd16581b578 64 const int DS28E83_DS28E84::publicKeyBxPage;
IanBenzMaxim 7:9cd16581b578 65 const int DS28E83_DS28E84::publicKeyByPage;
IanBenzMaxim 7:9cd16581b578 66 const int DS28E83_DS28E84::authorityPublicKeyAxPage;
IanBenzMaxim 7:9cd16581b578 67 const int DS28E83_DS28E84::authorityPublicKeyAyPage;
IanBenzMaxim 7:9cd16581b578 68 const int DS28E83_DS28E84::authorityPublicKeyBxPage;
IanBenzMaxim 7:9cd16581b578 69 const int DS28E83_DS28E84::authorityPublicKeyByPage;
IanBenzMaxim 7:9cd16581b578 70 const int DS28E83_DS28E84::privateKeyAPage;
IanBenzMaxim 7:9cd16581b578 71 const int DS28E83_DS28E84::privateKeyBPage;
IanBenzMaxim 7:9cd16581b578 72 const int DS28E83_DS28E84::secretAPage;
IanBenzMaxim 7:9cd16581b578 73 const int DS28E83_DS28E84::secretBPage;
IanBenzMaxim 7:9cd16581b578 74 const int DS28E83_DS28E84::romOptionsPage;
IanBenzMaxim 7:9cd16581b578 75 const int DS28E83_DS28E84::gpioControlPage;
IanBenzMaxim 7:9cd16581b578 76 const int DS28E83_DS28E84::publicKeySxPage;
IanBenzMaxim 7:9cd16581b578 77 const int DS28E83_DS28E84::publicKeySyPage;
IanBenzMaxim 7:9cd16581b578 78
IanBenzMaxim 7:9cd16581b578 79 const int DS28E83::memoryPages;
IanBenzMaxim 7:9cd16581b578 80 const int DS28E83::protectionBlocks;
IanBenzMaxim 7:9cd16581b578 81
IanBenzMaxim 7:9cd16581b578 82 const int DS28E84::publicKeySxBackupPage;
IanBenzMaxim 7:9cd16581b578 83 const int DS28E84::publicKeySyBackupPage;
IanBenzMaxim 7:9cd16581b578 84 const int DS28E84::decrementCounterPage;
IanBenzMaxim 7:9cd16581b578 85 const int DS28E84::memoryPages;
IanBenzMaxim 7:9cd16581b578 86 const int DS28E84::protectionBlocks;
IanBenzMaxim 7:9cd16581b578 87
IanBenzMaxim 8:5ea891c7d1a1 88 Result<void> DS28E83_DS28E84::writeMemory(int pageNum, Page::const_span page) {
IanBenzMaxim 7:9cd16581b578 89 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 90 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 91 }
IanBenzMaxim 7:9cd16581b578 92
IanBenzMaxim 7:9cd16581b578 93 uint_least8_t request[2 + Page::size];
IanBenzMaxim 7:9cd16581b578 94 request[0] = 0x96;
IanBenzMaxim 7:9cd16581b578 95 request[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 96 copy(page.begin(), page.end(), request + 2);
IanBenzMaxim 7:9cd16581b578 97 return runCommand(request, writeMemoryTimeMs);
IanBenzMaxim 7:9cd16581b578 98 }
IanBenzMaxim 7:9cd16581b578 99
IanBenzMaxim 8:5ea891c7d1a1 100 Result<DS28E83_DS28E84::Page::array>
IanBenzMaxim 8:5ea891c7d1a1 101 DS28E83_DS28E84::readMemory(int pageNum) const {
IanBenzMaxim 7:9cd16581b578 102 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 103 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 104 }
IanBenzMaxim 7:9cd16581b578 105
IanBenzMaxim 7:9cd16581b578 106 uint_least8_t buffer[1 + Page::size];
IanBenzMaxim 7:9cd16581b578 107 buffer[0] = 0x44;
IanBenzMaxim 7:9cd16581b578 108 buffer[1] = pageNum;
IanBenzMaxim 8:5ea891c7d1a1 109 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 110 runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer);
IanBenzMaxim 8:5ea891c7d1a1 111 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 112 return response.error();
IanBenzMaxim 7:9cd16581b578 113 }
IanBenzMaxim 8:5ea891c7d1a1 114 Page::array page;
IanBenzMaxim 8:5ea891c7d1a1 115 copy(response.value().begin(), response.value().end(), page.begin());
IanBenzMaxim 8:5ea891c7d1a1 116 return page;
IanBenzMaxim 7:9cd16581b578 117 }
IanBenzMaxim 7:9cd16581b578 118
IanBenzMaxim 8:5ea891c7d1a1 119 Result<pair<DS28E83_DS28E84::EncryptionChallenge::array,
IanBenzMaxim 8:5ea891c7d1a1 120 DS28E83_DS28E84::Page::array> >
IanBenzMaxim 8:5ea891c7d1a1 121 DS28E83_DS28E84::encryptedReadMemory(int pageNum, KeySecret secret) const {
IanBenzMaxim 7:9cd16581b578 122 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 123 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 124 }
IanBenzMaxim 7:9cd16581b578 125
IanBenzMaxim 7:9cd16581b578 126 const size_t requestSize = 3;
IanBenzMaxim 7:9cd16581b578 127 const size_t responseSize = 1 + EncryptionChallenge::size + Page::size;
IanBenzMaxim 7:9cd16581b578 128 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
IanBenzMaxim 7:9cd16581b578 129 buffer[0] = 0x4B;
IanBenzMaxim 7:9cd16581b578 130 buffer[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 131 buffer[2] = secret;
IanBenzMaxim 8:5ea891c7d1a1 132 const Result<span<uint_least8_t> > response = runCommand(
IanBenzMaxim 8:5ea891c7d1a1 133 make_span(buffer, requestSize), readMemoryTimeMs + computeTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 134 make_span(buffer, responseSize));
IanBenzMaxim 8:5ea891c7d1a1 135 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 136 return response.error();
IanBenzMaxim 7:9cd16581b578 137 }
IanBenzMaxim 8:5ea891c7d1a1 138 pair<EncryptionChallenge::array, Page::array> data;
IanBenzMaxim 8:5ea891c7d1a1 139 span<uint_least8_t>::const_iterator begin = response.value().begin();
IanBenzMaxim 8:5ea891c7d1a1 140 span<uint_least8_t>::const_iterator end = begin + data.first.size();
IanBenzMaxim 8:5ea891c7d1a1 141 copy(begin, end, data.first.begin());
IanBenzMaxim 8:5ea891c7d1a1 142 begin = end;
IanBenzMaxim 8:5ea891c7d1a1 143 end = begin + data.second.size();
IanBenzMaxim 8:5ea891c7d1a1 144 copy(begin, end, data.second.begin());
IanBenzMaxim 8:5ea891c7d1a1 145 return data;
IanBenzMaxim 7:9cd16581b578 146 }
IanBenzMaxim 7:9cd16581b578 147
IanBenzMaxim 8:5ea891c7d1a1 148 Result<pair<Optional<DS28E83_DS28E84::KeySecret>,
IanBenzMaxim 8:5ea891c7d1a1 149 DS28E83_DS28E84::BlockProtection> >
IanBenzMaxim 8:5ea891c7d1a1 150 DS28E83_DS28E84::readBlockProtection(int blockNumber) const {
IanBenzMaxim 7:9cd16581b578 151 if (blockNumber < 0 || blockNumber >= protectionBlocks) {
IanBenzMaxim 8:5ea891c7d1a1 152 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 153 }
IanBenzMaxim 7:9cd16581b578 154
IanBenzMaxim 7:9cd16581b578 155 const size_t requestSize = 2;
IanBenzMaxim 7:9cd16581b578 156 const size_t responseSize = 3;
IanBenzMaxim 7:9cd16581b578 157 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
IanBenzMaxim 7:9cd16581b578 158 buffer[0] = 0xAA;
IanBenzMaxim 7:9cd16581b578 159 buffer[1] = blockNumber;
IanBenzMaxim 8:5ea891c7d1a1 160 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 161 runCommand(make_span(buffer, requestSize), readMemoryTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 162 make_span(buffer, responseSize));
IanBenzMaxim 8:5ea891c7d1a1 163 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 164 return response.error();
IanBenzMaxim 7:9cd16581b578 165 }
IanBenzMaxim 8:5ea891c7d1a1 166 if ((response.value()[0] & 0x3F) != blockNumber) {
IanBenzMaxim 8:5ea891c7d1a1 167 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 168 }
IanBenzMaxim 8:5ea891c7d1a1 169 pair<Optional<KeySecret>, BlockProtection> data;
IanBenzMaxim 8:5ea891c7d1a1 170 switch (response.value()[0] >> 6) {
IanBenzMaxim 7:9cd16581b578 171 case 0:
IanBenzMaxim 8:5ea891c7d1a1 172 data.first = none;
IanBenzMaxim 7:9cd16581b578 173 break;
IanBenzMaxim 7:9cd16581b578 174 case 1:
IanBenzMaxim 8:5ea891c7d1a1 175 data.first = KeySecretA;
IanBenzMaxim 7:9cd16581b578 176 break;
IanBenzMaxim 7:9cd16581b578 177 case 2:
IanBenzMaxim 8:5ea891c7d1a1 178 data.first = KeySecretB;
IanBenzMaxim 7:9cd16581b578 179 break;
IanBenzMaxim 7:9cd16581b578 180 default:
IanBenzMaxim 8:5ea891c7d1a1 181 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 182 }
IanBenzMaxim 8:5ea891c7d1a1 183 if ((response.value()[1] & 0x20) != 0) {
IanBenzMaxim 8:5ea891c7d1a1 184 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 185 }
IanBenzMaxim 8:5ea891c7d1a1 186 data.second = response.value()[1];
IanBenzMaxim 8:5ea891c7d1a1 187 return data;
IanBenzMaxim 7:9cd16581b578 188 }
IanBenzMaxim 7:9cd16581b578 189
IanBenzMaxim 8:5ea891c7d1a1 190 Result<void>
IanBenzMaxim 7:9cd16581b578 191 DS28E83_DS28E84::setBlockProtection(int blockNum, KeySecret keySecret,
IanBenzMaxim 7:9cd16581b578 192 const BlockProtection & protection) {
IanBenzMaxim 7:9cd16581b578 193 if (blockNum < 0 || blockNum >= protectionBlocks || keySecret == KeySecretS) {
IanBenzMaxim 8:5ea891c7d1a1 194 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 195 }
IanBenzMaxim 7:9cd16581b578 196
IanBenzMaxim 7:9cd16581b578 197 const uint_least8_t request[] = {
IanBenzMaxim 7:9cd16581b578 198 0xC3,
IanBenzMaxim 7:9cd16581b578 199 static_cast<uint_least8_t>((keySecret == KeySecretB ? 0x80 : 0x40) |
IanBenzMaxim 7:9cd16581b578 200 blockNum),
IanBenzMaxim 7:9cd16581b578 201 static_cast<uint_least8_t>(protection.to_ulong())};
IanBenzMaxim 7:9cd16581b578 202 return runCommand(request, writeStateTimeMs);
IanBenzMaxim 7:9cd16581b578 203 }
IanBenzMaxim 7:9cd16581b578 204
IanBenzMaxim 8:5ea891c7d1a1 205 Result<Ecc256::Signature::array>
IanBenzMaxim 8:5ea891c7d1a1 206 DS28E83_DS28E84::computeAndReadEcdsaPageAuthentication(
IanBenzMaxim 8:5ea891c7d1a1 207 int pageNum, KeySecret key, Page::const_span challenge) const {
IanBenzMaxim 7:9cd16581b578 208 if (pageNum < 0 || pageNum >= memoryPages || key == KeySecretS) {
IanBenzMaxim 8:5ea891c7d1a1 209 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 210 }
IanBenzMaxim 7:9cd16581b578 211
IanBenzMaxim 7:9cd16581b578 212 const size_t requestSize = 3 + Page::size;
IanBenzMaxim 7:9cd16581b578 213 const size_t responseSize = 1 + 2 * Ecc256::Scalar::size;
IanBenzMaxim 7:9cd16581b578 214 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
IanBenzMaxim 7:9cd16581b578 215 buffer[0] = computeAndReadPageAuthenticationCmd;
IanBenzMaxim 7:9cd16581b578 216 buffer[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 217 buffer[2] = key + 3;
IanBenzMaxim 7:9cd16581b578 218 copy(challenge.begin(), challenge.end(), buffer + 3);
IanBenzMaxim 8:5ea891c7d1a1 219 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 220 runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 221 make_span(buffer, responseSize));
IanBenzMaxim 8:5ea891c7d1a1 222 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 223 return response.error();
IanBenzMaxim 7:9cd16581b578 224 }
IanBenzMaxim 8:5ea891c7d1a1 225 Ecc256::Signature::array signature;
IanBenzMaxim 8:5ea891c7d1a1 226 span<uint_least8_t>::const_iterator begin = response.value().begin();
IanBenzMaxim 8:5ea891c7d1a1 227 span<uint_least8_t>::const_iterator end = begin + signature.s.size();
IanBenzMaxim 8:5ea891c7d1a1 228 copy(begin, end, signature.s.begin());
IanBenzMaxim 8:5ea891c7d1a1 229 begin = end;
IanBenzMaxim 8:5ea891c7d1a1 230 end = begin + signature.r.size();
IanBenzMaxim 8:5ea891c7d1a1 231 copy(begin, end, signature.r.begin());
IanBenzMaxim 8:5ea891c7d1a1 232 return signature;
IanBenzMaxim 7:9cd16581b578 233 }
IanBenzMaxim 7:9cd16581b578 234
IanBenzMaxim 8:5ea891c7d1a1 235 Result<DS28E83_DS28E84::Page::array>
IanBenzMaxim 8:5ea891c7d1a1 236 DS28E83_DS28E84::computeAndReadSha256PageAuthentication(
IanBenzMaxim 8:5ea891c7d1a1 237 int pageNum, KeySecret secret, Page::const_span challenge) const {
IanBenzMaxim 7:9cd16581b578 238 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 239 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 240 }
IanBenzMaxim 7:9cd16581b578 241
IanBenzMaxim 7:9cd16581b578 242 const size_t requestSize = 3 + Page::size;
IanBenzMaxim 7:9cd16581b578 243 const size_t responseSize = 1 + Page::size;
IanBenzMaxim 7:9cd16581b578 244 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
IanBenzMaxim 7:9cd16581b578 245 buffer[0] = computeAndReadPageAuthenticationCmd;
IanBenzMaxim 7:9cd16581b578 246 buffer[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 247 buffer[2] = secret;
IanBenzMaxim 7:9cd16581b578 248 copy(challenge.begin(), challenge.end(), buffer + 3);
IanBenzMaxim 8:5ea891c7d1a1 249 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 250 runCommand(make_span(buffer, requestSize), computeTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 251 make_span(buffer, responseSize));
IanBenzMaxim 8:5ea891c7d1a1 252 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 253 return response.error();
IanBenzMaxim 7:9cd16581b578 254 }
IanBenzMaxim 8:5ea891c7d1a1 255 Page::array hmac;
IanBenzMaxim 8:5ea891c7d1a1 256 copy(response.value().begin(), response.value().end(), hmac.begin());
IanBenzMaxim 8:5ea891c7d1a1 257 return hmac;
IanBenzMaxim 7:9cd16581b578 258 }
IanBenzMaxim 7:9cd16581b578 259
IanBenzMaxim 8:5ea891c7d1a1 260 Result<void>
IanBenzMaxim 7:9cd16581b578 261 DS28E83_DS28E84::computeMultiblockHash(bool firstBlock, bool lastBlock,
IanBenzMaxim 7:9cd16581b578 262 span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 263 const span<const uint_least8_t>::index_type maxDataSize = 64;
IanBenzMaxim 7:9cd16581b578 264
IanBenzMaxim 7:9cd16581b578 265 if (data.size() < 1 || data.size() > maxDataSize) {
IanBenzMaxim 8:5ea891c7d1a1 266 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 267 }
IanBenzMaxim 7:9cd16581b578 268
IanBenzMaxim 7:9cd16581b578 269 uint_least8_t buffer[2 + maxDataSize];
IanBenzMaxim 7:9cd16581b578 270 buffer[0] = 0x33;
IanBenzMaxim 7:9cd16581b578 271 buffer[1] = 0;
IanBenzMaxim 7:9cd16581b578 272 if (firstBlock) {
IanBenzMaxim 7:9cd16581b578 273 buffer[1] |= 0x40;
IanBenzMaxim 7:9cd16581b578 274 }
IanBenzMaxim 7:9cd16581b578 275 if (lastBlock) {
IanBenzMaxim 7:9cd16581b578 276 buffer[1] |= 0x80;
IanBenzMaxim 7:9cd16581b578 277 }
IanBenzMaxim 7:9cd16581b578 278 copy(data.begin(), data.end(), buffer + 2);
IanBenzMaxim 7:9cd16581b578 279 return runCommand(make_span(buffer, 2 + data.size()), computeTimeMs);
IanBenzMaxim 7:9cd16581b578 280 }
IanBenzMaxim 7:9cd16581b578 281
IanBenzMaxim 8:5ea891c7d1a1 282 Result<void> DS28E83_DS28E84::verifyEcdsaSignature(
IanBenzMaxim 7:9cd16581b578 283 KeySecret key, bool authorityKey, GpioState gpioState,
IanBenzMaxim 7:9cd16581b578 284 Ecc256::Signature::const_span signature, span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 285 return verifyEcdsaSignature(key, authorityKey, DataInput, gpioState,
IanBenzMaxim 7:9cd16581b578 286 signature, data);
IanBenzMaxim 7:9cd16581b578 287 }
IanBenzMaxim 7:9cd16581b578 288
IanBenzMaxim 8:5ea891c7d1a1 289 Result<void> DS28E83_DS28E84::verifyEcdsaSignature(
IanBenzMaxim 7:9cd16581b578 290 KeySecret key, bool authorityKey, GpioState gpioState,
IanBenzMaxim 7:9cd16581b578 291 Ecc256::Signature::const_span signature, Page::const_span hash) {
IanBenzMaxim 7:9cd16581b578 292 return verifyEcdsaSignature(key, authorityKey, HashInput, gpioState,
IanBenzMaxim 7:9cd16581b578 293 signature, hash);
IanBenzMaxim 7:9cd16581b578 294 }
IanBenzMaxim 7:9cd16581b578 295
IanBenzMaxim 8:5ea891c7d1a1 296 Result<void>
IanBenzMaxim 7:9cd16581b578 297 DS28E83_DS28E84::verifyEcdsaSignature(KeySecret key, bool authorityKey,
IanBenzMaxim 7:9cd16581b578 298 GpioState gpioState,
IanBenzMaxim 7:9cd16581b578 299 Ecc256::Signature::const_span signature) {
IanBenzMaxim 7:9cd16581b578 300 return verifyEcdsaSignature(key, authorityKey, THASH, gpioState, signature,
IanBenzMaxim 7:9cd16581b578 301 span<const uint_least8_t>());
IanBenzMaxim 7:9cd16581b578 302 }
IanBenzMaxim 7:9cd16581b578 303
IanBenzMaxim 8:5ea891c7d1a1 304 Result<void> DS28E83_DS28E84::verifyEcdsaSignature(
IanBenzMaxim 7:9cd16581b578 305 KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState,
IanBenzMaxim 7:9cd16581b578 306 Ecc256::Signature::const_span signature, span<const uint_least8_t> buffer) {
IanBenzMaxim 7:9cd16581b578 307 const span<const uint_least8_t>::index_type maxBufferSize = 61;
IanBenzMaxim 7:9cd16581b578 308
IanBenzMaxim 7:9cd16581b578 309 if (buffer.size() > maxBufferSize) {
IanBenzMaxim 8:5ea891c7d1a1 310 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 311 }
IanBenzMaxim 7:9cd16581b578 312
IanBenzMaxim 7:9cd16581b578 313 uint_least8_t request[2 + 2 * Ecc256::Scalar::size + maxBufferSize];
IanBenzMaxim 7:9cd16581b578 314 uint_least8_t * requestIt = request;
IanBenzMaxim 7:9cd16581b578 315 *requestIt++ = 0x59;
IanBenzMaxim 7:9cd16581b578 316 switch (key) {
IanBenzMaxim 7:9cd16581b578 317 case KeySecretA:
IanBenzMaxim 7:9cd16581b578 318 if (authorityKey) {
IanBenzMaxim 7:9cd16581b578 319 *requestIt = 2;
IanBenzMaxim 7:9cd16581b578 320 } else {
IanBenzMaxim 7:9cd16581b578 321 *requestIt = 0;
IanBenzMaxim 7:9cd16581b578 322 }
IanBenzMaxim 7:9cd16581b578 323 break;
IanBenzMaxim 7:9cd16581b578 324 case KeySecretB:
IanBenzMaxim 7:9cd16581b578 325 if (authorityKey) {
IanBenzMaxim 7:9cd16581b578 326 *requestIt = 3;
IanBenzMaxim 7:9cd16581b578 327 } else {
IanBenzMaxim 7:9cd16581b578 328 *requestIt = 1;
IanBenzMaxim 7:9cd16581b578 329 }
IanBenzMaxim 7:9cd16581b578 330 break;
IanBenzMaxim 7:9cd16581b578 331 case KeySecretS:
IanBenzMaxim 7:9cd16581b578 332 if (!authorityKey) {
IanBenzMaxim 7:9cd16581b578 333 *requestIt = 4;
IanBenzMaxim 7:9cd16581b578 334 break;
IanBenzMaxim 7:9cd16581b578 335 }
IanBenzMaxim 7:9cd16581b578 336 // else: Go to default case.
IanBenzMaxim 7:9cd16581b578 337 default:
IanBenzMaxim 8:5ea891c7d1a1 338 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 339 }
IanBenzMaxim 7:9cd16581b578 340 *requestIt |= hashType << 3;
IanBenzMaxim 7:9cd16581b578 341 if (gpioState != Unchanged) {
IanBenzMaxim 7:9cd16581b578 342 *requestIt |= 0x40;
IanBenzMaxim 7:9cd16581b578 343 }
IanBenzMaxim 7:9cd16581b578 344 if (gpioState == Conducting) {
IanBenzMaxim 7:9cd16581b578 345 *requestIt |= 0x20;
IanBenzMaxim 7:9cd16581b578 346 }
IanBenzMaxim 7:9cd16581b578 347 requestIt = copy(signature.r.begin(), signature.r.end(), ++requestIt);
IanBenzMaxim 7:9cd16581b578 348 requestIt = copy(signature.s.begin(), signature.s.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 349 requestIt = copy(buffer.begin(), buffer.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 350 return runCommand(make_span(request, requestIt),
IanBenzMaxim 7:9cd16581b578 351 verifyEcdsaTimeMs +
IanBenzMaxim 7:9cd16581b578 352 (hashType == DataInput ? computeTimeMs : 0));
IanBenzMaxim 7:9cd16581b578 353 }
IanBenzMaxim 7:9cd16581b578 354
IanBenzMaxim 8:5ea891c7d1a1 355 Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey(
IanBenzMaxim 7:9cd16581b578 356 KeySecret key, Ecc256::Signature::const_span cert,
IanBenzMaxim 7:9cd16581b578 357 span<const uint_least8_t> certCustomization) {
IanBenzMaxim 7:9cd16581b578 358 return authenticateEcdsaPublicKey(key, true, cert, certCustomization, NULL);
IanBenzMaxim 7:9cd16581b578 359 }
IanBenzMaxim 7:9cd16581b578 360
IanBenzMaxim 8:5ea891c7d1a1 361 Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey(
IanBenzMaxim 7:9cd16581b578 362 KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
IanBenzMaxim 7:9cd16581b578 363 span<const uint_least8_t> certCustomization,
IanBenzMaxim 7:9cd16581b578 364 span<const uint_least8_t> ecdhCustomization) {
IanBenzMaxim 7:9cd16581b578 365 return authenticateEcdsaPublicKey(key, authWrites, cert, certCustomization,
IanBenzMaxim 7:9cd16581b578 366 &ecdhCustomization);
IanBenzMaxim 7:9cd16581b578 367 }
IanBenzMaxim 7:9cd16581b578 368
IanBenzMaxim 8:5ea891c7d1a1 369 Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey(
IanBenzMaxim 7:9cd16581b578 370 KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
IanBenzMaxim 7:9cd16581b578 371 span<const uint_least8_t> certCustomization,
IanBenzMaxim 7:9cd16581b578 372 const span<const uint_least8_t> * ecdhCustomization) {
IanBenzMaxim 7:9cd16581b578 373 const span<const uint_least8_t>::index_type minCustomizationSize = 1;
IanBenzMaxim 7:9cd16581b578 374 const span<const uint_least8_t>::index_type maxCertCustomizationSize = 32;
IanBenzMaxim 7:9cd16581b578 375 const span<const uint_least8_t>::index_type maxEcdhCustomizationSize = 48;
IanBenzMaxim 7:9cd16581b578 376 const span<const uint_least8_t>::index_type maxTotalCustomizationSize = 60;
IanBenzMaxim 7:9cd16581b578 377
IanBenzMaxim 7:9cd16581b578 378 if (!(certCustomization.size() >= minCustomizationSize &&
IanBenzMaxim 7:9cd16581b578 379 certCustomization.size() <= maxCertCustomizationSize &&
IanBenzMaxim 7:9cd16581b578 380 (!ecdhCustomization ||
IanBenzMaxim 7:9cd16581b578 381 (ecdhCustomization->size() >= minCustomizationSize &&
IanBenzMaxim 7:9cd16581b578 382 ecdhCustomization->size() <= maxEcdhCustomizationSize &&
IanBenzMaxim 7:9cd16581b578 383 certCustomization.size() + ecdhCustomization->size() <=
IanBenzMaxim 7:9cd16581b578 384 maxTotalCustomizationSize)))) {
IanBenzMaxim 8:5ea891c7d1a1 385 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 386 }
IanBenzMaxim 7:9cd16581b578 387
IanBenzMaxim 7:9cd16581b578 388 if (key == KeySecretS) {
IanBenzMaxim 8:5ea891c7d1a1 389 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 390 }
IanBenzMaxim 7:9cd16581b578 391
IanBenzMaxim 7:9cd16581b578 392 uint_least8_t
IanBenzMaxim 7:9cd16581b578 393 request[2 + 2 * Ecc256::Scalar::size + maxTotalCustomizationSize];
IanBenzMaxim 7:9cd16581b578 394 uint_least8_t * requestIt = request;
IanBenzMaxim 7:9cd16581b578 395 *requestIt++ = 0xA8;
IanBenzMaxim 7:9cd16581b578 396 *requestIt++ = static_cast<uint_least8_t>(
IanBenzMaxim 7:9cd16581b578 397 ((certCustomization.size() - 1) << 3) | (key << 2) |
IanBenzMaxim 7:9cd16581b578 398 ((ecdhCustomization != NULL) << 1) | (authWrites << 0));
IanBenzMaxim 7:9cd16581b578 399 requestIt = copy(cert.r.begin(), cert.r.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 400 requestIt = copy(cert.s.begin(), cert.s.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 401 requestIt =
IanBenzMaxim 7:9cd16581b578 402 copy(certCustomization.begin(), certCustomization.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 403 int delay = verifyEcdsaTimeMs;
IanBenzMaxim 7:9cd16581b578 404 if (ecdhCustomization) {
IanBenzMaxim 7:9cd16581b578 405 const span<const uint_least8_t>::index_type certCustomizationPaddingSize =
IanBenzMaxim 7:9cd16581b578 406 maxCertCustomizationSize - certCustomization.size();
IanBenzMaxim 7:9cd16581b578 407 std::fill_n(requestIt, certCustomizationPaddingSize, 0);
IanBenzMaxim 7:9cd16581b578 408 requestIt += certCustomizationPaddingSize;
IanBenzMaxim 7:9cd16581b578 409 requestIt =
IanBenzMaxim 7:9cd16581b578 410 copy(ecdhCustomization->begin(), ecdhCustomization->end(), requestIt);
IanBenzMaxim 7:9cd16581b578 411 delay += verifyEcdsaTimeMs;
IanBenzMaxim 7:9cd16581b578 412 }
IanBenzMaxim 7:9cd16581b578 413 return runCommand(make_span(request, requestIt), delay);
IanBenzMaxim 7:9cd16581b578 414 }
IanBenzMaxim 7:9cd16581b578 415
IanBenzMaxim 8:5ea891c7d1a1 416 Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory(
IanBenzMaxim 7:9cd16581b578 417 int pageNum, bool useKeyS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 418 Ecc256::Signature::const_span signature) {
IanBenzMaxim 7:9cd16581b578 419 return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
IanBenzMaxim 7:9cd16581b578 420 NULL);
IanBenzMaxim 7:9cd16581b578 421 }
IanBenzMaxim 7:9cd16581b578 422
IanBenzMaxim 8:5ea891c7d1a1 423 Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory(
IanBenzMaxim 7:9cd16581b578 424 int pageNum, bool useKeyS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 425 Ecc256::Signature::const_span signature,
IanBenzMaxim 7:9cd16581b578 426 EncryptionChallenge::const_span challenge) {
IanBenzMaxim 7:9cd16581b578 427 return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
IanBenzMaxim 7:9cd16581b578 428 &challenge);
IanBenzMaxim 7:9cd16581b578 429 }
IanBenzMaxim 7:9cd16581b578 430
IanBenzMaxim 8:5ea891c7d1a1 431 Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory(
IanBenzMaxim 7:9cd16581b578 432 int pageNum, bool useKeyS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 433 Ecc256::Signature::const_span signature,
IanBenzMaxim 7:9cd16581b578 434 const EncryptionChallenge::const_span * challenge) {
IanBenzMaxim 7:9cd16581b578 435 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 436 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 437 }
IanBenzMaxim 7:9cd16581b578 438
IanBenzMaxim 7:9cd16581b578 439 uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size +
IanBenzMaxim 7:9cd16581b578 440 EncryptionChallenge::size];
IanBenzMaxim 7:9cd16581b578 441 uint_least8_t * requestIt = request;
IanBenzMaxim 7:9cd16581b578 442 *requestIt++ = 0x89;
IanBenzMaxim 7:9cd16581b578 443 *requestIt = pageNum;
IanBenzMaxim 7:9cd16581b578 444 if (useKeyS) {
IanBenzMaxim 7:9cd16581b578 445 *requestIt |= 0x80;
IanBenzMaxim 7:9cd16581b578 446 }
IanBenzMaxim 7:9cd16581b578 447 requestIt = copy(newPageData.begin(), newPageData.end(), ++requestIt);
IanBenzMaxim 7:9cd16581b578 448 requestIt = copy(signature.r.begin(), signature.r.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 449 requestIt = copy(signature.s.begin(), signature.s.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 450 int delay = verifyEcdsaTimeMs + writeMemoryTimeMs;
IanBenzMaxim 7:9cd16581b578 451 if (challenge) {
IanBenzMaxim 7:9cd16581b578 452 requestIt = copy(challenge->begin(), challenge->end(), requestIt);
IanBenzMaxim 7:9cd16581b578 453 delay += computeTimeMs;
IanBenzMaxim 7:9cd16581b578 454 }
IanBenzMaxim 7:9cd16581b578 455 return runCommand(make_span(request, requestIt), delay);
IanBenzMaxim 7:9cd16581b578 456 }
IanBenzMaxim 7:9cd16581b578 457
IanBenzMaxim 8:5ea891c7d1a1 458 Result<void>
IanBenzMaxim 7:9cd16581b578 459 DS28E83_DS28E84::authenticatedSha256WriteMemory(int pageNum, bool useSecretS,
IanBenzMaxim 7:9cd16581b578 460 Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 461 Page::const_span hmac) {
IanBenzMaxim 7:9cd16581b578 462 return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
IanBenzMaxim 7:9cd16581b578 463 NULL);
IanBenzMaxim 7:9cd16581b578 464 }
IanBenzMaxim 7:9cd16581b578 465
IanBenzMaxim 8:5ea891c7d1a1 466 Result<void> DS28E83_DS28E84::authenticatedSha256WriteMemory(
IanBenzMaxim 7:9cd16581b578 467 int pageNum, bool useSecretS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 468 Page::const_span hmac, EncryptionChallenge::const_span challenge) {
IanBenzMaxim 7:9cd16581b578 469 return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
IanBenzMaxim 7:9cd16581b578 470 &challenge);
IanBenzMaxim 7:9cd16581b578 471 }
IanBenzMaxim 7:9cd16581b578 472
IanBenzMaxim 8:5ea891c7d1a1 473 Result<void> DS28E83_DS28E84::authenticatedSha256WriteMemory(
IanBenzMaxim 7:9cd16581b578 474 int pageNum, bool useSecretS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 475 Page::const_span hmac, const EncryptionChallenge::const_span * challenge) {
IanBenzMaxim 7:9cd16581b578 476 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 477 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 478 }
IanBenzMaxim 7:9cd16581b578 479
IanBenzMaxim 7:9cd16581b578 480 uint_least8_t request[3 + 2 * Page::size + EncryptionChallenge::size];
IanBenzMaxim 7:9cd16581b578 481 uint_least8_t * requestIt = request;
IanBenzMaxim 7:9cd16581b578 482 *requestIt++ = 0x99;
IanBenzMaxim 7:9cd16581b578 483 *requestIt++ = pageNum;
IanBenzMaxim 7:9cd16581b578 484 *requestIt++ = useSecretS ? 2 : 0;
IanBenzMaxim 7:9cd16581b578 485 requestIt = copy(newPageData.begin(), newPageData.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 486 requestIt = copy(hmac.begin(), hmac.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 487 int delay = writeMemoryTimeMs + computeTimeMs;
IanBenzMaxim 7:9cd16581b578 488 if (challenge) {
IanBenzMaxim 7:9cd16581b578 489 requestIt = copy(challenge->begin(), challenge->end(), requestIt);
IanBenzMaxim 7:9cd16581b578 490 delay += computeTimeMs;
IanBenzMaxim 7:9cd16581b578 491 }
IanBenzMaxim 7:9cd16581b578 492 return runCommand(make_span(request, requestIt), delay);
IanBenzMaxim 7:9cd16581b578 493 }
IanBenzMaxim 7:9cd16581b578 494
IanBenzMaxim 8:5ea891c7d1a1 495 Result<void> DS28E83_DS28E84::computeAndWriteSha256Secret(
IanBenzMaxim 7:9cd16581b578 496 int pageNum, KeySecret masterSecret, KeySecret destinationSecret,
IanBenzMaxim 7:9cd16581b578 497 Page::const_span partialSecret) {
IanBenzMaxim 7:9cd16581b578 498 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 499 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 500 }
IanBenzMaxim 7:9cd16581b578 501
IanBenzMaxim 7:9cd16581b578 502 uint_least8_t request[3 + Page::size];
IanBenzMaxim 7:9cd16581b578 503 request[0] = 0x3C;
IanBenzMaxim 7:9cd16581b578 504 request[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 505 request[2] = (destinationSecret << 2) | masterSecret;
IanBenzMaxim 7:9cd16581b578 506 copy(partialSecret.begin(), partialSecret.end(), request + 3);
IanBenzMaxim 7:9cd16581b578 507 return runCommand(request, writeMemoryTimeMs + computeTimeMs);
IanBenzMaxim 7:9cd16581b578 508 }
IanBenzMaxim 7:9cd16581b578 509
IanBenzMaxim 8:5ea891c7d1a1 510 Result<void> DS28E83_DS28E84::generateEcc256KeyPair(KeySecret key) {
IanBenzMaxim 7:9cd16581b578 511 if (key == KeySecretS) {
IanBenzMaxim 8:5ea891c7d1a1 512 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 513 }
IanBenzMaxim 7:9cd16581b578 514
IanBenzMaxim 7:9cd16581b578 515 const uint_least8_t request[] = {0xCB, key == KeySecretB};
IanBenzMaxim 7:9cd16581b578 516 return runCommand(request, generateEccKeyPairTimeMs);
IanBenzMaxim 7:9cd16581b578 517 }
IanBenzMaxim 7:9cd16581b578 518
IanBenzMaxim 8:5ea891c7d1a1 519 Result<void> DS28E83_DS28E84::readRng(span<uint_least8_t> data) const {
IanBenzMaxim 7:9cd16581b578 520 const span<uint_least8_t>::index_type maxDataSize = 64;
IanBenzMaxim 7:9cd16581b578 521 if ((data.size() < 1) || (data.size() > maxDataSize)) {
IanBenzMaxim 8:5ea891c7d1a1 522 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 523 }
IanBenzMaxim 7:9cd16581b578 524
IanBenzMaxim 7:9cd16581b578 525 uint_least8_t buffer[1 + maxDataSize];
IanBenzMaxim 7:9cd16581b578 526 buffer[0] = readRngCmd;
IanBenzMaxim 7:9cd16581b578 527 buffer[1] = static_cast<uint_least8_t>(data.size() - 1);
IanBenzMaxim 8:5ea891c7d1a1 528 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 529 runCommand(make_span(buffer, 2), trngGenerationTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 530 make_span(buffer, 1 + data.size()));
IanBenzMaxim 8:5ea891c7d1a1 531 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 532 return response.error();
IanBenzMaxim 7:9cd16581b578 533 }
IanBenzMaxim 8:5ea891c7d1a1 534 copy(response.value().begin(), response.value().end(), data.begin());
IanBenzMaxim 8:5ea891c7d1a1 535 return none;
IanBenzMaxim 7:9cd16581b578 536 }
IanBenzMaxim 7:9cd16581b578 537
IanBenzMaxim 8:5ea891c7d1a1 538 Result<void> DS28E83_DS28E84::entropyHealthTest() const {
IanBenzMaxim 7:9cd16581b578 539 const uint_least8_t request[] = {readRngCmd, 0x80};
IanBenzMaxim 7:9cd16581b578 540 return runCommand(request, trngOnDemandCheckTimeMs);
IanBenzMaxim 7:9cd16581b578 541 }
IanBenzMaxim 7:9cd16581b578 542
IanBenzMaxim 8:5ea891c7d1a1 543 Result<span<uint_least8_t> >
IanBenzMaxim 8:5ea891c7d1a1 544 DS28E83_DS28E84::runCommand(span<const uint_least8_t> request, int delayTime,
IanBenzMaxim 8:5ea891c7d1a1 545 span<uint_least8_t> response) const {
IanBenzMaxim 8:5ea891c7d1a1 546 const Result<span<uint_least8_t> > responseOutput =
IanBenzMaxim 8:5ea891c7d1a1 547 doRunCommand(request, delayTime, response);
IanBenzMaxim 8:5ea891c7d1a1 548 if (!responseOutput) {
IanBenzMaxim 8:5ea891c7d1a1 549 return responseOutput;
IanBenzMaxim 7:9cd16581b578 550 }
IanBenzMaxim 8:5ea891c7d1a1 551 if (responseOutput.value().empty()) {
IanBenzMaxim 8:5ea891c7d1a1 552 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 553 }
IanBenzMaxim 7:9cd16581b578 554 // Parse command result byte.
IanBenzMaxim 8:5ea891c7d1a1 555 switch (responseOutput.value().front()) {
IanBenzMaxim 7:9cd16581b578 556 case 0xAA:
IanBenzMaxim 7:9cd16581b578 557 // Success response.
IanBenzMaxim 7:9cd16581b578 558 break;
IanBenzMaxim 7:9cd16581b578 559
IanBenzMaxim 7:9cd16581b578 560 case 0x00:
IanBenzMaxim 8:5ea891c7d1a1 561 return AuthenticationError;
IanBenzMaxim 7:9cd16581b578 562
IanBenzMaxim 7:9cd16581b578 563 default:
IanBenzMaxim 8:5ea891c7d1a1 564 return error_code(responseOutput.value().front(), errorCategory());
IanBenzMaxim 7:9cd16581b578 565 }
IanBenzMaxim 8:5ea891c7d1a1 566 if (responseOutput.value().size() != response.size()) {
IanBenzMaxim 8:5ea891c7d1a1 567 return InvalidResponseError;
IanBenzMaxim 8:5ea891c7d1a1 568 }
IanBenzMaxim 8:5ea891c7d1a1 569 return responseOutput.value().subspan(1);
IanBenzMaxim 7:9cd16581b578 570 }
IanBenzMaxim 7:9cd16581b578 571
IanBenzMaxim 8:5ea891c7d1a1 572 Result<void> DS28E83_DS28E84::runCommand(span<const uint_least8_t> request,
IanBenzMaxim 8:5ea891c7d1a1 573 int delayTime) const {
IanBenzMaxim 7:9cd16581b578 574 uint_least8_t buffer;
IanBenzMaxim 8:5ea891c7d1a1 575 MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1)));
IanBenzMaxim 8:5ea891c7d1a1 576 return none;
IanBenzMaxim 7:9cd16581b578 577 }
IanBenzMaxim 7:9cd16581b578 578
IanBenzMaxim 7:9cd16581b578 579 const error_category & DS28E83_DS28E84::errorCategory() {
IanBenzMaxim 7:9cd16581b578 580 static class : public error_category {
IanBenzMaxim 7:9cd16581b578 581 public:
IanBenzMaxim 11:3f3bf6bf5e6c 582 virtual const char * name() const {
IanBenzMaxim 11:3f3bf6bf5e6c 583 return "MaximInterfaceDevices.DS28E83_DS28E84";
IanBenzMaxim 11:3f3bf6bf5e6c 584 }
IanBenzMaxim 7:9cd16581b578 585
IanBenzMaxim 7:9cd16581b578 586 virtual std::string message(int condition) const {
IanBenzMaxim 7:9cd16581b578 587 switch (condition) {
IanBenzMaxim 7:9cd16581b578 588 case InvalidOperationError:
IanBenzMaxim 7:9cd16581b578 589 return "Invalid Operation Error";
IanBenzMaxim 7:9cd16581b578 590
IanBenzMaxim 7:9cd16581b578 591 case InvalidParameterError:
IanBenzMaxim 7:9cd16581b578 592 return "Invalid Parameter Error";
IanBenzMaxim 7:9cd16581b578 593
IanBenzMaxim 7:9cd16581b578 594 case InvalidSequenceError:
IanBenzMaxim 7:9cd16581b578 595 return "Invalid Sequence Error";
IanBenzMaxim 7:9cd16581b578 596
IanBenzMaxim 7:9cd16581b578 597 case AuthenticationError:
IanBenzMaxim 7:9cd16581b578 598 return "Authentication Error";
IanBenzMaxim 7:9cd16581b578 599
IanBenzMaxim 7:9cd16581b578 600 case InternalError:
IanBenzMaxim 7:9cd16581b578 601 return "Internal Error";
IanBenzMaxim 7:9cd16581b578 602
IanBenzMaxim 7:9cd16581b578 603 case DeviceDisabledError:
IanBenzMaxim 7:9cd16581b578 604 return "Device Disabled Error";
IanBenzMaxim 7:9cd16581b578 605
IanBenzMaxim 7:9cd16581b578 606 case InvalidResponseError:
IanBenzMaxim 7:9cd16581b578 607 return "Invalid Response Error";
IanBenzMaxim 12:7eb41621ba22 608
IanBenzMaxim 12:7eb41621ba22 609 case EntropyHealthTestError:
IanBenzMaxim 12:7eb41621ba22 610 return "Entropy Health Test Error";
IanBenzMaxim 7:9cd16581b578 611 }
IanBenzMaxim 7:9cd16581b578 612 return defaultErrorMessage(condition);
IanBenzMaxim 7:9cd16581b578 613 }
IanBenzMaxim 7:9cd16581b578 614 } instance;
IanBenzMaxim 7:9cd16581b578 615 return instance;
IanBenzMaxim 7:9cd16581b578 616 }
IanBenzMaxim 7:9cd16581b578 617
IanBenzMaxim 8:5ea891c7d1a1 618 Result<void> DS28E84::decrementCounter() {
IanBenzMaxim 7:9cd16581b578 619 const uint_least8_t request = 0xC9;
IanBenzMaxim 7:9cd16581b578 620 return runCommand(make_span(&request, 1), writeMemoryTimeMs);
IanBenzMaxim 7:9cd16581b578 621 }
IanBenzMaxim 7:9cd16581b578 622
IanBenzMaxim 8:5ea891c7d1a1 623 Result<void> DS28E84::deviceStateControl(StateOperation operation) {
IanBenzMaxim 7:9cd16581b578 624 const uint_least8_t request[] = {0x55, operation == Backup};
IanBenzMaxim 7:9cd16581b578 625 return runCommand(request, writeMemoryTimeMs);
IanBenzMaxim 7:9cd16581b578 626 }
IanBenzMaxim 7:9cd16581b578 627
IanBenzMaxim 8:5ea891c7d1a1 628 Result<void> computeMultiblockHash(DS28E83_DS28E84 & device,
IanBenzMaxim 8:5ea891c7d1a1 629 span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 630 span<const uint_least8_t>::index_type dataIdx = 0;
IanBenzMaxim 8:5ea891c7d1a1 631 while (dataIdx < data.size()) {
IanBenzMaxim 7:9cd16581b578 632 const span<const uint_least8_t>::index_type remainingSize =
IanBenzMaxim 7:9cd16581b578 633 data.size() - dataIdx;
IanBenzMaxim 7:9cd16581b578 634 const span<const uint_least8_t>::index_type chunkSize =
IanBenzMaxim 7:9cd16581b578 635 std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
IanBenzMaxim 8:5ea891c7d1a1 636 MaximInterfaceCore_TRY(
IanBenzMaxim 7:9cd16581b578 637 device.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
IanBenzMaxim 8:5ea891c7d1a1 638 data.subspan(dataIdx, chunkSize)));
IanBenzMaxim 7:9cd16581b578 639 dataIdx += chunkSize;
IanBenzMaxim 7:9cd16581b578 640 }
IanBenzMaxim 8:5ea891c7d1a1 641 return none;
IanBenzMaxim 7:9cd16581b578 642 }
IanBenzMaxim 7:9cd16581b578 643
IanBenzMaxim 7:9cd16581b578 644 static void setAnonymous(RomId::span romId) {
IanBenzMaxim 7:9cd16581b578 645 std::fill(romId.begin(), romId.end(), 0xFF);
IanBenzMaxim 7:9cd16581b578 646 }
IanBenzMaxim 7:9cd16581b578 647
IanBenzMaxim 7:9cd16581b578 648 DS28E83_DS28E84::PageAuthenticationData &
IanBenzMaxim 7:9cd16581b578 649 DS28E83_DS28E84::PageAuthenticationData::setAnonymousRomId() {
IanBenzMaxim 7:9cd16581b578 650 setAnonymous(romId());
IanBenzMaxim 7:9cd16581b578 651 return *this;
IanBenzMaxim 7:9cd16581b578 652 }
IanBenzMaxim 7:9cd16581b578 653
IanBenzMaxim 7:9cd16581b578 654 DS28E83_DS28E84::ComputeSecretData::ComputeSecretData() : data() {
IanBenzMaxim 7:9cd16581b578 655 setPageNum(0);
IanBenzMaxim 7:9cd16581b578 656 setManId(ManId::array());
IanBenzMaxim 7:9cd16581b578 657 }
IanBenzMaxim 7:9cd16581b578 658
IanBenzMaxim 7:9cd16581b578 659 DS28E83_DS28E84::ComputeSecretData &
IanBenzMaxim 7:9cd16581b578 660 DS28E83_DS28E84::ComputeSecretData::setManId(ManId::const_span manId) {
IanBenzMaxim 7:9cd16581b578 661 ManId::array validatedManId;
IanBenzMaxim 7:9cd16581b578 662 copy(manId, make_span(validatedManId));
IanBenzMaxim 7:9cd16581b578 663 validatedManId[1] |= 0x80;
IanBenzMaxim 7:9cd16581b578 664 data.setManId(validatedManId);
IanBenzMaxim 7:9cd16581b578 665 return *this;
IanBenzMaxim 7:9cd16581b578 666 }
IanBenzMaxim 7:9cd16581b578 667
IanBenzMaxim 7:9cd16581b578 668 DS28E83_DS28E84::DecryptionHmacData &
IanBenzMaxim 7:9cd16581b578 669 DS28E83_DS28E84::DecryptionHmacData::setAnonymousRomId() {
IanBenzMaxim 7:9cd16581b578 670 setAnonymous(romId());
IanBenzMaxim 7:9cd16581b578 671 return *this;
IanBenzMaxim 7:9cd16581b578 672 }
IanBenzMaxim 7:9cd16581b578 673
IanBenzMaxim 7:9cd16581b578 674 } // namespace MaximInterfaceDevices