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"); }
void igc_writeline(char * line, bool sign = true) { uint8_t l = strlen(line); uint16_t wl; // DEBUG("IGC:%s\n", line); strcpy_P(line + l, PSTR("\r\n")); l += 2; assert(f_write(&log_file, line, l, &wl) == FR_OK); assert(wl == l); assert(f_sync(&log_file) == FR_OK); #ifndef IGC_NO_PRIVATE_KEY if (sign) for (uint8_t i = 0; i < l; i++) sha256.write(line[i]); #endif }
uint8_t igc_start(char * path) { char filename[128]; uint8_t sec; uint8_t min; uint8_t hour; uint8_t day; uint8_t wday; uint8_t month; uint16_t year; char line[79]; char id[32]; sha256.init(); IGC_PRIVATE_KEY_ADD; datetime_from_epoch(time_get_utc(), &sec, &min, &hour, &day, &wday, &month, &year); //XXX #define device_uid "DRP" sprintf_P(filename, PSTR("%sIGC"), path); DEBUG("IGC filename %s\n", filename); uint8_t res = f_open(&log_file, filename, FA_WRITE | FA_CREATE_ALWAYS); assert(res == FR_OK); DEBUG("f_open res = %02X\n", res); //cannot create file if (res != FR_OK) return false; //A record GetID_str(id); sprintf_P(line, PSTR("A%S%s:%s"), LOG_MID_P, device_uid, id); igc_writeline(line); //H records //H F DTE sprintf_P(line, PSTR("HFDTE%02u%02u%02u"), day, month, year % 100); igc_writeline(line); // //H F DTE // sprintf_P(line, PSTR("HFDTEDATE:%02u%02u%02u,%02u"), day, month, year % 100, logger_flight_number); // igc_writeline(line); //H F PLT PILOT IN CHARGE sprintf_P(line, PSTR("HFPLTPILOTINCHARGE:%s"), config.logger.pilot); igc_writeline(line); //H F CM2 CREW 2 sprintf_P(line, PSTR("HFCM2CREW2:NIL")); igc_writeline(line); //H F GTY GLIDER TYPE sprintf_P(line, PSTR("HFGTYGLIDERTYPE:%s"), config.logger.glider_type); igc_writeline(line); //H F GID GLIDER ID sprintf_P(line, PSTR("HFGIDGLIDERID:%s"), config.logger.glider_id); igc_writeline(line); //H F DTM GPS DATUM sprintf_P(line, PSTR("HFDTMGPSDATUM:WGS84")); igc_writeline(line); //H F RFW FIRMWARE VERSION sprintf_P(line, PSTR("HFRFWFIRMWAREVERSION:build %d"), BUILD_NUMBER); igc_writeline(line); //H F RHW HARDWARE VERSION sprintf_P(line, PSTR("HFRHWHARDWAREVERSION:drop_%d"), (hw_revision == HW_REW_1504) ? 1504 : 1506); igc_writeline(line); //H F FTY FR TYPE sprintf_P(line, PSTR("HFFTYFRTYPE:SkyBean,SkyDrop")); igc_writeline(line); //H F GPS RECEIVER sprintf_P(line, PSTR("HFGPSRECEIVER:Quectel,L80,22cm,18000m")); igc_writeline(line); //H F PRS PRESS ALT SENSOR sprintf_P(line, PSTR("HFPRSPRESSALTSENSOR:Measurement specialties,MS5611,25907m")); igc_writeline(line); //H F ALG ALT GPS sprintf_P(line, PSTR("HFALGALTGPS:GEO")); igc_writeline(line); //H F ALP sprintf_P(line, PSTR("HFALPALTPRESSURE:ISA")); igc_writeline(line); //H F TZN sprintf_P(line, PSTR("HFTZNTIMEZONE:%+0.1f"), config.system.time_zone / 2.0); igc_writeline(line); #ifdef IGC_NO_PRIVATE_KEY //Developer note: we can't publish the private key for signing the IGC file //H F FRS sprintf_P(line, PSTR("HFFRSSECSUSPECTUSEVALIPROG:This file is not valid. Private key not available!")); igc_writeline(line); #endif //dump the cache // DEBUG("IGC dump len %d\n", igc_pre_start_len); for (uint8_t i = igc_pre_start_len; i > 0; i--) { int8_t index = igc_pre_start_index - i; if (index < 0) index += IGC_PRE_START_BUFFER; // DEBUG("IGC dump %d\n", index); igc_pre_fix * pfix = &igc_pre_start_cache[index]; int16_t galt = pfix->galt; char c = 'A'; if (galt == 0x7FFF) { galt = 0; c = 'V'; } sprintf_P(line, PSTR("B%02d%02d%02d%s%s%c%05d%05d"), pfix->hour, pfix->min, pfix->sec, pfix->cache_igc_latitude, pfix->cache_igc_longtitude, c, pfix->balt, galt); igc_writeline(line); } // igc_comment("End of cache"); igc_write_grecord(); return (fc.gps_data.valid) ? LOGGER_ACTIVE : LOGGER_WAIT_FOR_GPS; }
// 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); }