问题
Quoting the documentation:
Once pre-registered, a Device can Activate by sending an Activation Code to the Xively API. This signals to Xively that the Device has woken up for the first time, and is requesting to be provisioned with a Feed ID and API Key that it can use. A Device’s Activation Code is generated using an HMAC-SHA1 hash that combines the Device’s Serial Number with its parent Product’s Product Secret to makes it effectively impossible for someone to extract the Product Secret from the activation code, or to fraudulently impersonate a Device in the provisioning process.
What is best practice:
- keeping the Activation Code on each device memory: very time consuming to program at factory time
- computing the Activation code on device wakeup via
HMAC-SHA1(serialnumber, productid)
.
In my case the second make more sense, however I cannot find how the HMAC is calculated from the API docs. Is it just a string concatenation? What about padding?
回答1:
Everything errordeveloper said is absolutely correct.
One additional thing to keep in mind is that the product secret listed on the product (or device) page is already in hex pair format. You do not need to convert the string to hex, but rather use the current string as a hex string. You can see how this is done in the Arduino code posted by errordeveloper.
回答2:
There is an example of how this can be done in Python. You will notice that it converts the product secret to binary using binascii .a2b_hex()
.
Here is another example in Ruby:
require('openssl')
secret = '488f40ff3d0b2c6188e272f8d86416b73b3cb4ef'
serial = '0123456789'
digest = OpenSSL::Digest::Digest.new('sha1')
puts OpenSSL::HMAC.hexdigest(digest, [secret].pack("H*"), serial)
And here is one for Arduino:
// First, download the library from https://github.com/Cathedrow/Cryptosuite
// and make sure it is installed properly, although until it supports Arduino 1.0,
// it's better to use this fork: https://github.com/jkiv/Cryptosuite
#include "sha1.h"
uint8_t secret[]={
0x48,0x8f,0x40,0xff,0x3d,0x0b,0x2c,0x61,0x88,0xe2,
0x72,0xf8,0xd8,0x64,0x16,0xb7,0x3b,0x3c,0xb4,0xef,
};
String serial = "0123456789";
String activation_code;
String convertHash(uint8_t* hash) {
String returnString;
int i;
for (i=0; i<20; i++) {
returnString += ("0123456789abcdef"[hash[i]>>4]);
returnString += ("0123456789abcdef"[hash[i]&0xf]);
}
return returnString;
}
void setup() {
// Generally you would compute the hash once on start up and store it in flash
// to avoid doing it each time as it can be a bit slow
Serial.begin(57600);
Serial.println("computing hmac sha: ");
Sha1.initHmac(secret, 20);
Sha1.print(serial);
activation_code = convertHash(Sha1.resultHmac());
Serial.println(activation_code);
}
来源:https://stackoverflow.com/questions/18445589/device-s-activation-code-best-practice