Hash of .bin file

I am working on a project with my Internet of Things students relative to ensuring integrity of code (digital transparency) as it is moved through development, testing, and deployment. I realize that Particle has some built-in functionality to ensure security of flashing code OTA. However, this is more a classroom learning exercise to understand how the students can ensure if they manually flash a .bin file that it matches the intended code and, ideally, to validate that the intended code is on a device.

We had a previous issue within our school’s firewall, that if I understand correctly, was related to a hash of the code on the Particle device being sent to the Particle Cloud as part of the connection/authentication process.

Thus, two part question:

  1. If there is indeed a hash of the code on the Particle that is sent to the cloud, is it accessible by the user (i.e., could I obtain that hash from the code running on my device)?
  2. Is there a way to hash a .bin file within the Particle-CLI so I can see that same hash and use it to compare what is on the device to the .bin file that is intended?

Thank you,
IoT Educator
Central New Mexico Community College

Hi Brian- Thanks for reaching out. Sorry for the delay in response.

What was the issue with the firewall? Unless firewall is doing some modification of CoAP packets on the fly, there’s might be something else going on

Colleen - thank you for getting back to me. My purpose for the post was less about the firewall issue and more about the question of can I get the hash of the .bin file that I create. My students are working on a project that includes ensuring providence of the code they generate (i.e., validating that the code on an Argon is actually the code that they created if someone else does the flash). I see a app-hash sent to the particle console events when new code is flashed, but is there a way that I can get that hash directly from the particle so I can compare it to what I expect to be there.

All that said, I would like to fix the issue we are having with the first connect after flashing code. You can look at ticket (104248) to see the history and the assistance Ismael Soleto gave me last year. Updating to 3.0.0 worked for a little while but the issue started again. My current group of students are experiencing the issue. We are running deviceOS 3.2.0.

Here’s a screen shot of the issue. I had simple Hello World code where I changed one delay.

ID: e00fce687131b33d2d92f1c8

At 10:29 (Mountain) I flashed to code. You can see it try to connect and send the new app-hash.
The device is stuck in blinking cyan.
After the 10:30:07 message (while still blinking cyan), I power cycle the Argon (remove and reconnect the USB cable).
It reconnects a few seconds later, has no trouble going into breathing cyan, and starts blinking Hello World to the D7 LED.

When you flash a device OTA, you’ll notice in the event log a spark/device/app-hash event published by the device. As you might guess, this is a hash. Specifically, a SHA-256, 32 bytes of hash expressed as 64 hexadecimal digits.

Each firmware binary consists of a prefix header, the binary executable, the suffix, and a CRC32. The suffix contains the 32-byte SHA-256 hash of the binary.

It’s theoretically possible to both find the saved hash for the binary currently loaded, as well as verify it, but it’s not something that’s normally ever done so it’s not currently documented anywhere. But it should be possible.

1 Like

Rick - thank you for your assistance. I did come across the app-hash which I see gets uploaded once when it changes (but not in subsequent Argon boots). So, presumably, there is code somewhere that can pull the hash and send it to the cloud. When you say is <isn’t documented but should be possible> how does one go about asking someone in the know on the DeviceOS development team how to do this?

Here’s an example of retrieving the app-hash and CRC from user firmware

Sample code

#include "Particle.h"

SerialLogHandler logHandler;

#ifdef SYSTEM_VERSION_v310
const uint32_t APP_ADDR = 0x000b4000; // Device OS 3.1 and later (256K binaries)
const uint32_t APP_ADDR = 0x000d4000; // Earlier versions including 2.x LTS

void setup() {
    waitFor(Serial.isConnected, 10000);

    const module_info_t *prefix = (module_info_t *)APP_ADDR;

    const uint32_t *crcAddr = (const uint32_t *)prefix->module_end_address;
    Log.info("crc32=%lx", *crcAddr);

    const uint8_t *sha = (const uint8_t *)(((uint32_t)prefix->module_end_address) - 34);
    Log.dump(sha, 32);

void loop() {


Debug Serial

0000002717 [app] INFO: crc32=748065e0
0000002717 [app] INFO: sha256=

Console Event

The app-hash matches!

Binary inspect

This shows the CRC. Note that the byte order is reversed here, but the bytes are the same.

% particle binary inspect firmware.bin 
 CRC is ok (e0658074)
 Compiled for argon
 This is an application module number 1 at version 6
 It depends on a system module number 1 at version 2301

Firmware binary dump

If you dump out the bytes of a compiled binary, you’ll see the last 4 bytes of the file are the CRC32. The hash begins 34 bytes before that (f0 58 f1 e0…)

% od -t x1 firmware.bin|tail               
0025220    81  63  0d  00  00  00  00  00  00  00  00  00  00  00  00  00
0025240    00  00  00  00  38  68  0d  00  08  69  0d  00  20  69  0d  00
0025260    10  e5  03  20  00  00  00  00  00  00  00  00  00  00  00  00
0025300    00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
0025420    00  00  00  00  e5  e7  03  20  ff  ff  ff  ff  00  00  f0  58
0025440    f1  e0  01  39  66  4b  26  92  2e  50  38  42  ad  15  cb  0b
0025460    3a  91  85  53  8d  7e  bd  c5  bb  d2  21  0a  9c  80  28  00
0025500    e0  65  80  74                                                
1 Like

Rick - thank you. You have answered my questions a few times over the years and I always learn a lot from your solutions. Even better, beyond the problem I am focused on, I learn more about the particle embedded systems in a way that allows me to enhance my class for my students. Thank you.


This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.