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.

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