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

DS28C36_DS2476.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 <algorithm>
00034 #include <MaximInterfaceCore/Error.hpp>
00035 #include <MaximInterfaceCore/I2CMaster.hpp>
00036 #include <MaximInterfaceCore/RomId.hpp>
00037 #include "DS28C36_DS2476.hpp"
00038 
00039 #define TRY MaximInterfaceCore_TRY
00040 #define TRY_VALUE MaximInterfaceCore_TRY_VALUE
00041 
00042 namespace MaximInterfaceDevices {
00043 
00044 using namespace Core;
00045 using namespace Ecc256;
00046 using std::copy;
00047 
00048 static Result<void> convertResultByte(uint_least8_t resultByte) {
00049   return (resultByte == 0xAA)
00050              ? makeResult(none)
00051              : error_code((resultByte == 0x00)
00052                               ? static_cast<int>(DS28C36::AuthenticationError)
00053                               : resultByte,
00054                           DS28C36::errorCategory());
00055 }
00056 
00057 const int DS28C36::publicKeyAxPage;
00058 const int DS28C36::publicKeyAyPage;
00059 const int DS28C36::publicKeyBxPage;
00060 const int DS28C36::publicKeyByPage;
00061 const int DS28C36::publicKeyCxPage;
00062 const int DS28C36::publicKeyCyPage;
00063 const int DS28C36::privateKeyAPage;
00064 const int DS28C36::privateKeyBPage;
00065 const int DS28C36::privateKeyCPage;
00066 const int DS28C36::secretAPage;
00067 const int DS28C36::secretBPage;
00068 const int DS28C36::decrementCounterPage;
00069 const int DS28C36::romOptionsPage;
00070 const int DS28C36::gpioControlPage;
00071 const int DS28C36::publicKeySxPage;
00072 const int DS28C36::publicKeySyPage;
00073 const int DS28C36::memoryPages;
00074 
00075 Result<void> DS28C36::writeMemory(int pageNum, Page::const_span page) {
00076   if (pageNum < 0 || pageNum >= memoryPages) {
00077     return InvalidParameterError;
00078   }
00079 
00080   uint_least8_t buffer[1 + Page::size];
00081   buffer[0] = pageNum;
00082   copy(page.begin(), page.end(), buffer + 1);
00083   Result<void> result = writeCommand(0x96, buffer);
00084   if (!result) {
00085     return result;
00086   }
00087   sleep(writeMemoryTimeMs);
00088   result = readFixedLengthResponse(make_span(buffer, 1));
00089   if (!result) {
00090     return result;
00091   }
00092   result = convertResultByte(buffer[0]);
00093   return result;
00094 }
00095 
00096 Result<DS28C36::Page::array> DS28C36::readMemory(int pageNum) const {
00097   if (pageNum < 0 || pageNum >= memoryPages) {
00098     return InvalidParameterError;
00099   }
00100 
00101   const uint_least8_t parameter = pageNum;
00102   Result<void> result = writeCommand(0x69, make_span(&parameter, 1));
00103   if (!result) {
00104     return result.error();
00105   }
00106   sleep(readMemoryTimeMs);
00107   array<uint_least8_t, 1 + Page::size> response;
00108   result = readFixedLengthResponse(response);
00109   if (!result) {
00110     return result.error();
00111   }
00112   result = convertResultByte(response[0]);
00113   if (!result) {
00114     return result.error();
00115   }
00116   Page::array page;
00117   copy(response.begin() + 1, response.end(), page.begin());
00118   return page;
00119 }
00120 
00121 Result<void> DS28C36::writeBuffer(span<const uint_least8_t> data) {
00122   return writeCommand(0x87, data);
00123 }
00124 
00125 Result<std::vector<uint_least8_t> > DS28C36::readBuffer() const {
00126   TRY(writeCommand(0x5A));
00127   std::vector<uint_least8_t> buffer(80);
00128   span<uint_least8_t>::index_type bufferLength;
00129   TRY_VALUE(bufferLength, readVariableLengthResponse(buffer));
00130   buffer.resize(bufferLength);
00131   return buffer;
00132 }
00133 
00134 Result<DS28C36::PageProtection> DS28C36::readPageProtection(int pageNum) const {
00135   if (pageNum < 0 || pageNum >= memoryPages) {
00136     return InvalidParameterError;
00137   }
00138 
00139   uint_least8_t buffer = pageNum;
00140   Result<void> result = writeCommand(0xAA, make_span(&buffer, 1));
00141   if (!result) {
00142     return result.error();
00143   }
00144   sleep(readMemoryTimeMs);
00145   result = readFixedLengthResponse(make_span(&buffer, 1));
00146   if (!result) {
00147     return result.error();
00148   }
00149   return PageProtection(buffer);
00150 }
00151 
00152 Result<void> DS28C36::setPageProtection(int pageNum,
00153                                         const PageProtection & protection) {
00154   if (pageNum < 0 || pageNum >= memoryPages) {
00155     return InvalidParameterError;
00156   }
00157 
00158   uint_least8_t buffer[] = {static_cast<uint_least8_t>(pageNum),
00159                             static_cast<uint_least8_t>(protection.to_ulong())};
00160   Result<void> result = writeCommand(0xC3, buffer);
00161   if (!result) {
00162     return result;
00163   }
00164   sleep(writeMemoryTimeMs);
00165   result = readFixedLengthResponse(make_span(buffer, 1));
00166   if (!result) {
00167     return result;
00168   }
00169   result = convertResultByte(buffer[0]);
00170   return result;
00171 }
00172 
00173 Result<void> DS28C36::decrementCounter() {
00174   Result<void> result = writeCommand(0xC9);
00175   if (!result) {
00176     return result;
00177   }
00178   sleep(writeMemoryTimeMs);
00179   uint_least8_t response;
00180   result = readFixedLengthResponse(make_span(&response, 1));
00181   if (!result) {
00182     return result;
00183   }
00184   result = convertResultByte(response);
00185   return result;
00186 }
00187 
00188 Result<void> DS28C36::readRng(span<uint_least8_t> data) const {
00189   if ((data.size() < 1) || (data.size() > 64)) {
00190     return InvalidParameterError;
00191   }
00192 
00193   data[0] = static_cast<uint_least8_t>(data.size() - 1);
00194   Result<void> result = writeCommand(0xD2, data.first(1));
00195   if (!result) {
00196     return result;
00197   }
00198   sleep(sha256ComputationTimeMs);
00199   result = readFixedLengthResponse(data);
00200   return result;
00201 }
00202 
00203 Result<std::pair<DS28C36::EncryptionChallenge::array, DS28C36::Page::array> >
00204 DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum) const {
00205   if (pageNum < 0 || pageNum >= memoryPages) {
00206     return InvalidParameterError;
00207   }
00208 
00209   const uint_least8_t parameter = (secretNum << 6) | pageNum;
00210   Result<void> result = writeCommand(0x4B, make_span(&parameter, 1));
00211   if (!result) {
00212     return result.error();
00213   }
00214   sleep(readMemoryTimeMs + sha256ComputationTimeMs);
00215   uint_least8_t response[1 + EncryptionChallenge::size + Page::size];
00216   result = readFixedLengthResponse(response);
00217   if (!result) {
00218     return result.error();
00219   }
00220   result = convertResultByte(response[0]);
00221   if (!result) {
00222     return result.error();
00223   }
00224   std::pair<DS28C36::EncryptionChallenge::array, DS28C36::Page::array> data;
00225   const uint_least8_t * begin = response + 1;
00226   const uint_least8_t * end = begin + data.first.size();
00227   copy(begin, end, data.first.begin());
00228   begin = end;
00229   end = begin + data.second.size();
00230   copy(begin, end, data.second.begin());
00231   return data;
00232 }
00233 
00234 Result<void>
00235 DS28C36::computeAndReadPageAuthentication(int pageNum,
00236                                           AuthType authType) const {
00237   if (pageNum < 0 || pageNum >= memoryPages) {
00238     return InvalidParameterError;
00239   }
00240 
00241   const uint_least8_t parameter = (authType << 5) | pageNum;
00242   return writeCommand(0xA5, make_span(&parameter, 1));
00243 }
00244 
00245 Result<Signature::array>
00246 DS28C36::computeAndReadPageAuthentication(int pageNum, KeyNum keyNum) const {
00247   AuthType authType;
00248   switch (keyNum) {
00249   case KeyNumA:
00250     authType = EcdsaWithKeyA;
00251     break;
00252   case KeyNumB:
00253     authType = EcdsaWithKeyB;
00254     break;
00255   case KeyNumC:
00256     authType = EcdsaWithKeyC;
00257     break;
00258   default:
00259     return InvalidParameterError;
00260   }
00261   Result<void> result = computeAndReadPageAuthentication(pageNum, authType);
00262   if (!result) {
00263     return result.error();
00264   }
00265   sleep(readMemoryTimeMs + generateEcdsaSignatureTimeMs);
00266   uint_least8_t response[1 + 2 * Scalar::size];
00267   result = readFixedLengthResponse(response);
00268   if (!result) {
00269     return result.error();
00270   }
00271   result = convertResultByte(response[0]);
00272   if (!result) {
00273     return result.error();
00274   }
00275   Signature::array signature;
00276   const uint_least8_t * begin = response + 1;
00277   const uint_least8_t * end = begin + signature.s.size();
00278   copy(begin, end, signature.s.begin());
00279   begin = end;
00280   end = begin + signature.r.size();
00281   copy(begin, end, signature.r.begin());
00282   return signature;
00283 }
00284 
00285 Result<DS28C36::Page::array>
00286 DS28C36::computeAndReadPageAuthentication(int pageNum,
00287                                           SecretNum secretNum) const {
00288   AuthType authType;
00289   switch (secretNum) {
00290   case SecretNumA:
00291     authType = HmacWithSecretA;
00292     break;
00293   case SecretNumB:
00294     authType = HmacWithSecretB;
00295     break;
00296   case SecretNumS:
00297     authType = HmacWithSecretS;
00298     break;
00299   default:
00300     return InvalidParameterError;
00301   }
00302   Result<void> result = computeAndReadPageAuthentication(pageNum, authType);
00303   if (!result) {
00304     return result.error();
00305   }
00306   sleep(readMemoryTimeMs + sha256ComputationTimeMs);
00307   array<uint_least8_t, 1 + Page::size> response;
00308   result = readFixedLengthResponse(response);
00309   if (!result) {
00310     return result.error();
00311   }
00312   result = convertResultByte(response[0]);
00313   if (!result) {
00314     return result.error();
00315   }
00316   Page::array hmac;
00317   copy(response.begin() + 1, response.end(), hmac.begin());
00318   return hmac;
00319 }
00320 
00321 Result<void> DS28C36::authenticatedSha2WriteMemory(int pageNum,
00322                                                    SecretNum secretNum,
00323                                                    Page::const_span page) {
00324   if (pageNum < 0 || pageNum >= memoryPages) {
00325     return InvalidParameterError;
00326   }
00327 
00328   uint_least8_t buffer[1 + Page::size];
00329   buffer[0] = (secretNum << 6) | pageNum;
00330   copy(page.begin(), page.end(), buffer + 1);
00331   Result<void> result = writeCommand(0x99, buffer);
00332   if (!result) {
00333     return result;
00334   }
00335   sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs));
00336   result = readFixedLengthResponse(make_span(buffer, 1));
00337   if (!result) {
00338     return result;
00339   }
00340   result = convertResultByte(buffer[0]);
00341   return result;
00342 }
00343 
00344 Result<void> DS28C36::computeAndLockSha2Secret(int pageNum,
00345                                                SecretNum msecretNum,
00346                                                SecretNum dsecretNum,
00347                                                bool writeProtectEnable) {
00348   // User pages only
00349   if (pageNum < 0 || pageNum > 15) {
00350     return InvalidParameterError;
00351   }
00352 
00353   uint_least8_t buffer[] = {
00354       static_cast<uint_least8_t>((dsecretNum << 6) | (msecretNum << 4) |
00355                                  pageNum),
00356       static_cast<uint_least8_t>(writeProtectEnable ? 0x80 : 0x00)};
00357   Result<void> result = writeCommand(0x3C, buffer);
00358   if (!result) {
00359     return result;
00360   }
00361   sleep(sha256ComputationTimeMs +
00362         ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs));
00363   result = readFixedLengthResponse(make_span(buffer, 1));
00364   if (!result) {
00365     return result;
00366   }
00367   result = convertResultByte(buffer[0]);
00368   return result;
00369 }
00370 
00371 Result<void> DS28C36::generateEcc256KeyPair(KeyNum keyNum,
00372                                             bool writeProtectEnable) {
00373   if (keyNum == KeyNumS) {
00374     return InvalidParameterError;
00375   }
00376 
00377   uint_least8_t buffer = keyNum;
00378   if (writeProtectEnable) {
00379     buffer |= 0x80;
00380   }
00381   Result<void> result = writeCommand(0xCB, make_span(&buffer, 1));
00382   if (!result) {
00383     return result;
00384   }
00385   sleep(generateEccKeyPairTimeMs);
00386   result = readFixedLengthResponse(make_span(&buffer, 1));
00387   if (!result) {
00388     return result;
00389   }
00390   result = convertResultByte(buffer);
00391   return result;
00392 }
00393 
00394 Result<void> DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock,
00395                                             span<const uint_least8_t> data) {
00396   const span<const uint_least8_t>::index_type maxDataSize = 64;
00397 
00398   if (data.size() < 1 || data.size() > maxDataSize) {
00399     return InvalidParameterError;
00400   }
00401 
00402   uint_least8_t buffer[1 + maxDataSize];
00403   buffer[0] = 0;
00404   if (firstBlock) {
00405     buffer[0] |= 0x40;
00406   }
00407   if (lastBlock) {
00408     buffer[0] |= 0x80;
00409   }
00410   copy(data.begin(), data.end(), buffer + 1);
00411   Result<void> result = writeCommand(0x33, make_span(buffer, data.size() + 1));
00412   if (!result) {
00413     return result;
00414   }
00415   sleep(sha256ComputationTimeMs);
00416   result = readFixedLengthResponse(make_span(buffer, 1));
00417   if (!result) {
00418     return result;
00419   }
00420   result = convertResultByte(buffer[0]);
00421   return result;
00422 }
00423 
00424 Result<void> DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
00425                                            Signature::const_span signature,
00426                                            PioState pioa, PioState piob) {
00427   uint_least8_t buffer[1 + 2 * Scalar::size];
00428   buffer[0] = keyNum | (hashType << 2);
00429   if (pioa != Unchanged) {
00430     buffer[0] |= 0x20;
00431   }
00432   if (pioa == Conducting) {
00433     buffer[0] |= 0x10;
00434   }
00435   if (piob != Unchanged) {
00436     buffer[0] |= 0x80;
00437   }
00438   if (piob == Conducting) {
00439     buffer[0] |= 0x40;
00440   }
00441   uint_least8_t * bufferIt =
00442       copy(signature.r.begin(), signature.r.end(), buffer + 1);
00443   copy(signature.s.begin(), signature.s.end(), bufferIt);
00444   Result<void> result = writeCommand(0x59, buffer);
00445   if (!result) {
00446     return result;
00447   }
00448   sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs +
00449         ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0));
00450   result = readFixedLengthResponse(make_span(buffer, 1));
00451   if (!result) {
00452     return result;
00453   }
00454   result = convertResultByte(buffer[0]);
00455   return result;
00456 }
00457 
00458 Result<void>
00459 DS28C36::authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum,
00460                                     int csOffset,
00461                                     Signature::const_span signature) {
00462   if (((keyNum != KeyNumA) && (keyNum != KeyNumB)) || (csOffset < 0) ||
00463       (csOffset > 31)) {
00464     return InvalidParameterError;
00465   }
00466 
00467   uint_least8_t buffer[1 + 2 * Scalar::size];
00468   buffer[0] = (csOffset << 3) | (keyNum << 2);
00469   if (ecdh) {
00470     buffer[0] |= 0x02;
00471   }
00472   if (authWrites) {
00473     buffer[0] |= 0x01;
00474   }
00475   uint_least8_t * bufferIt =
00476       copy(signature.r.begin(), signature.r.end(), buffer + 1);
00477   copy(signature.s.begin(), signature.s.end(), bufferIt);
00478   Result<void> result = writeCommand(0xA8, buffer);
00479   if (!result) {
00480     return result;
00481   }
00482   sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs);
00483   result = readFixedLengthResponse(make_span(buffer, 1));
00484   if (!result) {
00485     return result;
00486   }
00487   result = convertResultByte(buffer[0]);
00488   return result;
00489 }
00490 
00491 Result<void> DS28C36::authenticatedEcdsaWriteMemory(int pageNum,
00492                                                     Page::const_span page) {
00493   if (pageNum < 0 || pageNum >= memoryPages) {
00494     return InvalidParameterError;
00495   }
00496 
00497   uint_least8_t buffer[1 + Page::size];
00498   buffer[0] = pageNum;
00499   copy(page.begin(), page.end(), buffer + 1);
00500   Result<void> result = writeCommand(0x89, buffer);
00501   if (!result) {
00502     return result;
00503   }
00504   sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs +
00505         sha256ComputationTimeMs);
00506   result = readFixedLengthResponse(make_span(buffer, 1));
00507   if (!result) {
00508     return result;
00509   }
00510   result = convertResultByte(buffer[0]);
00511   return result;
00512 }
00513 
00514 Result<void> DS28C36::writeCommand(uint_least8_t command,
00515                                    span<const uint_least8_t> parameters) const {
00516   Result<void> result = master->start(address_);
00517   if (!result) {
00518     master->stop();
00519     return result;
00520   }
00521   result = master->writeByte(command);
00522   if (!result) {
00523     master->stop();
00524     return result;
00525   }
00526   if (!parameters.empty()) {
00527     result = master->writeByte(static_cast<uint_least8_t>(parameters.size()));
00528     if (!result) {
00529       master->stop();
00530       return result;
00531     }
00532     result = master->writeBlock(parameters);
00533     if (!result) {
00534       master->stop();
00535       return result;
00536     }
00537   }
00538   result = master->stop();
00539   return result;
00540 }
00541 
00542 Result<span<uint_least8_t>::index_type>
00543 DS28C36::readVariableLengthResponse(span<uint_least8_t> response) const {
00544   Result<void> result = master->start(address_ | 1);
00545   if (!result) {
00546     master->stop();
00547     return result.error();
00548   }
00549   uint_least8_t length;
00550   if (const Result<uint_least8_t> result = master->readByte(I2CMaster::Ack)) {
00551     length = result.value();
00552   } else {
00553     master->stop();
00554     return result.error();
00555   }
00556   if (length > response.size()) {
00557     master->stop();
00558     return InvalidResponseError;
00559   }
00560   if (length > 0) {
00561     result = master->readBlock(response.first(length), I2CMaster::Nack);
00562     if (!result) {
00563       master->stop();
00564       return result.error();
00565     }
00566   }
00567   result = master->stop();
00568   if (!result) {
00569     return result.error();
00570   }
00571   return length;
00572 }
00573 
00574 Result<void>
00575 DS28C36::readFixedLengthResponse(span<uint_least8_t> response) const {
00576   span<uint_least8_t>::index_type responseLength;
00577   TRY_VALUE(responseLength, readVariableLengthResponse(response));
00578   return (responseLength == response.size()) ? makeResult(none)
00579                                              : InvalidResponseError;
00580 }
00581 
00582 const error_category & DS28C36::errorCategory() {
00583   static class : public error_category {
00584   public:
00585     virtual const char * name() const {
00586       return "MaximInterfaceDevices.DS28C36_DS2476";
00587     }
00588 
00589     virtual std::string message(int condition) const {
00590       switch (condition) {
00591       case ProtectionError:
00592         return "Protection Error";
00593 
00594       case InvalidParameterError:
00595         return "Invalid Parameter Error";
00596 
00597       case InvalidSequenceError:
00598         return "Invalid Sequence Error";
00599 
00600       case InvalidEcdsaInputOrResultError:
00601         return "Invalid ECDSA Input or Result Error";
00602 
00603       case AuthenticationError:
00604         return "Authentication Error";
00605 
00606       case InvalidResponseError:
00607         return "Invalid Response Error";
00608       }
00609       return defaultErrorMessage(condition);
00610     }
00611   } instance;
00612   return instance;
00613 }
00614 
00615 Result<Signature::array> DS2476::generateEcdsaSignature(KeyNum keyNum) const {
00616   if (keyNum == KeyNumS) {
00617     return InvalidParameterError;
00618   }
00619 
00620   const uint_least8_t parameter = keyNum;
00621   Result<void> result = writeCommand(0x1E, make_span(&parameter, 1));
00622   if (!result) {
00623     return result.error();
00624   }
00625   sleep(generateEcdsaSignatureTimeMs);
00626   uint_least8_t response[1 + 2 * Scalar::size];
00627   result = readFixedLengthResponse(response);
00628   if (!result) {
00629     return result.error();
00630   }
00631   result = convertResultByte(response[0]);
00632   if (!result) {
00633     return result.error();
00634   }
00635   Signature::array signature;
00636   const uint_least8_t * begin = response + 1;
00637   const uint_least8_t * end = begin + signature.s.size();
00638   copy(begin, end, signature.s.begin());
00639   begin = end;
00640   end = begin + signature.r.size();
00641   copy(begin, end, signature.r.begin());
00642   return signature;
00643 }
00644 
00645 Result<void> DS2476::computeSha2UniqueSecret(SecretNum msecretNum) {
00646   uint_least8_t buffer = msecretNum << 4;
00647   Result<void> result = writeCommand(0x55, make_span(&buffer, 1));
00648   if (!result) {
00649     return result;
00650   }
00651   sleep(sha256ComputationTimeMs);
00652   result = readFixedLengthResponse(make_span(&buffer, 1));
00653   if (!result) {
00654     return result;
00655   }
00656   result = convertResultByte(buffer);
00657   return result;
00658 }
00659 
00660 Result<DS2476::Page::array> DS2476::computeSha2Hmac() const {
00661   Result<void> result = writeCommand(0x2D);
00662   if (!result) {
00663     return result.error();
00664   }
00665   sleep(sha256ComputationTimeMs);
00666   array<uint_least8_t, 1 + Page::size> response;
00667   result = readFixedLengthResponse(response);
00668   if (!result) {
00669     return result.error();
00670   }
00671   result = convertResultByte(response[0]);
00672   if (!result) {
00673     return result.error();
00674   }
00675   Page::array hmac;
00676   copy(response.begin() + 1, response.end(), hmac.begin());
00677   return hmac;
00678 }
00679 
00680 Result<void> computeMultiblockHash(DS28C36 & ds28c36,
00681                                    span<const uint_least8_t> data) {
00682   span<const uint_least8_t>::index_type dataIdx = 0;
00683   while (dataIdx < data.size()) {
00684     const span<const uint_least8_t>::index_type remainingSize =
00685         data.size() - dataIdx;
00686     const span<const uint_least8_t>::index_type chunkSize =
00687         std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
00688     TRY(ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
00689                                       data.subspan(dataIdx, chunkSize)));
00690     dataIdx += chunkSize;
00691   }
00692   return none;
00693 }
00694 
00695 Result<void> verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
00696                                   span<const uint_least8_t> data,
00697                                   Signature::const_span signature,
00698                                   DS28C36::PioState pioa,
00699                                   DS28C36::PioState piob) {
00700   Result<void> result = computeMultiblockHash(ds28c36, data);
00701   if (result) {
00702     result = ds28c36.verifyEcdsaSignature(publicKey, DS28C36::THASH, signature,
00703                                           pioa, piob);
00704   }
00705   return result;
00706 }
00707 
00708 Result<void> verifyEcdsaSignature(DS28C36 & ds28c36,
00709                                   PublicKey::const_span publicKey,
00710                                   span<const uint_least8_t> data,
00711                                   Signature::const_span signature,
00712                                   DS28C36::PioState pioa,
00713                                   DS28C36::PioState piob) {
00714   Result<void> result =
00715       ds28c36.writeMemory(DS28C36::publicKeySxPage, publicKey.x);
00716   if (!result) {
00717     return result;
00718   }
00719   result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y);
00720   if (!result) {
00721     return result;
00722   }
00723   result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, signature,
00724                                 pioa, piob);
00725   return result;
00726 }
00727 
00728 Result<void> enableCoprocessor(DS2476 & ds2476) {
00729   DS2476::Page::array page;
00730   TRY_VALUE(page, ds2476.readMemory(DS2476::gpioControlPage));
00731   DS2476::GpioControl gpioControl(page);
00732   if (!gpioControl.pioaConducting()) {
00733     gpioControl.setPioaConducting(true);
00734     TRY(ds2476.writeMemory(DS2476::gpioControlPage, page));
00735   }
00736   return none;
00737 }
00738 
00739 Result<void> enableRomId(DS2476 & ds2476) {
00740   DS2476::Page::array page;
00741   TRY_VALUE(page, ds2476.readMemory(DS2476::romOptionsPage));
00742   DS2476::RomOptions romOptions(page);
00743   if (!romOptions.romBlockDisable()) {
00744     romOptions.setRomBlockDisable(true);
00745     TRY(ds2476.writeMemory(DS2476::romOptionsPage, page));
00746   }
00747   return none;
00748 }
00749 
00750 static void setAnonymous(RomId::span romId) {
00751   std::fill(romId.begin(), romId.end(), 0xFF);
00752 }
00753 
00754 DS28C36::PageAuthenticationData &
00755 DS28C36::PageAuthenticationData::setAnonymousRomId() {
00756   setAnonymous(romId());
00757   return *this;
00758 }
00759 
00760 DS28C36::EncryptionHmacData & DS28C36::EncryptionHmacData::setAnonymousRomId() {
00761   setAnonymous(romId());
00762   return *this;
00763 }
00764 
00765 } // namespace MaximInterfaceDevices