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.hpp Source File

DS28C36_DS2476.hpp

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 #ifndef MaximInterfaceDevices_DS28C36_DS2476_hpp
00034 #define MaximInterfaceDevices_DS28C36_DS2476_hpp
00035 
00036 #include <stdint.h>
00037 #include <utility>
00038 #include <vector>
00039 #include <MaximInterfaceCore/Algorithm.hpp>
00040 #include <MaximInterfaceCore/array_span.hpp>
00041 #include <MaximInterfaceCore/Ecc256.hpp>
00042 #include <MaximInterfaceCore/FlagSet.hpp>
00043 #include <MaximInterfaceCore/I2CMaster.hpp>
00044 #include <MaximInterfaceCore/ManId.hpp>
00045 #include <MaximInterfaceCore/RomId.hpp>
00046 #include <MaximInterfaceCore/Sleep.hpp>
00047 #include <MaximInterfaceCore/system_error.hpp>
00048 #include "Config.hpp"
00049 
00050 namespace MaximInterfaceDevices {
00051 
00052 /// Interface to the DS28C36 authenticator.
00053 class DS28C36 {
00054 public:
00055   /// Device command results.
00056   enum ErrorValue {
00057     ProtectionError = 0x55,
00058     InvalidParameterError = 0x77,
00059     InvalidSequenceError = 0x33,
00060     InvalidEcdsaInputOrResultError = 0x22,
00061     AuthenticationError = 0x100,
00062     InvalidResponseError = 0x101 ///< Response does not match expected format.
00063   };
00064 
00065   /// @name Device memory pages
00066   /// @{
00067 
00068   static const int publicKeyAxPage = 16;
00069   static const int publicKeyAyPage = 17;
00070   static const int publicKeyBxPage = 18;
00071   static const int publicKeyByPage = 19;
00072   static const int publicKeyCxPage = 20;
00073   static const int publicKeyCyPage = 21;
00074   static const int privateKeyAPage = 22;
00075   static const int privateKeyBPage = 23;
00076   static const int privateKeyCPage = 24;
00077   static const int secretAPage = 25;
00078   static const int secretBPage = 26;
00079   static const int decrementCounterPage = 27;
00080   static const int romOptionsPage = 28;
00081   static const int gpioControlPage = 29;
00082   static const int publicKeySxPage = 30;
00083   static const int publicKeySyPage = 31;
00084 
00085   /// @}
00086 
00087   /// Number of memory pages on the device.
00088   static const int memoryPages = 32;
00089 
00090   /// Available keys for ECDSA operations.
00091   enum KeyNum { KeyNumA = 0, KeyNumB = 1, KeyNumC = 2, KeyNumS = 3 };
00092 
00093   /// Available secrets for HMAC operations.
00094   enum SecretNum { SecretNumA = 0, SecretNumB = 1, SecretNumS = 2 };
00095 
00096   /// Data hash type when verifying an ECDSA signature.
00097   enum HashType {
00098     HashInBuffer = 0, ///< Hash is loaded in the buffer.
00099     DataInBuffer = 1, ///< Compute hash from data loaded in the buffer.
00100     THASH = 2         ///< Use THASH from Compute Multiblock Hash command.
00101   };
00102 
00103   /// Available PIO states when verifying an ECDSA signature.
00104   enum PioState { Unchanged, Conducting, HighImpedance };
00105 
00106   /// Holds a device memory page.
00107   typedef Core::array_span<uint_least8_t, 32> Page;
00108 
00109   // Format page authentication input data.
00110   class PageAuthenticationData;
00111 
00112   // Format authenticated write input data.
00113   class WriteAuthenticationData;
00114 
00115   // Format compute secret input data.
00116   class ComputeSecretData;
00117 
00118   // Format encryption or decryption HMAC input data.
00119   class EncryptionHmacData;
00120 
00121   // Access fields in the ROM Options page.
00122   class RomOptions;
00123 
00124   // Access fields in the GPIO Control page.
00125   class GpioControl;
00126 
00127   /// Page protection types.
00128   enum PageProtectionType {
00129     RP = 0x01,   ///< Read protection.
00130     WP = 0x02,   ///< Write protection.
00131     EM = 0x04,   ///< EPROM emulation mode.
00132     APH = 0x08,  ///< Authentication write protection HMAC.
00133     EPH = 0x10,  ///< Encryption and authenticated write protection HMAC.
00134     AUTH = 0x20, ///< Public Key C is set to authority public key.
00135     ECH = 0x40,  ///< Encrypted read and write using shared key from ECDH.
00136     ECW = 0x80   ///< Authentication write protection ECDSA.
00137   };
00138   typedef Core::FlagSet<PageProtectionType, 8> PageProtection;
00139 
00140   /// Challenge for an encrypted device memory page.
00141   typedef Core::array_span<uint_least8_t, 8> EncryptionChallenge;
00142 
00143   DS28C36(Core::Sleep & sleep, Core::I2CMaster & master,
00144           uint_least8_t address = 0x36)
00145       : sleep_(&sleep), master(&master), address_(address & 0xFE) {}
00146 
00147   void setSleep(Core::Sleep & sleep) { sleep_ = &sleep; }
00148 
00149   void setMaster(Core::I2CMaster & master) { this->master = &master; }
00150 
00151   uint_least8_t address() const { return address_; }
00152 
00153   void setAddress(uint_least8_t address) { address_ = address & 0xFE; }
00154 
00155   /// @brief Write memory with no protection.
00156   /// @param pageNum Number of page to write.
00157   /// @param page Data to write.
00158   MaximInterfaceDevices_EXPORT Core::Result<void>
00159   writeMemory(int pageNum, Page::const_span page);
00160 
00161   /// @brief Read memory with no protection.
00162   /// @param pageNum Number of page to read.
00163   /// @returns Data that was read.
00164   MaximInterfaceDevices_EXPORT Core::Result<Page::array>
00165   readMemory(int pageNum) const;
00166 
00167   /// @brief Write the temporary buffer.
00168   /// @param data Data to write.
00169   MaximInterfaceDevices_EXPORT Core::Result<void>
00170   writeBuffer(Core::span<const uint_least8_t> data);
00171 
00172   /// @brief Read the temporary buffer.
00173   /// @returns Data that was read.
00174   MaximInterfaceDevices_EXPORT Core::Result<std::vector<uint_least8_t> >
00175   readBuffer() const;
00176 
00177   /// @brief Read the protection settings of a page.
00178   /// @param pageNum Number of page to read.
00179   /// @returns Protection that was read.
00180   MaximInterfaceDevices_EXPORT Core::Result<PageProtection>
00181   readPageProtection(int pageNum) const;
00182 
00183   /// @brief Set the protection settings of a page.
00184   /// @param pageNum Number of page to write.
00185   /// @param protection Protection to write.
00186   MaximInterfaceDevices_EXPORT Core::Result<void>
00187   setPageProtection(int pageNum, const PageProtection & protection);
00188 
00189   /// Decrement the decrement-only counter.
00190   MaximInterfaceDevices_EXPORT Core::Result<void> decrementCounter();
00191 
00192   /// @brief Read a block of random data from the RNG.
00193   /// @param[out] data Random data from RNG with length from 1 to 64.
00194   MaximInterfaceDevices_EXPORT Core::Result<void>
00195   readRng(Core::span<uint_least8_t> data) const;
00196 
00197   /// @brief Read memory with encryption.
00198   /// @param pageNum Number of page to read from.
00199   /// @param secretNum Secret to use for encryption.
00200   /// @returns Encryption challenge and encrypted page data that was read.
00201   MaximInterfaceDevices_EXPORT
00202       Core::Result<std::pair<EncryptionChallenge::array, Page::array> >
00203       encryptedReadMemory(int pageNum, SecretNum secretNum) const;
00204 
00205   /// @brief Compute and read page authentication with ECDSA.
00206   /// @param pageNum Number of page to authenticate.
00207   /// @param keyNum
00208   /// Private key to use for authentication.
00209   /// Key S cannot be used with this command.
00210   /// @returns Computed page signature.
00211   MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array>
00212   computeAndReadPageAuthentication(int pageNum, KeyNum keyNum) const;
00213 
00214   /// @brief Compute and read page authentication with HMAC.
00215   /// @param pageNum Number of page to authenticate.
00216   /// @param secretNum Secret to use for authentication.
00217   /// @returns Computed page HMAC.
00218   MaximInterfaceDevices_EXPORT Core::Result<Page::array>
00219   computeAndReadPageAuthentication(int pageNum, SecretNum secretNum) const;
00220 
00221   /// @brief Write with SHA2 authentication.
00222   /// @param pageNum Number of page to write.
00223   /// @param secretNum Secret to use for authentication.
00224   /// @param page Data to write.
00225   MaximInterfaceDevices_EXPORT Core::Result<void>
00226   authenticatedSha2WriteMemory(int pageNum, SecretNum secretNum,
00227                                Page::const_span page);
00228 
00229   /// @brief Compute SHA2 secret and optionally lock.
00230   /// @param pageNum Number of page to use in computation.
00231   /// @param msecretNum Master secret to use in computation.
00232   /// @param dsecretNum Destination secret to receive the computation result.
00233   /// @param writeProtectEnable
00234   /// True to lock the destination secret against further writes.
00235   MaximInterfaceDevices_EXPORT Core::Result<void>
00236   computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
00237                            SecretNum dsecretNum, bool writeProtectEnable);
00238 
00239   /// @brief Generate a new ECDSA key pair.
00240   /// @param keyNum Key to generate. Key S cannot be used with this command.
00241   /// @param writeProtectEnable True to lock the key against further writes.
00242   MaximInterfaceDevices_EXPORT Core::Result<void>
00243   generateEcc256KeyPair(KeyNum keyNum, bool writeProtectEnable);
00244 
00245   /// @brief Compute a hash over multiple blocks.
00246   /// @param firstBlock True if this is the first block being hashed.
00247   /// @param lastBlock True if this is the last block being hashed.
00248   /// @param data
00249   /// Data block to hash. Should be 64 bytes unless this is the last block.
00250   MaximInterfaceDevices_EXPORT Core::Result<void>
00251   computeMultiblockHash(bool firstBlock, bool lastBlock,
00252                         Core::span<const uint_least8_t> data);
00253 
00254   /// @brief Verify ECDSA signature.
00255   /// @param keyNum Public key to use for verification.
00256   /// @param hashType Source of the data hash input.
00257   /// @param signature Signature to verify.
00258   /// @param pioa New state of PIOA if verification successful.
00259   /// @param piob New state of PIOB if verification successful.
00260   MaximInterfaceDevices_EXPORT Core::Result<void>
00261   verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
00262                        Core::Ecc256::Signature::const_span signature,
00263                        PioState pioa = Unchanged, PioState piob = Unchanged);
00264 
00265   /// @brief
00266   /// Authenticate a public key for authenticated writes or encrypted reads
00267   /// with ECDH.
00268   /// @param authWrites True to select authentication for writes.
00269   /// @param ecdh True to select ECDH key exchange.
00270   /// @param keyNum
00271   /// Private key to use for ECDH key exchange. Key A or B can be selected.
00272   /// @param csOffset Certificate customization field ending offset in buffer.
00273   /// @param signature Signature to use for authentication of public key S.
00274   MaximInterfaceDevices_EXPORT Core::Result<void>
00275   authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum,
00276                              int csOffset,
00277                              Core::Ecc256::Signature::const_span signature);
00278 
00279   /// @brief Write with ECDSA authentication.
00280   /// @param pageNum Number of page to write.
00281   /// @param page Data to write.
00282   MaximInterfaceDevices_EXPORT Core::Result<void>
00283   authenticatedEcdsaWriteMemory(int pageNum, Page::const_span page);
00284 
00285   MaximInterfaceDevices_EXPORT static const Core::error_category &
00286   errorCategory();
00287 
00288 protected:
00289   // Timing constants.
00290   static const int generateEcdsaSignatureTimeMs = 50;
00291   static const int generateEccKeyPairTimeMs = 100;
00292   static const int verifyEsdsaSignatureOrComputeEcdhTimeMs = 150;
00293   static const int sha256ComputationTimeMs = 3;
00294   static const int readMemoryTimeMs = /*1*/ 2;
00295   static const int writeMemoryTimeMs = 15;
00296 
00297   Core::Result<void>
00298   writeCommand(uint_least8_t command,
00299                Core::span<const uint_least8_t> parameters) const;
00300 
00301   Core::Result<void> writeCommand(uint_least8_t command) const {
00302     return writeCommand(command, Core::span<const uint_least8_t>());
00303   }
00304 
00305   Core::Result<Core::span<uint_least8_t>::index_type>
00306   readVariableLengthResponse(Core::span<uint_least8_t> response) const;
00307 
00308   Core::Result<void>
00309   readFixedLengthResponse(Core::span<uint_least8_t> response) const;
00310 
00311   void sleep(int ms) const { sleep_->invoke(ms); }
00312 
00313 private:
00314   enum AuthType {
00315     HmacWithSecretA = 0,
00316     HmacWithSecretB = 1,
00317     HmacWithSecretS = 2,
00318     EcdsaWithKeyA = 3,
00319     EcdsaWithKeyB = 4,
00320     EcdsaWithKeyC = 5
00321   };
00322 
00323   Core::Result<void> computeAndReadPageAuthentication(int pageNum,
00324                                                       AuthType authType) const;
00325 
00326   const Core::Sleep * sleep_;
00327   Core::I2CMaster * master;
00328   uint_least8_t address_;
00329 };
00330 
00331 /// Interface to the DS2476 coprocessor.
00332 class DS2476 : public DS28C36 {
00333 public:
00334   DS2476(Core::Sleep & sleep, Core::I2CMaster & master,
00335          uint_least8_t address = 0x76)
00336       : DS28C36(sleep, master, address) {}
00337 
00338   /// @brief Generate ECDSA signature.
00339   /// @param keyNum
00340   /// Private key to use to create signature.
00341   /// Key S cannot be used with this command.
00342   /// @returns Computed signature.
00343   MaximInterfaceDevices_EXPORT Core::Result<Core::Ecc256::Signature::array>
00344   generateEcdsaSignature(KeyNum keyNum) const;
00345 
00346   /// @brief Compute unique SHA2 secret.
00347   /// @param msecretNum Master secret to use in computation.
00348   MaximInterfaceDevices_EXPORT Core::Result<void>
00349   computeSha2UniqueSecret(SecretNum msecretNum);
00350 
00351   /// @brief Compute SHA2 HMAC.
00352   /// @returns Computed HMAC.
00353   MaximInterfaceDevices_EXPORT Core::Result<Page::array>
00354   computeSha2Hmac() const;
00355 };
00356 
00357 } // namespace MaximInterfaceDevices
00358 namespace MaximInterfaceCore {
00359 
00360 template <>
00361 struct is_error_code_enum<MaximInterfaceDevices::DS28C36::ErrorValue>
00362     : true_type {};
00363 
00364 } // namespace MaximInterfaceCore
00365 namespace MaximInterfaceDevices {
00366 
00367 inline Core::error_code make_error_code(DS28C36::ErrorValue e) {
00368   return Core::error_code(e, DS28C36::errorCategory());
00369 }
00370 
00371 /// @brief
00372 /// Hash arbitrary length data with successive Compute Multiblock Hash commands.
00373 /// @param ds28c36 Device for computation.
00374 /// @param data Data to hash.
00375 MaximInterfaceDevices_EXPORT Core::Result<void>
00376 computeMultiblockHash(DS28C36 & ds28c36, Core::span<const uint_least8_t> data);
00377 
00378 /// @brief Verify ECDSA signature.
00379 /// @param ds28c36 Device for computation.
00380 /// @param publicKey Public key to use for verification.
00381 /// @param data Data to verify.
00382 /// @param signature Signature to verify.
00383 /// @param pioa New state of PIOA if verification successful.
00384 /// @param piob New state of PIOB if verification successful.
00385 MaximInterfaceDevices_EXPORT Core::Result<void>
00386 verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
00387                      Core::span<const uint_least8_t> data,
00388                      Core::Ecc256::Signature::const_span signature,
00389                      DS28C36::PioState pioa = DS28C36::Unchanged,
00390                      DS28C36::PioState piob = DS28C36::Unchanged);
00391 
00392 /// @brief Verify ECDSA signature.
00393 /// @param ds28c36 Device for computation.
00394 /// @param publicKey
00395 /// Public key to use for verification which is loaded into Public Key S.
00396 /// @param data Data to verify.
00397 /// @param signature Signature to verify.
00398 /// @param pioa New state of PIOA if verification successful.
00399 /// @param piob New state of PIOB if verification successful.
00400 MaximInterfaceDevices_EXPORT Core::Result<void>
00401 verifyEcdsaSignature(DS28C36 & ds28c36,
00402                      Core::Ecc256::PublicKey::const_span publicKey,
00403                      Core::span<const uint_least8_t> data,
00404                      Core::Ecc256::Signature::const_span signature,
00405                      DS28C36::PioState pioa = DS28C36::Unchanged,
00406                      DS28C36::PioState piob = DS28C36::Unchanged);
00407 
00408 /// @brief
00409 /// Enable coprocessor functionality on the DS2476 by writing to the
00410 /// GPIO Control page.
00411 MaximInterfaceDevices_EXPORT Core::Result<void>
00412 enableCoprocessor(DS2476 & ds2476);
00413 
00414 /// @brief
00415 /// Disable blocking of the ROM ID on the DS2476 by writing to the
00416 /// ROM Options page.
00417 MaximInterfaceDevices_EXPORT Core::Result<void> enableRomId(DS2476 & ds2476);
00418 
00419 /// Format page authentication input data.
00420 class DS28C36::PageAuthenticationData {
00421 public:
00422   typedef Core::array_span<uint_least8_t, Core::RomId::size + 2 * Page::size +
00423                                               1 + Core::ManId::size>
00424       Result;
00425 
00426   PageAuthenticationData() : result_() {}
00427 
00428   /// Formatted data result.
00429   Result::const_span result() const { return result_; }
00430 
00431   /// @name ROM ID
00432   /// @brief 1-Wire ROM ID of the device.
00433   /// @{
00434 
00435   /// Get mutable ROM ID.
00436   Core::RomId::span romId() {
00437     return make_span(result_).subspan<romIdIdx, Core::RomId::size>();
00438   }
00439 
00440   /// Get immutable ROM ID.
00441   Core::RomId::const_span romId() const {
00442     return const_cast<PageAuthenticationData &>(*this).romId();
00443   }
00444 
00445   /// Set ROM ID.
00446   PageAuthenticationData & setRomId(Core::RomId::const_span romId) {
00447     copy(romId, this->romId());
00448     return *this;
00449   }
00450 
00451   /// Set ROM ID for use in anonymous mode.
00452   MaximInterfaceDevices_EXPORT PageAuthenticationData & setAnonymousRomId();
00453 
00454   /// @}
00455 
00456   /// @name Page
00457   /// @brief Data from a device memory page.
00458   /// @{
00459 
00460   /// Get mutable page.
00461   Page::span page() {
00462     return make_span(result_).subspan<pageIdx, Page::size>();
00463   }
00464 
00465   /// Get immutable page.
00466   Page::const_span page() const {
00467     return const_cast<PageAuthenticationData &>(*this).page();
00468   }
00469 
00470   /// Set page.
00471   PageAuthenticationData & setPage(Page::const_span page) {
00472     copy(page, this->page());
00473     return *this;
00474   }
00475 
00476   /// @}
00477 
00478   /// @name Challenge
00479   /// @brief Random challenge used to prevent replay attacks.
00480   /// @{
00481 
00482   /// Get mutable Challenge.
00483   Page::span challenge() {
00484     return make_span(result_).subspan<challengeIdx, Page::size>();
00485   }
00486 
00487   /// Get immutable Challenge.
00488   Page::const_span challenge() const {
00489     return const_cast<PageAuthenticationData &>(*this).challenge();
00490   }
00491 
00492   /// Set Challenge.
00493   PageAuthenticationData & setChallenge(Page::const_span challenge) {
00494     copy(challenge, this->challenge());
00495     return *this;
00496   }
00497 
00498   /// @}
00499 
00500   /// @name Page number
00501   /// @brief Number of the page to use data from.
00502   /// @{
00503 
00504   /// Get page number.
00505   int pageNum() const { return result_[pageNumIdx]; }
00506 
00507   /// Set page number.
00508   PageAuthenticationData & setPageNum(int pageNum) {
00509     result_[pageNumIdx] = pageNum;
00510     return *this;
00511   }
00512 
00513   /// @}
00514 
00515   /// @name MAN ID
00516   /// @brief Manufacturer ID of the device.
00517   /// @{
00518 
00519   /// Get mutable MAN ID.
00520   Core::ManId::span manId() {
00521     return make_span(result_).subspan<manIdIdx, Core::ManId::size>();
00522   }
00523 
00524   /// Get immutable MAN ID.
00525   Core::ManId::const_span manId() const {
00526     return const_cast<PageAuthenticationData &>(*this).manId();
00527   }
00528 
00529   /// Set MAN ID.
00530   PageAuthenticationData & setManId(Core::ManId::const_span manId) {
00531     copy(manId, this->manId());
00532     return *this;
00533   }
00534 
00535   /// @}
00536 
00537 private:
00538   static const size_t romIdIdx = 0;
00539   static const size_t pageIdx = romIdIdx + Core::RomId::size;
00540   static const size_t challengeIdx = pageIdx + Page::size;
00541   static const size_t pageNumIdx = challengeIdx + Page::size;
00542   static const size_t manIdIdx = pageNumIdx + 1;
00543 
00544   Result::array result_;
00545 };
00546 
00547 /// Format authenticated write input data.
00548 class DS28C36::WriteAuthenticationData {
00549 public:
00550   typedef PageAuthenticationData::Result Result;
00551 
00552   WriteAuthenticationData() : data() {}
00553 
00554   /// Formatted data result.
00555   Result::const_span result() const { return data.result(); }
00556 
00557   /// @name ROM ID
00558   /// @brief 1-Wire ROM ID of the device.
00559   /// @{
00560 
00561   /// Get mutable ROM ID.
00562   Core::RomId::span romId() { return data.romId(); }
00563 
00564   /// Get immutable ROM ID.
00565   Core::RomId::const_span romId() const { return data.romId(); }
00566 
00567   /// Set ROM ID.
00568   WriteAuthenticationData & setRomId(Core::RomId::const_span romId) {
00569     data.setRomId(romId);
00570     return *this;
00571   }
00572 
00573   /// Set ROM ID for use in anonymous mode.
00574   WriteAuthenticationData & setAnonymousRomId() {
00575     data.setAnonymousRomId();
00576     return *this;
00577   }
00578 
00579   /// @}
00580 
00581   /// @name Old page
00582   /// @brief Existing data contained in the page.
00583   /// @{
00584 
00585   /// Get mutable old page.
00586   Page::span oldPage() { return data.page(); }
00587 
00588   /// Get immutable old page.
00589   Page::const_span oldPage() const { return data.page(); }
00590 
00591   /// Set old page.
00592   WriteAuthenticationData & setOldPage(Page::const_span oldPage) {
00593     data.setPage(oldPage);
00594     return *this;
00595   }
00596 
00597   /// @}
00598 
00599   /// @name New page
00600   /// @brief New data to write to the page.
00601   /// @{
00602 
00603   /// Get mutable new page.
00604   Page::span newPage() { return data.challenge(); }
00605 
00606   /// Get immutable new page.
00607   Page::const_span newPage() const { return data.challenge(); }
00608 
00609   /// Set new page.
00610   WriteAuthenticationData & setNewPage(Page::const_span newPage) {
00611     data.setChallenge(newPage);
00612     return *this;
00613   }
00614 
00615   /// @}
00616 
00617   /// @name Page number
00618   /// @brief Page number for write operation.
00619   /// @{
00620 
00621   /// Get page number.
00622   int pageNum() const { return data.pageNum(); }
00623 
00624   /// Set page number.
00625   WriteAuthenticationData & setPageNum(int pageNum) {
00626     data.setPageNum(pageNum);
00627     return *this;
00628   }
00629 
00630   /// @}
00631 
00632   /// @name MAN ID
00633   /// @brief Manufacturer ID of the device.
00634   /// @{
00635 
00636   /// Get mutable MAN ID.
00637   Core::ManId::span manId() { return data.manId(); }
00638 
00639   /// Get immutable MAN ID.
00640   Core::ManId::const_span manId() const { return data.manId(); }
00641 
00642   /// Set MAN ID.
00643   WriteAuthenticationData & setManId(Core::ManId::const_span manId) {
00644     data.setManId(manId);
00645     return *this;
00646   }
00647 
00648   /// @}
00649 
00650 private:
00651   PageAuthenticationData data;
00652 };
00653 
00654 /// Format compute secret input data.
00655 class DS28C36::ComputeSecretData {
00656 public:
00657   typedef PageAuthenticationData::Result Result;
00658 
00659   ComputeSecretData() : data() {}
00660 
00661   /// Formatted data result.
00662   Result::const_span result() const { return data.result(); }
00663 
00664   /// @name ROM ID
00665   /// @brief 1-Wire ROM ID of the device.
00666   /// @{
00667 
00668   /// Get mutable ROM ID.
00669   Core::RomId::span romId() { return data.romId(); }
00670 
00671   /// Get immutable ROM ID.
00672   Core::RomId::const_span romId() const { return data.romId(); }
00673 
00674   /// Set ROM ID.
00675   ComputeSecretData & setRomId(Core::RomId::const_span romId) {
00676     data.setRomId(romId);
00677     return *this;
00678   }
00679 
00680   /// @}
00681 
00682   /// @name Binding Data
00683   /// @brief Binding Data contained in the selected page.
00684   /// @{
00685 
00686   /// Get mutable Binding Data.
00687   Page::span bindingData() { return data.page(); }
00688 
00689   /// Get immutable Binding Data.
00690   Page::const_span bindingData() const { return data.page(); }
00691 
00692   /// Set Binding Data.
00693   ComputeSecretData & setBindingData(Page::const_span bindingData) {
00694     data.setPage(bindingData);
00695     return *this;
00696   }
00697 
00698   /// @}
00699 
00700   /// @name Partial Secret
00701   /// @brief Partial Secret used for customization.
00702   /// @{
00703 
00704   /// Get mutable Partial Secret.
00705   Page::span partialSecret() { return data.challenge(); }
00706 
00707   /// Get immutable Partial Secret.
00708   Page::const_span partialSecret() const { return data.challenge(); }
00709 
00710   /// Set Partial Secret.
00711   ComputeSecretData & setPartialSecret(Page::const_span partialSecret) {
00712     data.setChallenge(partialSecret);
00713     return *this;
00714   }
00715 
00716   /// @}
00717 
00718   /// @name Page number
00719   /// @brief Page number for Binding Data.
00720   /// @{
00721 
00722   /// Get page number.
00723   int pageNum() const { return data.pageNum(); }
00724 
00725   /// Set page number.
00726   ComputeSecretData & setPageNum(int pageNum) {
00727     data.setPageNum(pageNum);
00728     return *this;
00729   }
00730 
00731   /// @}
00732 
00733   /// @name MAN ID
00734   /// @brief Manufacturer ID of the device.
00735   /// @{
00736 
00737   /// Get mutable MAN ID.
00738   Core::ManId::span manId() { return data.manId(); }
00739 
00740   /// Get immutable MAN ID.
00741   Core::ManId::const_span manId() const { return data.manId(); }
00742 
00743   /// Set MAN ID.
00744   ComputeSecretData & setManId(Core::ManId::const_span manId) {
00745     data.setManId(manId);
00746     return *this;
00747   }
00748 
00749   /// @}
00750 
00751 private:
00752   PageAuthenticationData data;
00753 };
00754 
00755 /// Format encryption or decryption HMAC input data.
00756 class DS28C36::EncryptionHmacData {
00757 public:
00758   typedef Core::array_span<uint_least8_t, EncryptionChallenge::size +
00759                                               Core::RomId::size + 1 +
00760                                               Core::ManId::size>
00761       Result;
00762 
00763   EncryptionHmacData() : result_() {}
00764 
00765   /// Formatted data result.
00766   Result::const_span result() const { return result_; }
00767 
00768   /// @name Encryption Challenge
00769   /// @brief Random challenge used to prevent replay attacks.
00770   /// @{
00771 
00772   /// Get mutable Encryption Challenge.
00773   EncryptionChallenge::span encryptionChallenge() {
00774     return make_span(result_)
00775         .subspan<encryptionChallengeIdx, EncryptionChallenge::size>();
00776   }
00777 
00778   /// Get immutable Encryption Challenge.
00779   EncryptionChallenge::const_span encryptionChallenge() const {
00780     return const_cast<EncryptionHmacData &>(*this).encryptionChallenge();
00781   }
00782 
00783   /// Set Encryption Challenge.
00784   EncryptionHmacData &
00785   setEncryptionChallenge(EncryptionChallenge::const_span encryptionChallenge) {
00786     copy(encryptionChallenge, this->encryptionChallenge());
00787     return *this;
00788   }
00789 
00790   /// @}
00791 
00792   /// @name ROM ID
00793   /// @brief 1-Wire ROM ID of the device.
00794   /// @{
00795 
00796   /// Get mutable ROM ID.
00797   Core::RomId::span romId() {
00798     return make_span(result_).subspan<romIdIdx, Core::RomId::size>();
00799   }
00800 
00801   /// Get immutable ROM ID.
00802   Core::RomId::const_span romId() const {
00803     return const_cast<EncryptionHmacData &>(*this).romId();
00804   }
00805 
00806   /// Set ROM ID.
00807   EncryptionHmacData & setRomId(Core::RomId::const_span romId) {
00808     copy(romId, this->romId());
00809     return *this;
00810   }
00811 
00812   /// Set ROM ID for use in anonymous mode.
00813   MaximInterfaceDevices_EXPORT EncryptionHmacData & setAnonymousRomId();
00814 
00815   /// @}
00816 
00817   /// @name Page number
00818   /// @brief Number of the page to use data from.
00819   /// @{
00820 
00821   /// Get page number.
00822   int pageNum() const { return result_[pageNumIdx]; }
00823 
00824   /// Set page number.
00825   EncryptionHmacData & setPageNum(int pageNum) {
00826     result_[pageNumIdx] = pageNum;
00827     return *this;
00828   }
00829 
00830   /// @}
00831 
00832   /// @name MAN ID
00833   /// @brief Manufacturer ID of the device.
00834   /// @{
00835 
00836   /// Get mutable MAN ID.
00837   Core::ManId::span manId() {
00838     return make_span(result_).subspan<manIdIdx, Core::ManId::size>();
00839   }
00840 
00841   /// Get immutable MAN ID.
00842   Core::ManId::const_span manId() const {
00843     return const_cast<EncryptionHmacData &>(*this).manId();
00844   }
00845 
00846   /// Set MAN ID.
00847   EncryptionHmacData & setManId(Core::ManId::const_span manId) {
00848     copy(manId, this->manId());
00849     return *this;
00850   }
00851 
00852   /// @}
00853 
00854 private:
00855   static const size_t encryptionChallengeIdx = 0;
00856   static const size_t romIdIdx =
00857       encryptionChallengeIdx + EncryptionChallenge::size;
00858   static const size_t pageNumIdx = romIdIdx + Core::RomId::size;
00859   static const size_t manIdIdx = pageNumIdx + 1;
00860 
00861   Result::array result_;
00862 };
00863 
00864 /// Access fields in the ROM Options page.
00865 class DS28C36::RomOptions {
00866 public:
00867   explicit RomOptions(Page::span page) : page(page) {}
00868 
00869   bool romBlockDisable() const {
00870     return page[romBlockDisableIdx] == enabledValue;
00871   }
00872 
00873   RomOptions & setRomBlockDisable(bool romBlockDisable) {
00874     page[romBlockDisableIdx] = (romBlockDisable ? enabledValue : 0);
00875     return *this;
00876   }
00877 
00878   bool anonymous() const { return page[anonymousIdx] == enabledValue; }
00879 
00880   RomOptions & setAnonymous(bool anonymous) {
00881     page[anonymousIdx] = (anonymous ? enabledValue : 0);
00882     return *this;
00883   }
00884 
00885   Core::ManId::const_span manId() const {
00886     return page.subspan<22, Core::ManId::size>();
00887   }
00888 
00889   Core::RomId::const_span romId() const {
00890     return page.subspan<24, Core::RomId::size>();
00891   }
00892 
00893 private:
00894   static const Page::span::index_type romBlockDisableIdx = 0;
00895   static const Page::span::index_type anonymousIdx = 1;
00896   static const Page::span::value_type enabledValue = 0xAA;
00897 
00898   Page::span page;
00899 };
00900 
00901 /// Access fields in the GPIO Control page.
00902 class DS28C36::GpioControl {
00903 public:
00904   explicit GpioControl(Page::span page) : page(page) {}
00905 
00906   bool pioaConducting() const {
00907     return page[pioaConductingIdx] == pioConductingValue;
00908   }
00909 
00910   GpioControl & setPioaConducting(bool pioaConducting) {
00911     page[pioaConductingIdx] = (pioaConducting ? pioConductingValue : 0x55);
00912     return *this;
00913   }
00914 
00915   bool piobConducting() const {
00916     return page[piobConductingIdx] == pioConductingValue;
00917   }
00918 
00919   GpioControl & setPiobConducting(bool piobConducting) {
00920     page[piobConductingIdx] = (piobConducting ? pioConductingValue : 0x55);
00921     return *this;
00922   }
00923 
00924   bool pioaLevel() const { return page[2] == pioLevelValue; }
00925 
00926   bool piobLevel() const { return page[3] == pioLevelValue; }
00927 
00928 private:
00929   static const Page::span::index_type pioaConductingIdx = 0;
00930   static const Page::span::index_type piobConductingIdx = 1;
00931   static const Page::span::value_type pioConductingValue = 0xAA;
00932   static const Page::span::value_type pioLevelValue = 0x55;
00933 
00934   Page::span page;
00935 };
00936 
00937 } // namespace MaximInterfaceDevices
00938 
00939 #endif