bool signerAtsha204SoftSignMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0); return false; } // Calculate signature of message mSetSigned(msg, 1); // make sure signing flag is set before signature is calculated signerCalculateSignature(msg); if (DO_WHITELIST(msg.destination)) { // Salt the signature with the senders nodeId and the (hopefully) unique serial The Creator has provided _signing_sha256.init(); for (int i=0; i<32; i++) _signing_sha256.write(_signing_hmac[i]); _signing_sha256.write(msg.sender); for (int i=0; i<SHA204_SERIAL_SZ; i++) _signing_sha256.write(_signing_node_serial_info[i]); memcpy(_signing_hmac, _signing_sha256.result(), 32); DEBUG_SIGNING_PRINTBUF(F("SHA256: "), _signing_hmac, 32); DEBUG_SIGNING_PRINTBUF(F("Signature salted with serial"), NULL, 0); } // Overwrite the first byte in the signature with the signing identifier _signing_hmac[0] = SIGNING_IDENTIFIER; // Transfer as much signature data as the remaining space in the message permits memcpy(&msg.data[mGetLength(msg)], _signing_hmac, MAX_PAYLOAD-mGetLength(msg)); DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); return true; }
bool signerAtsha204SoftGetNonce(MyMessage &msg) { DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0); // We used a basic whitening technique that takes the first byte of a new random value and builds up a 32-byte random value // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce _signing_sha256.init(); for (int i = 0; i < 32; i++) { _signing_sha256.write(random(256)); } memcpy(_signing_current_nonce, _signing_sha256.result(), MAX_PAYLOAD); DEBUG_SIGNING_PRINTBUF(F("SHA256: "), _signing_current_nonce, 32); // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(&_signing_current_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_current_nonce)-MAX_PAYLOAD); // Transfer the first part of the nonce to the message msg.set(_signing_current_nonce, MAX_PAYLOAD); _signing_verification_ongoing = true; _signing_timestamp = millis(); // Set timestamp to determine when to purge nonce // Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover) // Note that if message is "too" quick, and arrives before turnover, it will be rejected // but this is consider such a rare case that it is accepted and rejects are 'safe' if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < millis()) _signing_timestamp = 0; return true; }
bool signerAtsha204SoftVerifyMsg(MyMessage &msg) { if (!_signing_verification_ongoing) { DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0); return false; } else { // Make sure we have not expired if (!signerCheckTimer()) { return false; } _signing_verification_ongoing = false; if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { DEBUG_SIGNING_PRINTBUF(F("Incorrect signing identifier"), NULL, 0); return false; } // Get signature of message DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); signerCalculateSignature(msg); #ifdef MY_SIGNING_NODE_WHITELISTING // Look up the senders nodeId in our whitelist and salt the signature with that data size_t j; for (j=0; j < NUM_OF(_signing_whitelist); j++) { if (_signing_whitelist[j].nodeId == msg.sender) { DEBUG_SIGNING_PRINTBUF(F("Sender found in whitelist"), NULL, 0); _signing_sha256.init(); for (int i=0; i<32; i++) _signing_sha256.write(_signing_hmac[i]); _signing_sha256.write(msg.sender); for (int i=0; i<SHA204_SERIAL_SZ; i++) _signing_sha256.write(_signing_whitelist[j].serial[i]); memcpy(_signing_hmac, _signing_sha256.result(), 32); DEBUG_SIGNING_PRINTBUF(F("SHA256: "), _signing_hmac, 32); break; } } if (j == NUM_OF(_signing_whitelist)) { DEBUG_SIGNING_PRINTBUF(F("Sender not found in whitelist, message rejected!"), NULL, 0); return false; } #endif // Overwrite the first byte in the signature with the signing identifier _signing_hmac[0] = SIGNING_IDENTIFIER; // Compare the caluclated signature with the provided signature if (memcmp(&msg.data[mGetLength(msg)], _signing_hmac, MAX_PAYLOAD-mGetLength(msg))) { DEBUG_SIGNING_PRINTBUF(F("Signature bad: "), _signing_hmac, MAX_PAYLOAD-mGetLength(msg)); #ifdef MY_SIGNING_NODE_WHITELISTING DEBUG_SIGNING_PRINTBUF(F("Is the sender whitelisted and serial correct?"), NULL, 0); #endif return false; } else { DEBUG_SIGNING_PRINTBUF(F("Signature OK"), NULL, 0); return true; } } }
void setup() { printf("Test: FIPS 180-2 B.1\n"); printf("Expect:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad\n"); printf("Result:"); Sha256Class sha; sha.init(); uint32_t value = 0x1010101; sha.write('a'); sha.write('b'); sha.write('c'); uint8_t *ans = sha.result(); printHash(ans); printf("\n"); }
// Helper to calculate signature of msg (returned in hmac) static void signerCalculateSignature(MyMessage &msg) { memset(_signing_temp_message, 0, 32); memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), _signing_current_nonce, 32); // ATSHA204 calculates the HMAC with a PSK and a SHA256 digest of the following data: // 32 bytes zeroes // 32 bytes digest, // 1 byte OPCODE (0x11) // 1 byte Mode (0x04) // 2 bytes SlotID (0x0000) // 11 bytes zeroes // SN[8] (0xEE) // 4 bytes zeroes // SN[0:1] (0x0123) // 2 bytes zeroes // The digest is calculated as a SHA256 digest of the following: // 32 bytes message // 1 byte OPCODE (0x15) // 1 byte param1 (0x02) // 2 bytes param2 (0x0800) // SN[8] (0xEE) // SN[0:1] (0x0123) // 25 bytes zeroes // 32 bytes nonce // Calculate message digest first _signing_sha256.init(); for (int i=0; i<32; i++) _signing_sha256.write(_signing_temp_message[i]); _signing_sha256.write(0x15); // OPCODE _signing_sha256.write(0x02); // param1 _signing_sha256.write(0x08); // param2(1) _signing_sha256.write(0x00); // param2(2) _signing_sha256.write(0xEE); // SN[8] _signing_sha256.write(0x01); // SN[0] _signing_sha256.write(0x23); // SN[1] for (int i=0; i<25; i++) _signing_sha256.write(0x00); for (int i=0; i<32; i++) _signing_sha256.write(_signing_current_nonce[i]); // Purge nonce when used memset(_signing_current_nonce, 0xAA, 32); memcpy(_signing_temp_message, _signing_sha256.result(), 32); // Feed "message" to HMAC calculator _signing_sha256.initHmac(_signing_hmac_key,32); // Set the key to use for (int i=0; i<32; i++) _signing_sha256.write(0x00); // 32 bytes zeroes for (int i=0; i<32; i++) _signing_sha256.write(_signing_temp_message[i]); // 32 bytes digest _signing_sha256.write(0x11); // OPCODE _signing_sha256.write(0x04); // Mode _signing_sha256.write(0x00); // SlotID(1) _signing_sha256.write(0x00); // SlotID(2) for (int i=0; i<11; i++) _signing_sha256.write(0x00); // 11 bytes zeroes _signing_sha256.write(0xEE); // SN[8] for (int i=0; i<4; i++) _signing_sha256.write(0x00); // 4 bytes zeroes _signing_sha256.write(0x01); // SN[0] _signing_sha256.write(0x23); // SN[1] for (int i=0; i<2; i++) _signing_sha256.write(0x00); // 2 bytes zeroes memcpy(_signing_hmac, _signing_sha256.resultHmac(), 32); DEBUG_SIGNING_PRINTBUF(F("HMAC: "), _signing_hmac, 32); }