MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification
Dependencies: MaximInterface mbed
The MAXREFDES143# is an Internet of Things (IoT) embedded security reference design, built to protect an industrial sensing node by means of authentication and notification to a web server. The hardware includes a peripheral module representing a protected sensor node monitoring operating temperature and remaining life of a filter (simulated through ambient light sensing) and an mbed shield representing a controller node responsible for monitoring one or more sensor nodes. The design is hierarchical with each controller node communicating data from connected sensor nodes to a web server that maintains a centralized log and dispatches notifications as necessary. The mbed shield contains a Wi-Fi module, a DS2465 coprocessor with 1-Wire® master function, an LCD, LEDs, and pushbuttons. The protected sensor node contains a DS28E15 authenticator, a DS7505 temperature sensor, and a MAX44009 light sensor. The mbed shield communicates to a web server by the onboard Wi-Fi module and to the protected sensor node with I2C and 1-Wire. The MAXREFDES143# is equipped with a standard shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The simplicity of this design enables rapid integration into any star-topology IoT network requiring the heightened security with low overhead provided by the SHA-256 symmetric-key algorithm.
More information about the MAXREFDES143# is available on the Maxim Integrated website.
Diff: Factory.cpp
- Revision:
- 32:0a09505a656d
- Parent:
- 25:37ea43ff81be
--- a/Factory.cpp Tue Apr 04 14:10:48 2017 -0500 +++ b/Factory.cpp Mon Nov 06 17:34:13 2017 -0600 @@ -28,127 +28,160 @@ * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. -******************************************************************************* -*/ +*******************************************************************************/ +#include <MaximInterface/Devices/DS2465.hpp> +#include <MaximInterface/Devices/DS28E15_22_25.hpp> +#include <MaximInterface/Utilities/Segment.hpp> #include "Factory.hpp" #include "SensorNode.hpp" -#include "Masters/DS2465/DS2465.h" -#include "Slaves/Authenticators/DS28E15_22_25/DS28E15_22_25.h" -#include "wait_api.h" -using namespace OneWire; +using namespace MaximInterface; /// The valid master secret for the system. -static const DS2465::Secret masterSecret = { { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x21, - 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x31, 0x32 } }; +static const Sha256::Hash masterSecret = { + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1E, 0x1F, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x31, 0x32}; /// An invalid master secret for example purposes. -static const DS2465::Secret invalidMasterSecret = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; +static const Sha256::Hash invalidMasterSecret = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -bool provisionCoprocessor(DS2465 & ds2465) -{ - bool result = (ds2465.setMasterSecret(masterSecret) == ISha256MacCoproc::Success); - if (result) - { +bool provisionCoprocessor(DS2465 & ds2465) { + bool result = !ds2465.writeMasterSecret(masterSecret); + if (result) { SensorNode::AuthData authData; - DS28E15_22_25::Page pageData; + DS28E15::Page pageData; pageData.fill(uint8_t(SensorNode::defaultPaddingByte)); - std::copy(authData.segment.begin(), authData.segment.end(), pageData.begin()); - result = (ds2465.writeScratchpad(pageData.data(), pageData.size()) == OneWireMaster::Success); + const std::pair<DS28E15::Page::iterator, DS28E15::Page::iterator> + pageSegment = + createSegment(pageData.begin(), pageData.end(), + authData.segment.size(), authData.segmentNum); + if (pageSegment.first != pageData.end()) { + std::copy(authData.segment.begin(), authData.segment.end(), + pageSegment.first); + } + result = !ds2465.writePage(0, pageData); } - if (result) - { - result = (ds2465.copyScratchpadToPage(0) == OneWireMaster::Success); - if (result) - wait_ms(DS2465::eepromPageWriteDelayMs); - } - return result; } -bool provisionSensorNode(SensorNode & sensorNode, bool validSecret) -{ +bool provisionSensorNode(SensorNode & sensorNode, bool validSecret) { const int blockNum = sensorNode.authData.pageNum / 2; - const DS28E15_22_25::BlockProtection desiredProtection(false, false, false, true, blockNum); // Authentication Protection only - + const DS28E15::BlockProtection desiredProtection( + false, false, false, true, blockNum); // Authentication Protection only + // Reset to starting defaults sensorNode.authData.reset(); - + // Read current protection status - DS28E15_22_25::BlockProtection protectionStatus; - bool result; - // Read block protections - result = (sensorNode.ds28e15.readBlockProtection(blockNum, protectionStatus) == OneWireSlave::Success); + DS28E15::BlockProtection protectionStatus; + bool result = + !sensorNode.ds28e15.readBlockProtection(blockNum, protectionStatus); // Check if invalid protections are set if (result) - result = ((protectionStatus.statusByte() & ~(desiredProtection.statusByte())) == 0x00); + result = ((protectionStatus.statusByte() & + ~(desiredProtection.statusByte())) == 0x00); // Load secret into scratchpad if (result) - result = (sensorNode.ds28e15.writeScratchpad(validSecret ? masterSecret : invalidMasterSecret) == OneWireSlave::Success); + result = !sensorNode.ds28e15.writeScratchpad( + validSecret ? masterSecret : invalidMasterSecret); // Load master secret from scratchpad without locking if (result) - result = (sensorNode.ds28e15.loadSecret(false) == OneWireSlave::Success); - + result = !sensorNode.ds28e15.loadSecret(false); + // Setup is complete if not using a valid secret if (!validSecret) return result; - + // Create constant partial secret - DS28E15_22_25::Scratchpad partialSecret; - DS28E15_22_25::Page pageData; + DS28E15::Scratchpad partialSecret; + DS28E15::Page pageData; partialSecret.fill(uint8_t(SensorNode::defaultPaddingByte)); - + // Read page data if (result) - result = (sensorNode.ds28e15.readPage(sensorNode.authData.pageNum, pageData, false) == OneWireSlave::Success); + result = + !sensorNode.ds28e15.readPage(sensorNode.authData.pageNum, pageData); // Load partial secret into scratchpad if (result) - result = (sensorNode.ds28e15.writeScratchpad(partialSecret) == OneWireSlave::Success); + result = !sensorNode.ds28e15.writeScratchpad(partialSecret); // Compute secret if (result) - result = (sensorNode.ds28e15.computeSecret(sensorNode.authData.pageNum, false) == OneWireSlave::Success); + result = + !sensorNode.ds28e15.computeSecret(sensorNode.authData.pageNum, false); // Configure slave secret on DS2465 - if (result) - result = (DS28E15_22_25::computeNextSecret(sensorNode.ds2465, pageData, sensorNode.authData.pageNum, partialSecret, sensorNode.ds28e15.romId(), sensorNode.ds28e15.manId()) == ISha256MacCoproc::Success); + if (result) { + const Sha256::SlaveSecretData data = DS28E15::createSlaveSecretData( + pageData, sensorNode.authData.pageNum, partialSecret, + sensorNode.romId(), sensorNode.manId); + result = !sensorNode.ds2465.computeSlaveSecret(data); + } // Enable authentication protection if not set - if (result && (protectionStatus != desiredProtection)) - result = (sensorNode.ds28e15.writeAuthBlockProtection(sensorNode.ds2465, desiredProtection, protectionStatus) == OneWireSlave::Success); + if (result && (protectionStatus != desiredProtection)) { + const Sha256::WriteMacData data = DS28E15::createProtectionWriteMacData( + desiredProtection, protectionStatus, sensorNode.romId(), + sensorNode.manId); + Sha256::Hash mac; + result = !sensorNode.ds2465.computeWriteMac(data, mac); + if (result) + result = + !sensorNode.ds28e15.writeAuthBlockProtection(desiredProtection, mac); + } // Write initial filter life and set all other segments to default value - if (result) - { - DS28E15_22_25::Segment blankSegment; + if (result) { + DS28E15::Segment blankSegment; blankSegment.fill(uint8_t(SensorNode::defaultPaddingByte)); - for (size_t i = 0; i < DS28E15_22_25::segmentsPerPage; i++) - { - result = (sensorNode.ds28e15.writeAuthSegment(sensorNode.ds2465, sensorNode.authData.pageNum, i, - ((i == sensorNode.authData.segmentNum) ? sensorNode.authData.segment : blankSegment), - DS28E15_22_25::segmentFromPage(i, pageData), false) == OneWireSlave::Success); - + for (int i = 0; i < DS28E15::segmentsPerPage; i++) { + const DS28E15::Segment newSegment = (i == sensorNode.authData.segmentNum) + ? sensorNode.authData.segment + : blankSegment; + const std::pair<DS28E15::Page::iterator, DS28E15::Page::iterator> + pageSegment = createSegment(pageData.begin(), pageData.end(), + DS28E15::Segment::size(), i); + DS28E15::Segment oldSegment; + std::copy(pageSegment.first, pageSegment.second, oldSegment.begin()); + const Sha256::WriteMacData data = DS28E15::createSegmentWriteMacData( + sensorNode.authData.pageNum, i, newSegment, oldSegment, + sensorNode.romId(), sensorNode.manId); + Sha256::Hash mac; + result = !sensorNode.ds2465.computeWriteMac(data, mac); + if (!result) + break; + result = !sensorNode.ds28e15.writeAuthSegment(sensorNode.authData.pageNum, + i, newSegment, mac); if (!result) break; } } - + // Reload secret with known page values // Load master secret into scratchpad if (result) - result = (sensorNode.ds28e15.writeScratchpad(masterSecret) == OneWireSlave::Success); + result = !sensorNode.ds28e15.writeScratchpad(masterSecret); // Load master secret if (result) - result = (sensorNode.ds28e15.loadSecret(false) == OneWireSlave::Success); + result = !sensorNode.ds28e15.loadSecret(false); // Read page data if (result) - result = (sensorNode.ds28e15.readPage(sensorNode.authData.pageNum, pageData, false) == OneWireSlave::Success); + result = + !sensorNode.ds28e15.readPage(sensorNode.authData.pageNum, pageData); // Write partial secret to scratchpad if (result) - result = (sensorNode.ds28e15.writeScratchpad(partialSecret) == OneWireSlave::Success); + result = !sensorNode.ds28e15.writeScratchpad(partialSecret); // Compute secret if (result) - result = (sensorNode.ds28e15.computeSecret(sensorNode.authData.pageNum, false) == OneWireSlave::Success); + result = + !sensorNode.ds28e15.computeSecret(sensorNode.authData.pageNum, false); // Configure slave secret on DS2465 - if (result) - result = (DS28E15_22_25::computeNextSecret(sensorNode.ds2465, pageData, sensorNode.authData.pageNum, partialSecret, sensorNode.ds28e15.romId(), sensorNode.ds28e15.manId()) == ISha256MacCoproc::Success); + if (result) { + const Sha256::SlaveSecretData data = DS28E15::createSlaveSecretData( + pageData, sensorNode.authData.pageNum, partialSecret, + sensorNode.romId(), sensorNode.manId); + result = !sensorNode.ds2465.computeSlaveSecret(data); + } return result; } \ No newline at end of file