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

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