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 DS28E83_DS28E84.cpp Source File

DS28E83_DS28E84.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 "DS28E83_DS28E84.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 = 100;
00046 static const int writeStateTimeMs = 15;
00047 static const int generateEccKeyPairTimeMs = 350;
00048 static const int generateEcdsaSignatureTimeMs = 80;
00049 static const int computeTimeMs = 4;
00050 static const int verifyEcdsaTimeMs = 160;
00051 static const int trngGenerationTimeMs = 40;
00052 static const int trngOnDemandCheckTimeMs = 65;
00053 
00054 static const uint_least8_t computeAndReadPageAuthenticationCmd = 0xA5;
00055 static const uint_least8_t readRngCmd = 0xD2;
00056 
00057 static const int memoryPages =
00058     MaximInterfaceCore_MAX(DS28E83::memoryPages, DS28E84::memoryPages);
00059 static const int protectionBlocks = MaximInterfaceCore_MAX(
00060     DS28E83::protectionBlocks, DS28E84::protectionBlocks);
00061 
00062 const int DS28E83_DS28E84::publicKeyAxPage;
00063 const int DS28E83_DS28E84::publicKeyAyPage;
00064 const int DS28E83_DS28E84::publicKeyBxPage;
00065 const int DS28E83_DS28E84::publicKeyByPage;
00066 const int DS28E83_DS28E84::authorityPublicKeyAxPage;
00067 const int DS28E83_DS28E84::authorityPublicKeyAyPage;
00068 const int DS28E83_DS28E84::authorityPublicKeyBxPage;
00069 const int DS28E83_DS28E84::authorityPublicKeyByPage;
00070 const int DS28E83_DS28E84::privateKeyAPage;
00071 const int DS28E83_DS28E84::privateKeyBPage;
00072 const int DS28E83_DS28E84::secretAPage;
00073 const int DS28E83_DS28E84::secretBPage;
00074 const int DS28E83_DS28E84::romOptionsPage;
00075 const int DS28E83_DS28E84::gpioControlPage;
00076 const int DS28E83_DS28E84::publicKeySxPage;
00077 const int DS28E83_DS28E84::publicKeySyPage;
00078 
00079 const int DS28E83::memoryPages;
00080 const int DS28E83::protectionBlocks;
00081 
00082 const int DS28E84::publicKeySxBackupPage;
00083 const int DS28E84::publicKeySyBackupPage;
00084 const int DS28E84::decrementCounterPage;
00085 const int DS28E84::memoryPages;
00086 const int DS28E84::protectionBlocks;
00087 
00088 Result<void> DS28E83_DS28E84::writeMemory(int pageNum, Page::const_span page) {
00089   if (pageNum < 0 || pageNum >= memoryPages) {
00090     return InvalidParameterError;
00091   }
00092 
00093   uint_least8_t request[2 + Page::size];
00094   request[0] = 0x96;
00095   request[1] = pageNum;
00096   copy(page.begin(), page.end(), request + 2);
00097   return runCommand(request, writeMemoryTimeMs);
00098 }
00099 
00100 Result<DS28E83_DS28E84::Page::array>
00101 DS28E83_DS28E84::readMemory(int pageNum) const {
00102   if (pageNum < 0 || pageNum >= memoryPages) {
00103     return InvalidParameterError;
00104   }
00105 
00106   uint_least8_t buffer[1 + Page::size];
00107   buffer[0] = 0x44;
00108   buffer[1] = pageNum;
00109   const Result<span<uint_least8_t> > response =
00110       runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer);
00111   if (!response) {
00112     return response.error();
00113   }
00114   Page::array page;
00115   copy(response.value().begin(), response.value().end(), page.begin());
00116   return page;
00117 }
00118 
00119 Result<pair<DS28E83_DS28E84::EncryptionChallenge::array,
00120             DS28E83_DS28E84::Page::array> >
00121 DS28E83_DS28E84::encryptedReadMemory(int pageNum, KeySecret secret) const {
00122   if (pageNum < 0 || pageNum >= memoryPages) {
00123     return InvalidParameterError;
00124   }
00125 
00126   const size_t requestSize = 3;
00127   const size_t responseSize = 1 + EncryptionChallenge::size + Page::size;
00128   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00129   buffer[0] = 0x4B;
00130   buffer[1] = pageNum;
00131   buffer[2] = secret;
00132   const Result<span<uint_least8_t> > response = runCommand(
00133       make_span(buffer, requestSize), readMemoryTimeMs + computeTimeMs,
00134       make_span(buffer, responseSize));
00135   if (!response) {
00136     return response.error();
00137   }
00138   pair<EncryptionChallenge::array, Page::array> data;
00139   span<uint_least8_t>::const_iterator begin = response.value().begin();
00140   span<uint_least8_t>::const_iterator end = begin + data.first.size();
00141   copy(begin, end, data.first.begin());
00142   begin = end;
00143   end = begin + data.second.size();
00144   copy(begin, end, data.second.begin());
00145   return data;
00146 }
00147 
00148 Result<pair<Optional<DS28E83_DS28E84::KeySecret>,
00149             DS28E83_DS28E84::BlockProtection> >
00150 DS28E83_DS28E84::readBlockProtection(int blockNumber) const {
00151   if (blockNumber < 0 || blockNumber >= protectionBlocks) {
00152     return InvalidParameterError;
00153   }
00154 
00155   const size_t requestSize = 2;
00156   const size_t responseSize = 3;
00157   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00158   buffer[0] = 0xAA;
00159   buffer[1] = blockNumber;
00160   const Result<span<uint_least8_t> > response =
00161       runCommand(make_span(buffer, requestSize), readMemoryTimeMs,
00162                  make_span(buffer, responseSize));
00163   if (!response) {
00164     return response.error();
00165   }
00166   if ((response.value()[0] & 0x3F) != blockNumber) {
00167     return InvalidResponseError;
00168   }
00169   pair<Optional<KeySecret>, BlockProtection> data;
00170   switch (response.value()[0] >> 6) {
00171   case 0:
00172     data.first = none;
00173     break;
00174   case 1:
00175     data.first = KeySecretA;
00176     break;
00177   case 2:
00178     data.first = KeySecretB;
00179     break;
00180   default:
00181     return InvalidResponseError;
00182   }
00183   if ((response.value()[1] & 0x20) != 0) {
00184     return InvalidResponseError;
00185   }
00186   data.second = response.value()[1];
00187   return data;
00188 }
00189 
00190 Result<void>
00191 DS28E83_DS28E84::setBlockProtection(int blockNum, KeySecret keySecret,
00192                                     const BlockProtection & protection) {
00193   if (blockNum < 0 || blockNum >= protectionBlocks || keySecret == KeySecretS) {
00194     return InvalidParameterError;
00195   }
00196 
00197   const uint_least8_t request[] = {
00198       0xC3,
00199       static_cast<uint_least8_t>((keySecret == KeySecretB ? 0x80 : 0x40) |
00200                                  blockNum),
00201       static_cast<uint_least8_t>(protection.to_ulong())};
00202   return runCommand(request, writeStateTimeMs);
00203 }
00204 
00205 Result<Ecc256::Signature::array>
00206 DS28E83_DS28E84::computeAndReadEcdsaPageAuthentication(
00207     int pageNum, KeySecret key, Page::const_span challenge) const {
00208   if (pageNum < 0 || pageNum >= memoryPages || key == KeySecretS) {
00209     return InvalidParameterError;
00210   }
00211 
00212   const size_t requestSize = 3 + Page::size;
00213   const size_t responseSize = 1 + 2 * Ecc256::Scalar::size;
00214   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00215   buffer[0] = computeAndReadPageAuthenticationCmd;
00216   buffer[1] = pageNum;
00217   buffer[2] = key + 3;
00218   copy(challenge.begin(), challenge.end(), buffer + 3);
00219   const Result<span<uint_least8_t> > response =
00220       runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs,
00221                  make_span(buffer, responseSize));
00222   if (!response) {
00223     return response.error();
00224   }
00225   Ecc256::Signature::array signature;
00226   span<uint_least8_t>::const_iterator begin = response.value().begin();
00227   span<uint_least8_t>::const_iterator end = begin + signature.s.size();
00228   copy(begin, end, signature.s.begin());
00229   begin = end;
00230   end = begin + signature.r.size();
00231   copy(begin, end, signature.r.begin());
00232   return signature;
00233 }
00234 
00235 Result<DS28E83_DS28E84::Page::array>
00236 DS28E83_DS28E84::computeAndReadSha256PageAuthentication(
00237     int pageNum, KeySecret secret, Page::const_span challenge) const {
00238   if (pageNum < 0 || pageNum >= memoryPages) {
00239     return InvalidParameterError;
00240   }
00241 
00242   const size_t requestSize = 3 + Page::size;
00243   const size_t responseSize = 1 + Page::size;
00244   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00245   buffer[0] = computeAndReadPageAuthenticationCmd;
00246   buffer[1] = pageNum;
00247   buffer[2] = secret;
00248   copy(challenge.begin(), challenge.end(), buffer + 3);
00249   const Result<span<uint_least8_t> > response =
00250       runCommand(make_span(buffer, requestSize), computeTimeMs,
00251                  make_span(buffer, responseSize));
00252   if (!response) {
00253     return response.error();
00254   }
00255   Page::array hmac;
00256   copy(response.value().begin(), response.value().end(), hmac.begin());
00257   return hmac;
00258 }
00259 
00260 Result<void>
00261 DS28E83_DS28E84::computeMultiblockHash(bool firstBlock, bool lastBlock,
00262                                        span<const uint_least8_t> data) {
00263   const span<const uint_least8_t>::index_type maxDataSize = 64;
00264 
00265   if (data.size() < 1 || data.size() > maxDataSize) {
00266     return InvalidParameterError;
00267   }
00268 
00269   uint_least8_t buffer[2 + maxDataSize];
00270   buffer[0] = 0x33;
00271   buffer[1] = 0;
00272   if (firstBlock) {
00273     buffer[1] |= 0x40;
00274   }
00275   if (lastBlock) {
00276     buffer[1] |= 0x80;
00277   }
00278   copy(data.begin(), data.end(), buffer + 2);
00279   return runCommand(make_span(buffer, 2 + data.size()), computeTimeMs);
00280 }
00281 
00282 Result<void> DS28E83_DS28E84::verifyEcdsaSignature(
00283     KeySecret key, bool authorityKey, GpioState gpioState,
00284     Ecc256::Signature::const_span signature, span<const uint_least8_t> data) {
00285   return verifyEcdsaSignature(key, authorityKey, DataInput, gpioState,
00286                               signature, data);
00287 }
00288 
00289 Result<void> DS28E83_DS28E84::verifyEcdsaSignature(
00290     KeySecret key, bool authorityKey, GpioState gpioState,
00291     Ecc256::Signature::const_span signature, Page::const_span hash) {
00292   return verifyEcdsaSignature(key, authorityKey, HashInput, gpioState,
00293                               signature, hash);
00294 }
00295 
00296 Result<void>
00297 DS28E83_DS28E84::verifyEcdsaSignature(KeySecret key, bool authorityKey,
00298                                       GpioState gpioState,
00299                                       Ecc256::Signature::const_span signature) {
00300   return verifyEcdsaSignature(key, authorityKey, THASH, gpioState, signature,
00301                               span<const uint_least8_t>());
00302 }
00303 
00304 Result<void> DS28E83_DS28E84::verifyEcdsaSignature(
00305     KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState,
00306     Ecc256::Signature::const_span signature, span<const uint_least8_t> buffer) {
00307   const span<const uint_least8_t>::index_type maxBufferSize = 61;
00308 
00309   if (buffer.size() > maxBufferSize) {
00310     return InvalidParameterError;
00311   }
00312 
00313   uint_least8_t request[2 + 2 * Ecc256::Scalar::size + maxBufferSize];
00314   uint_least8_t * requestIt = request;
00315   *requestIt++ = 0x59;
00316   switch (key) {
00317   case KeySecretA:
00318     if (authorityKey) {
00319       *requestIt = 2;
00320     } else {
00321       *requestIt = 0;
00322     }
00323     break;
00324   case KeySecretB:
00325     if (authorityKey) {
00326       *requestIt = 3;
00327     } else {
00328       *requestIt = 1;
00329     }
00330     break;
00331   case KeySecretS:
00332     if (!authorityKey) {
00333       *requestIt = 4;
00334       break;
00335     }
00336     // else: Go to default case.
00337   default:
00338     return InvalidParameterError;
00339   }
00340   *requestIt |= hashType << 3;
00341   if (gpioState != Unchanged) {
00342     *requestIt |= 0x40;
00343   }
00344   if (gpioState == Conducting) {
00345     *requestIt |= 0x20;
00346   }
00347   requestIt = copy(signature.r.begin(), signature.r.end(), ++requestIt);
00348   requestIt = copy(signature.s.begin(), signature.s.end(), requestIt);
00349   requestIt = copy(buffer.begin(), buffer.end(), requestIt);
00350   return runCommand(make_span(request, requestIt),
00351                     verifyEcdsaTimeMs +
00352                         (hashType == DataInput ? computeTimeMs : 0));
00353 }
00354 
00355 Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey(
00356     KeySecret key, Ecc256::Signature::const_span cert,
00357     span<const uint_least8_t> certCustomization) {
00358   return authenticateEcdsaPublicKey(key, true, cert, certCustomization, NULL);
00359 }
00360 
00361 Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey(
00362     KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
00363     span<const uint_least8_t> certCustomization,
00364     span<const uint_least8_t> ecdhCustomization) {
00365   return authenticateEcdsaPublicKey(key, authWrites, cert, certCustomization,
00366                                     &ecdhCustomization);
00367 }
00368 
00369 Result<void> DS28E83_DS28E84::authenticateEcdsaPublicKey(
00370     KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
00371     span<const uint_least8_t> certCustomization,
00372     const span<const uint_least8_t> * ecdhCustomization) {
00373   const span<const uint_least8_t>::index_type minCustomizationSize = 1;
00374   const span<const uint_least8_t>::index_type maxCertCustomizationSize = 32;
00375   const span<const uint_least8_t>::index_type maxEcdhCustomizationSize = 48;
00376   const span<const uint_least8_t>::index_type maxTotalCustomizationSize = 60;
00377 
00378   if (!(certCustomization.size() >= minCustomizationSize &&
00379         certCustomization.size() <= maxCertCustomizationSize &&
00380         (!ecdhCustomization ||
00381          (ecdhCustomization->size() >= minCustomizationSize &&
00382           ecdhCustomization->size() <= maxEcdhCustomizationSize &&
00383           certCustomization.size() + ecdhCustomization->size() <=
00384               maxTotalCustomizationSize)))) {
00385     return InvalidParameterError;
00386   }
00387 
00388   if (key == KeySecretS) {
00389     return InvalidParameterError;
00390   }
00391 
00392   uint_least8_t
00393       request[2 + 2 * Ecc256::Scalar::size + maxTotalCustomizationSize];
00394   uint_least8_t * requestIt = request;
00395   *requestIt++ = 0xA8;
00396   *requestIt++ = static_cast<uint_least8_t>(
00397       ((certCustomization.size() - 1) << 3) | (key << 2) |
00398       ((ecdhCustomization != NULL) << 1) | (authWrites << 0));
00399   requestIt = copy(cert.r.begin(), cert.r.end(), requestIt);
00400   requestIt = copy(cert.s.begin(), cert.s.end(), requestIt);
00401   requestIt =
00402       copy(certCustomization.begin(), certCustomization.end(), requestIt);
00403   int delay = verifyEcdsaTimeMs;
00404   if (ecdhCustomization) {
00405     const span<const uint_least8_t>::index_type certCustomizationPaddingSize =
00406         maxCertCustomizationSize - certCustomization.size();
00407     std::fill_n(requestIt, certCustomizationPaddingSize, 0);
00408     requestIt += certCustomizationPaddingSize;
00409     requestIt =
00410         copy(ecdhCustomization->begin(), ecdhCustomization->end(), requestIt);
00411     delay += verifyEcdsaTimeMs;
00412   }
00413   return runCommand(make_span(request, requestIt), delay);
00414 }
00415 
00416 Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory(
00417     int pageNum, bool useKeyS, Page::const_span newPageData,
00418     Ecc256::Signature::const_span signature) {
00419   return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
00420                                        NULL);
00421 }
00422 
00423 Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory(
00424     int pageNum, bool useKeyS, Page::const_span newPageData,
00425     Ecc256::Signature::const_span signature,
00426     EncryptionChallenge::const_span challenge) {
00427   return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
00428                                        &challenge);
00429 }
00430 
00431 Result<void> DS28E83_DS28E84::authenticatedEcdsaWriteMemory(
00432     int pageNum, bool useKeyS, Page::const_span newPageData,
00433     Ecc256::Signature::const_span signature,
00434     const EncryptionChallenge::const_span * challenge) {
00435   if (pageNum < 0 || pageNum >= memoryPages) {
00436     return InvalidParameterError;
00437   }
00438 
00439   uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size +
00440                         EncryptionChallenge::size];
00441   uint_least8_t * requestIt = request;
00442   *requestIt++ = 0x89;
00443   *requestIt = pageNum;
00444   if (useKeyS) {
00445     *requestIt |= 0x80;
00446   }
00447   requestIt = copy(newPageData.begin(), newPageData.end(), ++requestIt);
00448   requestIt = copy(signature.r.begin(), signature.r.end(), requestIt);
00449   requestIt = copy(signature.s.begin(), signature.s.end(), requestIt);
00450   int delay = verifyEcdsaTimeMs + writeMemoryTimeMs;
00451   if (challenge) {
00452     requestIt = copy(challenge->begin(), challenge->end(), requestIt);
00453     delay += computeTimeMs;
00454   }
00455   return runCommand(make_span(request, requestIt), delay);
00456 }
00457 
00458 Result<void>
00459 DS28E83_DS28E84::authenticatedSha256WriteMemory(int pageNum, bool useSecretS,
00460                                                 Page::const_span newPageData,
00461                                                 Page::const_span hmac) {
00462   return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
00463                                         NULL);
00464 }
00465 
00466 Result<void> DS28E83_DS28E84::authenticatedSha256WriteMemory(
00467     int pageNum, bool useSecretS, Page::const_span newPageData,
00468     Page::const_span hmac, EncryptionChallenge::const_span challenge) {
00469   return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
00470                                         &challenge);
00471 }
00472 
00473 Result<void> DS28E83_DS28E84::authenticatedSha256WriteMemory(
00474     int pageNum, bool useSecretS, Page::const_span newPageData,
00475     Page::const_span hmac, const EncryptionChallenge::const_span * challenge) {
00476   if (pageNum < 0 || pageNum >= memoryPages) {
00477     return InvalidParameterError;
00478   }
00479 
00480   uint_least8_t request[3 + 2 * Page::size + EncryptionChallenge::size];
00481   uint_least8_t * requestIt = request;
00482   *requestIt++ = 0x99;
00483   *requestIt++ = pageNum;
00484   *requestIt++ = useSecretS ? 2 : 0;
00485   requestIt = copy(newPageData.begin(), newPageData.end(), requestIt);
00486   requestIt = copy(hmac.begin(), hmac.end(), requestIt);
00487   int delay = writeMemoryTimeMs + computeTimeMs;
00488   if (challenge) {
00489     requestIt = copy(challenge->begin(), challenge->end(), requestIt);
00490     delay += computeTimeMs;
00491   }
00492   return runCommand(make_span(request, requestIt), delay);
00493 }
00494 
00495 Result<void> DS28E83_DS28E84::computeAndWriteSha256Secret(
00496     int pageNum, KeySecret masterSecret, KeySecret destinationSecret,
00497     Page::const_span partialSecret) {
00498   if (pageNum < 0 || pageNum >= memoryPages) {
00499     return InvalidParameterError;
00500   }
00501 
00502   uint_least8_t request[3 + Page::size];
00503   request[0] = 0x3C;
00504   request[1] = pageNum;
00505   request[2] = (destinationSecret << 2) | masterSecret;
00506   copy(partialSecret.begin(), partialSecret.end(), request + 3);
00507   return runCommand(request, writeMemoryTimeMs + computeTimeMs);
00508 }
00509 
00510 Result<void> DS28E83_DS28E84::generateEcc256KeyPair(KeySecret key) {
00511   if (key == KeySecretS) {
00512     return InvalidParameterError;
00513   }
00514 
00515   const uint_least8_t request[] = {0xCB, key == KeySecretB};
00516   return runCommand(request, generateEccKeyPairTimeMs);
00517 }
00518 
00519 Result<void> DS28E83_DS28E84::readRng(span<uint_least8_t> data) const {
00520   const span<uint_least8_t>::index_type maxDataSize = 64;
00521   if ((data.size() < 1) || (data.size() > maxDataSize)) {
00522     return InvalidParameterError;
00523   }
00524 
00525   uint_least8_t buffer[1 + maxDataSize];
00526   buffer[0] = readRngCmd;
00527   buffer[1] = static_cast<uint_least8_t>(data.size() - 1);
00528   const Result<span<uint_least8_t> > response =
00529       runCommand(make_span(buffer, 2), trngGenerationTimeMs,
00530                  make_span(buffer, 1 + data.size()));
00531   if (!response) {
00532     return response.error();
00533   }
00534   copy(response.value().begin(), response.value().end(), data.begin());
00535   return none;
00536 }
00537 
00538 Result<void> DS28E83_DS28E84::entropyHealthTest() const {
00539   const uint_least8_t request[] = {readRngCmd, 0x80};
00540   return runCommand(request, trngOnDemandCheckTimeMs);
00541 }
00542 
00543 Result<span<uint_least8_t> >
00544 DS28E83_DS28E84::runCommand(span<const uint_least8_t> request, int delayTime,
00545                             span<uint_least8_t> response) const {
00546   const Result<span<uint_least8_t> > responseOutput =
00547       doRunCommand(request, delayTime, response);
00548   if (!responseOutput) {
00549     return responseOutput;
00550   }
00551   if (responseOutput.value().empty()) {
00552     return InvalidResponseError;
00553   }
00554   // Parse command result byte.
00555   switch (responseOutput.value().front()) {
00556   case 0xAA:
00557     // Success response.
00558     break;
00559 
00560   case 0x00:
00561     return AuthenticationError;
00562 
00563   default:
00564     return error_code(responseOutput.value().front(), errorCategory());
00565   }
00566   if (responseOutput.value().size() != response.size()) {
00567     return InvalidResponseError;
00568   }
00569   return responseOutput.value().subspan(1);
00570 }
00571 
00572 Result<void> DS28E83_DS28E84::runCommand(span<const uint_least8_t> request,
00573                                          int delayTime) const {
00574   uint_least8_t buffer;
00575   MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1)));
00576   return none;
00577 }
00578 
00579 const error_category & DS28E83_DS28E84::errorCategory() {
00580   static class : public error_category {
00581   public:
00582     virtual const char * name() const {
00583       return "MaximInterfaceDevices.DS28E83_DS28E84";
00584     }
00585 
00586     virtual std::string message(int condition) const {
00587       switch (condition) {
00588       case InvalidOperationError:
00589         return "Invalid Operation Error";
00590 
00591       case InvalidParameterError:
00592         return "Invalid Parameter Error";
00593 
00594       case InvalidSequenceError:
00595         return "Invalid Sequence Error";
00596 
00597       case AuthenticationError:
00598         return "Authentication Error";
00599 
00600       case InternalError:
00601         return "Internal Error";
00602 
00603       case DeviceDisabledError:
00604         return "Device Disabled Error";
00605 
00606       case InvalidResponseError:
00607         return "Invalid Response Error";
00608 
00609       case EntropyHealthTestError:
00610         return "Entropy Health Test Error";
00611       }
00612       return defaultErrorMessage(condition);
00613     }
00614   } instance;
00615   return instance;
00616 }
00617 
00618 Result<void> DS28E84::decrementCounter() {
00619   const uint_least8_t request = 0xC9;
00620   return runCommand(make_span(&request, 1), writeMemoryTimeMs);
00621 }
00622 
00623 Result<void> DS28E84::deviceStateControl(StateOperation operation) {
00624   const uint_least8_t request[] = {0x55, operation == Backup};
00625   return runCommand(request, writeMemoryTimeMs);
00626 }
00627 
00628 Result<void> computeMultiblockHash(DS28E83_DS28E84 & device,
00629                                    span<const uint_least8_t> data) {
00630   span<const uint_least8_t>::index_type dataIdx = 0;
00631   while (dataIdx < data.size()) {
00632     const span<const uint_least8_t>::index_type remainingSize =
00633         data.size() - dataIdx;
00634     const span<const uint_least8_t>::index_type chunkSize =
00635         std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
00636     MaximInterfaceCore_TRY(
00637         device.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
00638                                      data.subspan(dataIdx, chunkSize)));
00639     dataIdx += chunkSize;
00640   }
00641   return none;
00642 }
00643 
00644 static void setAnonymous(RomId::span romId) {
00645   std::fill(romId.begin(), romId.end(), 0xFF);
00646 }
00647 
00648 DS28E83_DS28E84::PageAuthenticationData &
00649 DS28E83_DS28E84::PageAuthenticationData::setAnonymousRomId() {
00650   setAnonymous(romId());
00651   return *this;
00652 }
00653 
00654 DS28E83_DS28E84::ComputeSecretData::ComputeSecretData() : data() {
00655   setPageNum(0);
00656   setManId(ManId::array());
00657 }
00658 
00659 DS28E83_DS28E84::ComputeSecretData &
00660 DS28E83_DS28E84::ComputeSecretData::setManId(ManId::const_span manId) {
00661   ManId::array validatedManId;
00662   copy(manId, make_span(validatedManId));
00663   validatedManId[1] |= 0x80;
00664   data.setManId(validatedManId);
00665   return *this;
00666 }
00667 
00668 DS28E83_DS28E84::DecryptionHmacData &
00669 DS28E83_DS28E84::DecryptionHmacData::setAnonymousRomId() {
00670   setAnonymous(romId());
00671   return *this;
00672 }
00673 
00674 } // namespace MaximInterfaceDevices