Device interface library for multiple platforms including Mbed.

Dependents:   DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS28C40.cpp Source File

DS28C40.cpp

00001 /*******************************************************************************
00002 * Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved.
00003 *
00004 * Permission is hereby granted, free of charge, to any person obtaining a
00005 * copy of this software and associated documentation files (the "Software"),
00006 * to deal in the Software without restriction, including without limitation
00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008 * and/or sell copies of the Software, and to permit persons to whom the
00009 * Software is furnished to do so, subject to the following conditions:
00010 *
00011 * The above copyright notice and this permission notice shall be included
00012 * in all copies or substantial portions of the Software.
00013 *
00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020 * OTHER DEALINGS IN THE SOFTWARE.
00021 *
00022 * Except as contained in this notice, the name of Maxim Integrated
00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024 * Products, Inc. Branding Policy.
00025 *
00026 * The mere transfer of this software does not imply any licenses
00027 * of trade secrets, proprietary technology, copyrights, patents,
00028 * trademarks, maskwork rights, or any other form of intellectual
00029 * property whatsoever. Maxim Integrated Products, Inc. retains all
00030 * ownership rights.
00031 *******************************************************************************/
00032 
00033 #include <stddef.h>
00034 #include <algorithm>
00035 #include <MaximInterfaceCore/Error.hpp>
00036 #include "DS28C40.hpp"
00037 
00038 namespace MaximInterfaceDevices {
00039 
00040 using namespace Core;
00041 using std::copy;
00042 using std::pair;
00043 
00044 static const int readMemoryTimeMs = 2;
00045 static const int writeMemoryTimeMs = 150;
00046 static const int writeStateTimeMs = 15;
00047 static const int generateEccKeyPairTimeMs = 500;
00048 static const int generateEcdsaSignatureTimeMs = 50;
00049 static const int computeTimeMs = 4;
00050 static const int verifyEcdsaTimeMs = 160;
00051 static const int trngGenerationTimeMs = 50;
00052 static const int trngOnDemandCheckTimeMs = 50;
00053 
00054 static const uint_least8_t computeAndReadPageAuthenticationCmd = 0xA5;
00055 static const uint_least8_t readRngCmd = 0xD2;
00056 
00057 const int DS28C40::publicKeyAxPage;
00058 const int DS28C40::publicKeyAyPage;
00059 const int DS28C40::publicKeyBxPage;
00060 const int DS28C40::publicKeyByPage;
00061 const int DS28C40::authorityPublicKeyAxPage;
00062 const int DS28C40::authorityPublicKeyAyPage;
00063 const int DS28C40::authorityPublicKeyBxPage;
00064 const int DS28C40::authorityPublicKeyByPage;
00065 const int DS28C40::privateKeyAPage;
00066 const int DS28C40::privateKeyBPage;
00067 const int DS28C40::secretAPage;
00068 const int DS28C40::secretBPage;
00069 const int DS28C40::romOptionsPage;
00070 const int DS28C40::gpioControlPage;
00071 const int DS28C40::publicKeySxPage;
00072 const int DS28C40::publicKeySyPage;
00073 
00074 const int DS28C40::memoryPages;
00075 const int DS28C40::protectionBlocks;
00076 
00077 Result<void> DS28C40::writeMemory(int pageNum, Page::const_span page) {
00078   if (pageNum < 0 || pageNum >= memoryPages) {
00079     return InvalidParameterError;
00080   }
00081 
00082   uint_least8_t request[2 + Page::size];
00083   request[0] = 0x96;
00084   request[1] = pageNum;
00085   copy(page.begin(), page.end(), request + 2);
00086   return runCommand(request, writeMemoryTimeMs);
00087 }
00088 
00089 Result<DS28C40::Page::array> DS28C40::readMemory(int pageNum) const {
00090   if (pageNum < 0 || pageNum >= memoryPages) {
00091     return InvalidParameterError;
00092   }
00093 
00094   uint_least8_t buffer[1 + Page::size];
00095   buffer[0] = 0x44;
00096   buffer[1] = pageNum;
00097   const Result<span<uint_least8_t> > response =
00098       runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer);
00099   if (!response) {
00100     return response.error();
00101   }
00102   Page::array page;
00103   copy(response.value().begin(), response.value().end(), page.begin());
00104   return page;
00105 }
00106 
00107 Result<pair<DS28C40::EncryptionChallenge::array, DS28C40::Page::array> >
00108 DS28C40::encryptedReadMemory(int pageNum, KeySecret secret) const {
00109   if (pageNum < 0 || pageNum >= memoryPages) {
00110     return InvalidParameterError;
00111   }
00112 
00113   const size_t requestSize = 3;
00114   const size_t responseSize = 1 + EncryptionChallenge::size + Page::size;
00115   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00116   buffer[0] = 0x4B;
00117   buffer[1] = pageNum;
00118   buffer[2] = secret;
00119   const Result<span<uint_least8_t> > response = runCommand(
00120       make_span(buffer, requestSize), readMemoryTimeMs + computeTimeMs,
00121       make_span(buffer, responseSize));
00122   if (!response) {
00123     return response.error();
00124   }
00125   pair<EncryptionChallenge::array, Page::array> data;
00126   span<uint_least8_t>::const_iterator begin = response.value().begin();
00127   span<uint_least8_t>::const_iterator end = begin + data.first.size();
00128   copy(begin, end, data.first.begin());
00129   begin = end;
00130   end = begin + data.second.size();
00131   copy(begin, end, data.second.begin());
00132   return data;
00133 }
00134 
00135 Result<pair<Optional<DS28C40::KeySecret>, DS28C40::BlockProtection> >
00136 DS28C40::readBlockProtection(int blockNumber) const {
00137   if (blockNumber < 0 || blockNumber >= protectionBlocks) {
00138     return InvalidParameterError;
00139   }
00140 
00141   const size_t requestSize = 2;
00142   const size_t responseSize = 3;
00143   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00144   buffer[0] = 0xAA;
00145   buffer[1] = blockNumber;
00146   const Result<span<uint_least8_t> > response =
00147       runCommand(make_span(buffer, requestSize), readMemoryTimeMs,
00148                  make_span(buffer, responseSize));
00149   if (!response) {
00150     return response.error();
00151   }
00152   if ((response.value()[0] & 0x3F) != blockNumber) {
00153     return InvalidResponseError;
00154   }
00155   pair<Optional<KeySecret>, BlockProtection> data;
00156   switch (response.value()[0] >> 6) {
00157   case 0:
00158     data.first = none;
00159     break;
00160   case 1:
00161     data.first = KeySecretA;
00162     break;
00163   case 2:
00164     data.first = KeySecretB;
00165     break;
00166   default:
00167     return InvalidResponseError;
00168   }
00169   if ((response.value()[1] & 0x20) != 0) {
00170     return InvalidResponseError;
00171   }
00172   data.second = response.value()[1];
00173   return data;
00174 }
00175 
00176 Result<void> DS28C40::setBlockProtection(int blockNum, KeySecret keySecret,
00177                                          const BlockProtection & protection) {
00178   if (blockNum < 0 || blockNum >= protectionBlocks || keySecret == KeySecretS) {
00179     return InvalidParameterError;
00180   }
00181 
00182   const uint_least8_t request[] = {
00183       0xC3,
00184       static_cast<uint_least8_t>((keySecret == KeySecretB ? 0x80 : 0x40) |
00185                                  blockNum),
00186       static_cast<uint_least8_t>(protection.to_ulong())};
00187   return runCommand(request, writeStateTimeMs);
00188 }
00189 
00190 Result<Ecc256::Signature::array> DS28C40::computeAndReadEcdsaPageAuthentication(
00191     int pageNum, KeySecret key, Page::const_span challenge) const {
00192   if (pageNum < 0 || pageNum >= memoryPages || key == KeySecretS) {
00193     return InvalidParameterError;
00194   }
00195 
00196   const size_t requestSize = 3 + Page::size;
00197   const size_t responseSize = 1 + 2 * Ecc256::Scalar::size;
00198   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00199   buffer[0] = computeAndReadPageAuthenticationCmd;
00200   buffer[1] = pageNum;
00201   buffer[2] = key + 3;
00202   copy(challenge.begin(), challenge.end(), buffer + 3);
00203   const Result<span<uint_least8_t> > response =
00204       runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs,
00205                  make_span(buffer, responseSize));
00206   if (!response) {
00207     return response.error();
00208   }
00209   Ecc256::Signature::array signature;
00210   span<uint_least8_t>::const_iterator begin = response.value().begin();
00211   span<uint_least8_t>::const_iterator end = begin + signature.s.size();
00212   copy(begin, end, signature.s.begin());
00213   begin = end;
00214   end = begin + signature.r.size();
00215   copy(begin, end, signature.r.begin());
00216   return signature;
00217 }
00218 
00219 Result<DS28C40::Page::array> DS28C40::computeAndReadSha256PageAuthentication(
00220     int pageNum, KeySecret secret, Page::const_span challenge) const {
00221   if (pageNum < 0 || pageNum >= memoryPages) {
00222     return InvalidParameterError;
00223   }
00224 
00225   const size_t requestSize = 3 + Page::size;
00226   const size_t responseSize = 1 + Page::size;
00227   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00228   buffer[0] = computeAndReadPageAuthenticationCmd;
00229   buffer[1] = pageNum;
00230   buffer[2] = secret;
00231   copy(challenge.begin(), challenge.end(), buffer + 3);
00232   const Result<span<uint_least8_t> > response =
00233       runCommand(make_span(buffer, requestSize), computeTimeMs,
00234                  make_span(buffer, responseSize));
00235   if (!response) {
00236     return response.error();
00237   }
00238   Page::array hmac;
00239   copy(response.value().begin(), response.value().end(), hmac.begin());
00240   return hmac;
00241 }
00242 
00243 Result<void> DS28C40::computeMultiblockHash(bool firstBlock, bool lastBlock,
00244                                             span<const uint_least8_t> data) {
00245   const span<const uint_least8_t>::index_type maxDataSize = 64;
00246 
00247   if (data.size() < 1 || data.size() > maxDataSize) {
00248     return InvalidParameterError;
00249   }
00250 
00251   uint_least8_t buffer[2 + maxDataSize];
00252   buffer[0] = 0x33;
00253   buffer[1] = 0;
00254   if (firstBlock) {
00255     buffer[1] |= 0x40;
00256   }
00257   if (lastBlock) {
00258     buffer[1] |= 0x80;
00259   }
00260   copy(data.begin(), data.end(), buffer + 2);
00261   return runCommand(make_span(buffer, 2 + data.size()), computeTimeMs);
00262 }
00263 
00264 Result<void> DS28C40::verifyEcdsaSignature(
00265     KeySecret key, bool authorityKey, GpioState gpioState,
00266     Ecc256::Signature::const_span signature, span<const uint_least8_t> data) {
00267   return verifyEcdsaSignature(key, authorityKey, DataInput, gpioState,
00268                               signature, data);
00269 }
00270 
00271 Result<void> DS28C40::verifyEcdsaSignature(
00272     KeySecret key, bool authorityKey, GpioState gpioState,
00273     Ecc256::Signature::const_span signature, Page::const_span hash) {
00274   return verifyEcdsaSignature(key, authorityKey, HashInput, gpioState,
00275                               signature, hash);
00276 }
00277 
00278 Result<void>
00279 DS28C40::verifyEcdsaSignature(KeySecret key, bool authorityKey,
00280                               GpioState gpioState,
00281                               Ecc256::Signature::const_span signature) {
00282   return verifyEcdsaSignature(key, authorityKey, THASH, gpioState, signature,
00283                               span<const uint_least8_t>());
00284 }
00285 
00286 Result<void> DS28C40::verifyEcdsaSignature(
00287     KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState,
00288     Ecc256::Signature::const_span signature, span<const uint_least8_t> buffer) {
00289   const span<const uint_least8_t>::index_type maxBufferSize = 61;
00290 
00291   if (buffer.size() > maxBufferSize) {
00292     return InvalidParameterError;
00293   }
00294 
00295   uint_least8_t request[2 + 2 * Ecc256::Scalar::size + maxBufferSize];
00296   uint_least8_t * requestIt = request;
00297   *requestIt++ = 0x59;
00298   switch (key) {
00299   case KeySecretA:
00300     if (authorityKey) {
00301       *requestIt = 2;
00302     } else {
00303       *requestIt = 0;
00304     }
00305     break;
00306   case KeySecretB:
00307     if (authorityKey) {
00308       *requestIt = 3;
00309     } else {
00310       *requestIt = 1;
00311     }
00312     break;
00313   case KeySecretS:
00314     if (!authorityKey) {
00315       *requestIt = 4;
00316       break;
00317     }
00318     // else: Go to default case.
00319   default:
00320     return InvalidParameterError;
00321   }
00322   *requestIt |= hashType << 3;
00323   if (gpioState != Unchanged) {
00324     *requestIt |= 0x40;
00325   }
00326   if (gpioState == Conducting) {
00327     *requestIt |= 0x20;
00328   }
00329   requestIt = copy(signature.r.begin(), signature.r.end(), ++requestIt);
00330   requestIt = copy(signature.s.begin(), signature.s.end(), requestIt);
00331   requestIt = copy(buffer.begin(), buffer.end(), requestIt);
00332   return runCommand(make_span(request, requestIt),
00333                     verifyEcdsaTimeMs +
00334                         (hashType == DataInput ? computeTimeMs : 0));
00335 }
00336 
00337 Result<void> DS28C40::authenticateEcdsaPublicKey(
00338     KeySecret key, Ecc256::Signature::const_span cert,
00339     span<const uint_least8_t> certCustomization) {
00340   return authenticateEcdsaPublicKey(key, true, cert, certCustomization, NULL);
00341 }
00342 
00343 Result<void> DS28C40::authenticateEcdsaPublicKey(
00344     KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
00345     span<const uint_least8_t> certCustomization,
00346     span<const uint_least8_t> ecdhCustomization) {
00347   return authenticateEcdsaPublicKey(key, authWrites, cert, certCustomization,
00348                                     &ecdhCustomization);
00349 }
00350 
00351 Result<void> DS28C40::authenticateEcdsaPublicKey(
00352     KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
00353     span<const uint_least8_t> certCustomization,
00354     const span<const uint_least8_t> * ecdhCustomization) {
00355   const span<const uint_least8_t>::index_type minCustomizationSize = 1;
00356   const span<const uint_least8_t>::index_type maxCertCustomizationSize = 32;
00357   const span<const uint_least8_t>::index_type maxEcdhCustomizationSize = 48;
00358   const span<const uint_least8_t>::index_type maxTotalCustomizationSize = 60;
00359 
00360   if (!(certCustomization.size() >= minCustomizationSize &&
00361         certCustomization.size() <= maxCertCustomizationSize &&
00362         (!ecdhCustomization ||
00363          (ecdhCustomization->size() >= minCustomizationSize &&
00364           ecdhCustomization->size() <= maxEcdhCustomizationSize &&
00365           certCustomization.size() + ecdhCustomization->size() <=
00366               maxTotalCustomizationSize)))) {
00367     return InvalidParameterError;
00368   }
00369 
00370   if (key == KeySecretS) {
00371     return InvalidParameterError;
00372   }
00373 
00374   uint_least8_t
00375       request[2 + 2 * Ecc256::Scalar::size + maxTotalCustomizationSize];
00376   uint_least8_t * requestIt = request;
00377   *requestIt++ = 0xA8;
00378   *requestIt++ = static_cast<uint_least8_t>(
00379       ((certCustomization.size() - 1) << 3) | (key << 2) |
00380       ((ecdhCustomization != NULL) << 1) | (authWrites << 0));
00381   requestIt = copy(cert.r.begin(), cert.r.end(), requestIt);
00382   requestIt = copy(cert.s.begin(), cert.s.end(), requestIt);
00383   requestIt =
00384       copy(certCustomization.begin(), certCustomization.end(), requestIt);
00385   int delay = verifyEcdsaTimeMs;
00386   if (ecdhCustomization) {
00387     const span<const uint_least8_t>::index_type certCustomizationPaddingSize =
00388         maxCertCustomizationSize - certCustomization.size();
00389     std::fill_n(requestIt, certCustomizationPaddingSize, 0);
00390     requestIt += certCustomizationPaddingSize;
00391     requestIt =
00392         copy(ecdhCustomization->begin(), ecdhCustomization->end(), requestIt);
00393     delay += verifyEcdsaTimeMs;
00394   }
00395   return runCommand(make_span(request, requestIt), delay);
00396 }
00397 
00398 Result<void> DS28C40::authenticatedEcdsaWriteMemory(
00399     int pageNum, bool useKeyS, Page::const_span newPageData,
00400     Ecc256::Signature::const_span signature) {
00401   return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
00402                                        NULL);
00403 }
00404 
00405 Result<void> DS28C40::authenticatedEcdsaWriteMemory(
00406     int pageNum, bool useKeyS, Page::const_span newPageData,
00407     Ecc256::Signature::const_span signature,
00408     EncryptionChallenge::const_span challenge) {
00409   return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
00410                                        &challenge);
00411 }
00412 
00413 Result<void> DS28C40::authenticatedEcdsaWriteMemory(
00414     int pageNum, bool useKeyS, Page::const_span newPageData,
00415     Ecc256::Signature::const_span signature,
00416     const EncryptionChallenge::const_span * challenge) {
00417   if (pageNum < 0 || pageNum >= memoryPages) {
00418     return InvalidParameterError;
00419   }
00420 
00421   uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size +
00422                         EncryptionChallenge::size];
00423   uint_least8_t * requestIt = request;
00424   *requestIt++ = 0x89;
00425   *requestIt = pageNum;
00426   if (useKeyS) {
00427     *requestIt |= 0x80;
00428   }
00429   requestIt = copy(newPageData.begin(), newPageData.end(), ++requestIt);
00430   requestIt = copy(signature.r.begin(), signature.r.end(), requestIt);
00431   requestIt = copy(signature.s.begin(), signature.s.end(), requestIt);
00432   int delay = verifyEcdsaTimeMs + writeMemoryTimeMs;
00433   if (challenge) {
00434     requestIt = copy(challenge->begin(), challenge->end(), requestIt);
00435     delay += computeTimeMs;
00436   }
00437   return runCommand(make_span(request, requestIt), delay);
00438 }
00439 
00440 Result<void>
00441 DS28C40::authenticatedSha256WriteMemory(int pageNum, bool useSecretS,
00442                                         Page::const_span newPageData,
00443                                         Page::const_span hmac) {
00444   return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
00445                                         NULL);
00446 }
00447 
00448 Result<void> DS28C40::authenticatedSha256WriteMemory(
00449     int pageNum, bool useSecretS, Page::const_span newPageData,
00450     Page::const_span hmac, EncryptionChallenge::const_span challenge) {
00451   return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
00452                                         &challenge);
00453 }
00454 
00455 Result<void> DS28C40::authenticatedSha256WriteMemory(
00456     int pageNum, bool useSecretS, Page::const_span newPageData,
00457     Page::const_span hmac, const EncryptionChallenge::const_span * challenge) {
00458   if (pageNum < 0 || pageNum >= memoryPages) {
00459     return InvalidParameterError;
00460   }
00461 
00462   uint_least8_t request[3 + 2 * Page::size + EncryptionChallenge::size];
00463   uint_least8_t * requestIt = request;
00464   *requestIt++ = 0x99;
00465   *requestIt++ = pageNum;
00466   *requestIt++ = useSecretS ? 2 : 0;
00467   requestIt = copy(newPageData.begin(), newPageData.end(), requestIt);
00468   requestIt = copy(hmac.begin(), hmac.end(), requestIt);
00469   int delay = writeMemoryTimeMs + computeTimeMs;
00470   if (challenge) {
00471     requestIt = copy(challenge->begin(), challenge->end(), requestIt);
00472     delay += computeTimeMs;
00473   }
00474   return runCommand(make_span(request, requestIt), delay);
00475 }
00476 
00477 Result<void>
00478 DS28C40::computeAndWriteSha256Secret(int pageNum, KeySecret masterSecret,
00479                                      KeySecret destinationSecret,
00480                                      Page::const_span partialSecret) {
00481   if (pageNum < 0 || pageNum >= memoryPages) {
00482     return InvalidParameterError;
00483   }
00484 
00485   uint_least8_t request[3 + Page::size];
00486   request[0] = 0x3C;
00487   request[1] = pageNum;
00488   request[2] = (destinationSecret << 2) | masterSecret;
00489   copy(partialSecret.begin(), partialSecret.end(), request + 3);
00490   return runCommand(request, writeMemoryTimeMs + computeTimeMs);
00491 }
00492 
00493 Result<void> DS28C40::generateEcc256KeyPair(KeySecret key) {
00494   if (key == KeySecretS) {
00495     return InvalidParameterError;
00496   }
00497 
00498   const uint_least8_t request[] = {0xCB, key == KeySecretB};
00499   return runCommand(request, generateEccKeyPairTimeMs);
00500 }
00501 
00502 Result<void> DS28C40::readRng(span<uint_least8_t> data) const {
00503   const span<uint_least8_t>::index_type maxDataSize = 64;
00504   if ((data.size() < 1) || (data.size() > maxDataSize)) {
00505     return InvalidParameterError;
00506   }
00507 
00508   uint_least8_t buffer[1 + maxDataSize];
00509   buffer[0] = readRngCmd;
00510   buffer[1] = static_cast<uint_least8_t>(data.size() - 1);
00511   const Result<span<uint_least8_t> > response =
00512       runCommand(make_span(buffer, 2), trngGenerationTimeMs,
00513                  make_span(buffer, 1 + data.size()));
00514   if (!response) {
00515     return response.error();
00516   }
00517   copy(response.value().begin(), response.value().end(), data.begin());
00518   return none;
00519 }
00520 
00521 Result<void> DS28C40::entropyHealthTest() const {
00522   const uint_least8_t request[] = {readRngCmd, 0x80};
00523   return runCommand(request, trngOnDemandCheckTimeMs);
00524 }
00525 
00526 Result<span<uint_least8_t> >
00527 DS28C40::runCommand(span<const uint_least8_t> request, int delayTime,
00528                     span<uint_least8_t> response) const {
00529   const Result<span<uint_least8_t> > responseOutput =
00530       doRunCommand(request, delayTime, response);
00531   if (!responseOutput) {
00532     return responseOutput;
00533   }
00534   if (responseOutput.value().empty()) {
00535     return InvalidResponseError;
00536   }
00537   // Parse command result byte.
00538   switch (responseOutput.value().front()) {
00539   case 0xAA:
00540     // Success response.
00541     break;
00542 
00543   case 0x00:
00544     return AuthenticationError;
00545 
00546   default:
00547     return error_code(responseOutput.value().front(), errorCategory());
00548   }
00549   if (responseOutput.value().size() != response.size()) {
00550     return InvalidResponseError;
00551   }
00552   return responseOutput.value().subspan(1);
00553 }
00554 
00555 Result<void> DS28C40::runCommand(span<const uint_least8_t> request,
00556                                  int delayTime) const {
00557   uint_least8_t buffer;
00558   MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1)));
00559   return none;
00560 }
00561 
00562 const error_category & DS28C40::errorCategory() {
00563   static class : public error_category {
00564   public:
00565     virtual const char * name() const {
00566       return "MaximInterfaceDevices.DS28C40";
00567     }
00568 
00569     virtual std::string message(int condition) const {
00570       switch (condition) {
00571       case InvalidOperationError:
00572         return "Invalid Operation Error";
00573 
00574       case InvalidParameterError:
00575         return "Invalid Parameter Error";
00576 
00577       case InvalidSequenceError:
00578         return "Invalid Sequence Error";
00579 
00580       case AuthenticationError:
00581         return "Authentication Error";
00582 
00583       case InternalError:
00584         return "Internal Error";
00585 
00586       case DeviceDisabledError:
00587         return "Device Disabled Error";
00588 
00589       case InvalidResponseError:
00590         return "Invalid Response Error";
00591 
00592       case EntropyHealthTestError:
00593         return "Entropy Health Test Error";
00594       }
00595       return defaultErrorMessage(condition);
00596     }
00597   } instance;
00598   return instance;
00599 }
00600 
00601 Result<void> computeMultiblockHash(DS28C40 & device,
00602                                    span<const uint_least8_t> data) {
00603   span<const uint_least8_t>::index_type dataIdx = 0;
00604   while (dataIdx < data.size()) {
00605     const span<const uint_least8_t>::index_type remainingSize =
00606         data.size() - dataIdx;
00607     const span<const uint_least8_t>::index_type chunkSize =
00608         std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
00609     MaximInterfaceCore_TRY(
00610         device.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
00611                                      data.subspan(dataIdx, chunkSize)));
00612     dataIdx += chunkSize;
00613   }
00614   return none;
00615 }
00616 
00617 static void setAnonymous(RomId::span romId) {
00618   std::fill(romId.begin(), romId.end(), 0xFF);
00619 }
00620 
00621 DS28C40::PageAuthenticationData &
00622 DS28C40::PageAuthenticationData::setAnonymousRomId() {
00623   setAnonymous(romId());
00624   return *this;
00625 }
00626 
00627 DS28C40::ComputeSecretData::ComputeSecretData() : data() {
00628   setPageNum(0);
00629   setManId(ManId::array());
00630 }
00631 
00632 DS28C40::ComputeSecretData &
00633 DS28C40::ComputeSecretData::setManId(ManId::const_span manId) {
00634   ManId::array validatedManId;
00635   copy(manId, make_span(validatedManId));
00636   validatedManId[1] |= 0x80;
00637   data.setManId(validatedManId);
00638   return *this;
00639 }
00640 
00641 DS28C40::DecryptionHmacData & DS28C40::DecryptionHmacData::setAnonymousRomId() {
00642   setAnonymous(romId());
00643   return *this;
00644 }
00645 
00646 } // namespace MaximInterfaceDevices