//-------------------------------------------------------------------------- // Copyright 2016, RIoT International Pty Ltd // // @author Aaron Ardiri //-------------------------------------------------------------------------- // microTLS - ecc163/aes128 //-------------------------------------------------------------------------- // configuration //-------------------------------------------------------------------------- const char WiFi_SSID[] PROGMEM = "xxxx"; const char WiFi_PASS[] PROGMEM = "xxxx"; const uint8_t SERVER[] PROGMEM = { xxx, xxx, xxx, xxx }; #define SERVER_URI "/xxx/index.php" #define SERVER_NAME "xxx.xxxxxxxx.xxx" #define CLIENT_GUID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" #define CLIENT_INTERVAL 300 // 5 minutes //-------------------------------------------------------------------------- // pre-shared keys //-------------------------------------------------------------------------- // :: server - we need the public key, private goes on server // // char ecc_public_x[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // char ecc_public_y[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // char ecc_priv[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; const uint32_t ecc_public_x[] PROGMEM = { 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX }; const uint32_t ecc_public_y[] PROGMEM = { 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX }; // :: client - we need the private key, public goes on server // // char ecc_public_x[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // char ecc_public_y[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // char ecc_priv[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; const uint32_t ecc_private[] PROGMEM = { 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX, 0xXXXXXXXX }; //-------------------------------------------------------------------------- // modules //-------------------------------------------------------------------------- #include "microTLS-module-ecc163.h" #include "microTLS-module-aes128.h" #define SESS_SECURITY "ecc-163" #define PING_SECURITY "aes-128" //-------------------------------------------------------------------------- // additional globals //-------------------------------------------------------------------------- typedef struct xGlobals { uint8_t aeskey[AES_KEYLEN]; } xGlobals; xGlobals gx; //-------------------------------------------------------------------------- // entry point //-------------------------------------------------------------------------- void microTLS_setup() { } //-------------------------------------------------------------------------- // session: creation //-------------------------------------------------------------------------- void microTLS_sess_prepare() { HashEngine ctx_hash; ECCEngine ctx_ecc; int enc_len; int ofs; SYS_RAM_CHECK; // how long is the buffer we want to encrypt enc_len = g.scratch.token.len + ECC_OVERHEAD; // we must prepare our send buffer g.scratch.send.len = 0; ofs = g.scratch.token.len + g.scratch.param.len + g.scratch.send.len + g.scratch.recv.len; g.scratch.send.buf = &g.scratch.reserved[ofs]; // we need to generate an integrity hash for the buffer we are sending hashInit(&ctx_hash); hashUpdate(&ctx_hash, g.scratch.token.buf, g.scratch.token.len); hashFinal(&ctx_hash); g.scratch.send.digest = ctx_hash.digest; // encode our message ECCinitState(&ctx_ecc); ECCencrypt(&ctx_ecc, (char *)g.scratch.send.buf, (char *)g.scratch.token.buf, g.scratch.token.len); // the message we want to send is now stored in g.param and g.scratch g.scratch.send.len = enc_len; } bool microTLS_sess_process() { ECCEngine ctx_ecc; int len; SYS_RAM_CHECK; // how long is the destination buffer? len = g.scratch.recv.len - ECC_OVERHEAD; // did we receive a key? if (len == AES_KEYLEN) { // decode our message - direct into the AES key ECCinitState(&ctx_ecc); ECCdecrypt(&ctx_ecc, (char *)gx.aeskey, (char *)g.scratch.recv.buf, len); // let's move it back into scratch for debugging purposes memcpy(g.scratch.recv.buf, gx.aeskey, len); g.scratch.recv.len = len; } return true; } //-------------------------------------------------------------------------- // session: update //-------------------------------------------------------------------------- const char msg[] PROGMEM = "sending a message over microTLS"; void microTLS_ping_prepare() { HashEngine ctx_hash; AESEngine ctx_aes; int len, enc_len; uint8_t *p; int i; int ofs; SYS_RAM_CHECK; // how much memory do we need for this operation? len = strlen_P(msg); enc_len = (len + AES_BLOCKSIZE) & ~(AES_BLOCKSIZE-1); enc_len += AES_BLOCKSIZE; // don't forget the IV // we need to make sure both buffers fit in our scratch area if ((len + enc_len) < (CLIENT_SCRATCH_LEN - 2)) { // we'll put our source at the end of scratch p = &g.scratch.reserved[CLIENT_SCRATCH_LEN - len - 1]; strcpy_P((char *)p, msg); // we need to generate an integrity hash for the buffer we are sending hashInit(&ctx_hash); hashUpdate(&ctx_hash, p, len); hashFinal(&ctx_hash); g.scratch.send.digest = ctx_hash.digest; // we must prepare our send buffer g.scratch.send.len = 0; ofs = g.scratch.token.len + g.scratch.param.len + g.scratch.send.len + g.scratch.recv.len; g.scratch.send.buf = &g.scratch.reserved[ofs]; // we must create a random IV - put it in first bytes for (i=0;i < AES_BLOCKSIZE; i++) g.scratch.send.buf[i] = xrand(); // encode our message AESinitState(&ctx_aes, gx.aeskey, g.scratch.send.buf); AESencrypt(&ctx_aes, p, len, g.scratch.send.buf+AES_BLOCKSIZE); // the encrypted value is now stored in g.scratch.buf g.scratch.send.len = enc_len; } } bool microTLS_ping_process() { AESEngine ctx_aes; int len, enc_len; uint8_t *p; int i; int ofs; SYS_RAM_CHECK; enc_len = g.scratch.recv.len; len = enc_len - AES_BLOCKSIZE; // maximum size it can be // we need to make sure both buffers fit in our scratch area if ((len + enc_len) < (CLIENT_SCRATCH_LEN - 2)) { // we'll put our encoded stuff at the end of scratch p = &g.scratch.reserved[CLIENT_SCRATCH_LEN - enc_len - 1]; memcpy(p, g.scratch.recv.buf, g.scratch.recv.len); // decode our message - IV is at start of packet AESinitState(&ctx_aes, gx.aeskey, p); p += AES_BLOCKSIZE; AESdecrypt(&ctx_aes, p, len, g.scratch.recv.buf); // find the PKCS7 padding bytes - correct the length if needed if (g.scratch.recv.buf[len-1] < (AES_BLOCKSIZE+1)) len -= g.scratch.recv.buf[len-1]; // the decrypted value is now stored in g.scratch.buf g.scratch.recv.len = len; // the buffer should now have been shortened } return true; } //--------------------------------------------------------------------------