MySensors: generare chiavi HMAC e AES

Mysensors criptazione dati

Mysensors: generare le chiavi HMAC e AES

Questo è l’articolo numero 2 di una serie totale di 3 articoli su “MySensors e criptazione dati”.

Articolo 1: Leggi

Nella scorsa puntata abbiamo usato uno script per verificare che la nostra EEPROM fosse vuota. Ora dobbiamo installare il primo nodo (presumibilmente sarà Arduino che ci farà da gateway USB per MySensors) e più in dettaglio far generare allo script due chiavi:

SOFT_HMAC_KEY

AES_KEY

(Ricordo che l’intera guida si basa sulla sicurezza software e non tramite hardware).

Come generare AES_KEY e SOFT_HMAC_KEY

Riprendiamo lo script precedente (stavolta dall’IDE Arduino facciamo un Salva con nome e diamogli come nome “Setup_first_node”).

Ci basta definire (quindi togliere il commento, cioè il doppio “slash”) davanti ad alcune righe e commentarne altre.

In dettaglio

  • Commentare //#define SKIP_KEY_STORAGE < vogliamo salvare i dati nella EEPROM
  • Decommentare #define STORE_SOFT_KEY
  • Decommentare #define STORE_SOFT_SERIAL
  • Decommentare #define STORE_AES_KEY

E fare l’upload dello sketch nel nostro Arduino.

In questo caso sarà lo sketch stesso ad occuparsi di generare in automatico le due chiavi per la crittografia e assegnare un seriale al nostro Arduino.

Le due chiavi dovranno essere uguali in tutti i nodi della nostra rete. La seriale invece no, anzi, sarà quella che ci permetterà di dire ad un nodo “Accetta solo connessioni da questo seriale”). Un livello di sicurezza in più.

Una volta uploadato lo script, aprendo il monitor seriale avremo una risposta simile alla seguente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Personalization sketch for MySensors usage.
-------------------------------------------
This value will be stored in EEPROM as soft HMAC key:
#define MY_SOFT_HMAC_KEY 0xAA[...],0xAA
This value will be stored in EEPROM as soft serial:
#define MY_SOFT_SERIAL 0xAA,[...],0xAA
This key will be stored in EEPROM as AES key:
#define MY_AES_KEY 0xAA.[...],0xBD
EEPROM configuration:
SOFT_HMAC_KEY | 3FAAAAAAAAAAAAAAAAAAAAAAAAAAAA
SOFT_SERIAL | BBBBBBBBBBBBBBB
AES_KEY | CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCBD
--------------------------------
Personalization is now complete.

Otteniamo la risposta sia in formato piano che in formato binario. Salviamo su un documento di testo questi dati, perchè ci serviranno! Prestiamo attenzione anche a non confonderli tra i vari nodi, eventualmente creiamo un file di testo diverso per ogni singolo nodo.

Di seguito lo script completo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad &lt;henrik.ekblad@mysensors.org&gt;
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*******************************
*/
/**
* @ingroup MySigninggrp
* @{
* @file SecurityPersonalizer.ino
* @brief Security personalization sketch
*
* REVISION HISTORY
* - See git log (git log libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino)
*/

/**
* @example SecurityPersonalizer.ino
* This sketch will personalize either none-volatile memory or ATSHA204A for security functions
* available in the MySensors library.
*
* For ATSHA204A:
* It will write factory default settings to the configuration zone
* and then lock it.&lt;br&gt;
* It will then either&lt;br&gt;
* -# Generate a random value to use as a key which will be stored in
* slot 0. The key is printed on UART (115200) in clear text for the user to be
* able to use it as a user-supplied key in other personalization executions
* where the same key is needed.
* -# Use a user-supplied value to use as a key which will be stored in
* slot 0.
* Finally it will lock the data zone.
*
* By default, no locking is performed. User have to manually enable the flags that
* turn on the locking. Furthermore, user have to send a SPACE character on serial
* console when prompted to do any locking. On boards that does not provide UART
* input it is possible to configure the sketch to skip this confirmation.
* Default settings use ATSHA204A on @ref MY_SIGNING_ATSHA204_PIN.
*
* For Soft signing:
* It will&lt;br&gt;
* -# Generate a random value to use as a key which will be stored in EEPROM.
* The key is printed on UART (115200) in clear text for the user to be ablle to
* use it as a user-supplied key in other personalization executions where the same
* key is needed.
* -# Use a user-supplied value to use as a key which will be stored in EEPROM.
* -# Generate a random value to use as a serial number which will be stored in EEPROM.
* The serial number is printed on UART (115200) in clear text for the user to be ablle to
* use it as a user-supplied serial number in other personalization executions where the
* serial is needed (typically for a whitelist).
* -# Use a user-supplied value to use as a serial which will be stored in EEPROM.
*
* For Encryption support:
* -# Generate a random value to use as a AES key which will be stored in EEPROM.
* The AES key is printed on UART (115200) in clear text for the user to be ablle to
* use it as a user-supplied AES key in other personalization executions where the
* AES key is needed (typically for RF encryption).
* -# Use a user-supplied value to use as a AES key which will be stored in EEPROM.
*
* Personalizing EEPROM or ATSHA204A still require the appropriate configuration of the
* library to actually have an effect. There is no problem personalizing EEPROM and
* ATSHA204A at the same time. There is however a security risk with using the same
* data for EEPROM and ATSHA204A so it is recommended to use different serial and HMAC
* keys on the same device for ATSHA204A vs soft signing settings.
*
* Details on personalization procedure is given in @ref personalization.
*/

#include "sha204_library.h"
#include "sha204_lib_return_codes.h"
#define MY_CORE_ONLY
#include &lt;MySensors.h&gt;

// Doxygen specific constructs, not included when built normally
// This is used to enable disabled macros/definitions to be included in the documentation as well.
#if DOXYGEN
#define LOCK_CONFIGURATION
#define LOCK_DATA
#define SKIP_KEY_STORAGE
#define USER_KEY
#define SKIP_UART_CONFIRMATION
#define USE_SOFT_SIGNING
#define STORE_SOFT_KEY
#define USER_SOFT_KEY
#define STORE_SOFT_SERIAL
#define USER_SOFT_SERIAL
#define STORE_AES_KEY
#define USER_AES_KEY
#endif

/**
* @def LOCK_CONFIGURATION
* @brief Uncomment this to enable locking the configuration zone.
*
* It is still possible to change the key, and this also enable random key generation.
* @warning BE AWARE THAT THIS PREVENTS ANY FUTURE CONFIGURATION CHANGE TO THE CHIP
*/
//#define LOCK_CONFIGURATION

/**
* @def LOCK_DATA
* @brief Uncomment this to enable locking the data zone.
*
* It is not required to lock data, key cannot be retrieved anyway, but by locking
* data, it can be guaranteed that nobody even with physical access to the chip,
* will be able to change the key.
* @warning BE AWARE THAT THIS PREVENTS THE KEY TO BE CHANGED
*/
//#define LOCK_DATA

/**
* @def SKIP_KEY_STORAGE
* @brief Uncomment this to skip key storage (typically once key has been written once)
*/
//#define SKIP_KEY_STORAGE

/**
* @def USER_KEY
* @brief Uncomment this to skip key generation and use @ref user_key_data as key instead.
*/
//#define USER_KEY

/**
* @def SKIP_UART_CONFIRMATION
* @brief Uncomment this for boards that lack UART
*
* @b Important&lt;br&gt; No confirmation will be required for locking any zones with this configuration!
* Also, key generation is not permitted in this mode as there is no way of presenting the generated key.
*/
//#define SKIP_UART_CONFIRMATION

/**
* @def USE_SOFT_SIGNING
* @brief Uncomment this to store data to EEPROM instead of ATSHA204A
*/
#define USE_SOFT_SIGNING

/**
* @def STORE_SOFT_KEY
* @brief Uncomment this to store soft HMAC key to EEPROM
*/
#define STORE_SOFT_KEY

/**
* @def USER_SOFT_KEY
* @brief Uncomment this to skip soft HMAC key generation and use @ref user_soft_key_data as HMAC key instead.
*/
//#define USER_SOFT_KEY

/**
* @def STORE_SOFT_SERIAL
* @brief Uncomment this to store soft serial to EEPROM
*/
#define STORE_SOFT_SERIAL

/**
* @def USER_SOFT_SERIAL
* @brief Uncomment this to skip soft serial generation and use @ref user_soft_serial as serial instead.
*/
//#define USER_SOFT_SERIAL

/**
* @def STORE_AES_KEY
* @brief Uncomment this to store AES key to EEPROM
*/
#define STORE_AES_KEY

/**
* @def USER_AES_KEY
* @brief Uncomment this to skip AES key generation and use @ref user_aes_key as key instead.
*/
//#define USER_AES_KEY

#if defined(SKIP_UART_CONFIRMATION) &amp;&amp; !defined(USER_KEY)
#error You have to define USER_KEY for boards that does not have UART
#endif

#ifdef USER_KEY
/** @brief The user-defined HMAC key to use for personalization */
#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/** @brief The data to store in key slot 0 */
const uint8_t user_key_data[32] = {MY_HMAC_KEY};
#endif

#ifdef USER_SOFT_KEY
/** @brief The user-defined soft HMAC key to use for EEPROM personalization */
#define MY_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/** @brief The data to store as soft HMAC key in EEPROM */
const uint8_t user_soft_key_data[32] = {MY_SOFT_HMAC_KEY};
#endif

#ifdef USER_SOFT_SERIAL
/** @brief The user-defined soft serial to use for EEPROM personalization */
#define MY_SOFT_SERIAL 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/** @brief The data to store as soft serial in EEPROM */
const uint8_t user_soft_serial[9] = {MY_SOFT_SERIAL};
#endif

#ifdef USER_AES_KEY
/** @brief The user-defined AES key to use for EEPROM personalization */
#define MY_AES_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/** @brief The data to store as AES key in EEPROM */
const uint8_t user_aes_key[16] = {MY_AES_KEY};
#endif

#ifndef USE_SOFT_SIGNING
const int sha204Pin = MY_SIGNING_ATSHA204_PIN; //!&lt; The IO pin to use for ATSHA204A
atsha204Class sha204(sha204Pin);
#endif

/** @brief Print a error notice and halt the execution */
void halt()
{
Serial.println(F("Halting!"));
while(1);
}

#ifndef USE_SOFT_SIGNING
/**
* @brief Write default configuration and return CRC of the configuration bits
* @returns CRC over the configuration bits
*/
uint16_t write_config_and_get_crc()
{
uint16_t crc = 0;
uint8_t config_word[4];
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
bool do_write;

// We will set default settings from datasheet on all slots. This means that we can use slot 0 for the key
// as that slot will not be readable (key will therefore be secure) and slot 8 for the payload digest
// calculationon as that slot can be written in clear text even when the datazone is locked.
// Other settings which are not relevant are kept as is.

for (int i=0; i &lt; 88; i += 4) {
do_write = true;
if (i == 20) {
config_word[0] = 0x8F;
config_word[1] = 0x80;
config_word[2] = 0x80;
config_word[3] = 0xA1;
} else if (i == 24) {
config_word[0] = 0x82;
config_word[1] = 0xE0;
config_word[2] = 0xA3;
config_word[3] = 0x60;
} else if (i == 28) {
config_word[0] = 0x94;
config_word[1] = 0x40;
config_word[2] = 0xA0;
config_word[3] = 0x85;
} else if (i == 32) {
config_word[0] = 0x86;
config_word[1] = 0x40;
config_word[2] = 0x87;
config_word[3] = 0x07;
} else if (i == 36) {
config_word[0] = 0x0F;
config_word[1] = 0x00;
config_word[2] = 0x89;
config_word[3] = 0xF2;
} else if (i == 40) {
config_word[0] = 0x8A;
config_word[1] = 0x7A;
config_word[2] = 0x0B;
config_word[3] = 0x8B;
} else if (i == 44) {
config_word[0] = 0x0C;
config_word[1] = 0x4C;
config_word[2] = 0xDD;
config_word[3] = 0x4D;
} else if (i == 48) {
config_word[0] = 0xC2;
config_word[1] = 0x42;
config_word[2] = 0xAF;
config_word[3] = 0x8F;
} else if (i == 52 || i == 56 || i == 60 || i == 64) {
config_word[0] = 0xFF;
config_word[1] = 0x00;
config_word[2] = 0xFF;
config_word[3] = 0x00;
} else if (i == 68 || i == 72 || i == 76 || i == 80) {
config_word[0] = 0xFF;
config_word[1] = 0xFF;
config_word[2] = 0xFF;
config_word[3] = 0xFF;
} else {
// All other configs are untouched
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to read config. Response: "));
Serial.println(ret_code, HEX);
halt();
}
// Set config_word to the read data
config_word[0] = rx_buffer[SHA204_BUFFER_POS_DATA+0];
config_word[1] = rx_buffer[SHA204_BUFFER_POS_DATA+1];
config_word[2] = rx_buffer[SHA204_BUFFER_POS_DATA+2];
config_word[3] = rx_buffer[SHA204_BUFFER_POS_DATA+3];
do_write = false;
}

// Update crc with CRC for the current word
crc = sha204.calculateAndUpdateCrc(4, config_word, crc);

// Write config word
if (do_write) {
ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_CONFIG,
i &gt;&gt; 2, 4, config_word, 0, NULL, 0, NULL,
WRITE_COUNT_SHORT, tx_buffer, WRITE_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to write config word at address "));
Serial.print(i);
Serial.print(F(". Response: "));
Serial.println(ret_code, HEX);
halt();
}
}
}
return crc;
}

/**
* @brief Write provided key to slot 0
* @param key The key data to write
*/
void write_key(uint8_t* key)
{
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;

// Write key to slot 0
ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG,
0, SHA204_ZONE_ACCESS_32, key, 0, NULL, 0, NULL,
WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to write key to slot 0. Response: "));
Serial.println(ret_code, HEX);
halt();
}
}
#endif // not USE_SOFT_SIGNING

/** @brief Dump current configuration to UART */
void dump_configuration()
{
uint8_t buffer[32];
#ifndef USE_SOFT_SIGNING
Serial.println(F("EEPROM DATA:"));
#endif
hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
Serial.print(F("SOFT_HMAC_KEY | "));
for (int j=0; j&lt;32; j++) {
if (buffer[j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(buffer[j], HEX);
}
Serial.println();
hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
Serial.print(F("SOFT_SERIAL | "));
for (int j=0; j&lt;9; j++) {
if (buffer[j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(buffer[j], HEX);
}
Serial.println();
hwReadConfigBlock((void*)buffer, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
Serial.print(F("AES_KEY | "));
for (int j=0; j&lt;16; j++) {
if (buffer[j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(buffer[j], HEX);
}
Serial.println();
#ifndef USE_SOFT_SIGNING
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
Serial.println(F("ATSHA204A DATA:"));
for (int i=0; i &lt; 88; i += 4) {
//ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to read config. Response: "));
Serial.println(ret_code, HEX);
halt();
}
if (i == 0x00) {
Serial.print(F(" SN[0:1] | SN[2:3] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x04) {
Serial.print(F(" Revnum | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x08) {
Serial.print(F(" SN[4:7] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x0C) {
Serial.print(F(" SN[8] | Reserved13 | I2CEnable | Reserved15 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x10) {
Serial.print(F(" I2CAddress | TempOffset | OTPmode | SelectorMode | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x14) {
Serial.print(F(" SlotConfig00 | SlotConfig01 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x18) {
Serial.print(F(" SlotConfig02 | SlotConfig03 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x1C) {
Serial.print(F(" SlotConfig04 | SlotConfig05 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x20) {
Serial.print(F(" SlotConfig06 | SlotConfig07 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x24) {
Serial.print(F(" SlotConfig08 | SlotConfig09 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x28) {
Serial.print(F(" SlotConfig0A | SlotConfig0B | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x2C) {
Serial.print(F(" SlotConfig0C | SlotConfig0D | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x30) {
Serial.print(F(" SlotConfig0E | SlotConfig0F | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x34) {
Serial.print(F(" UseFlag00 | UpdateCount00 | UseFlag01 | UpdateCount01 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x38) {
Serial.print(F(" UseFlag02 | UpdateCount02 | UseFlag03 | UpdateCount03 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x3C) {
Serial.print(F(" UseFlag04 | UpdateCount04 | UseFlag05 | UpdateCount05 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x40) {
Serial.print(F(" UseFlag06 | UpdateCount06 | UseFlag07 | UpdateCount07 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x44) {
Serial.print(F(" LastKeyUse[0:3] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x48) {
Serial.print(F(" LastKeyUse[4:7] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x4C) {
Serial.print(F(" LastKeyUse[8:B] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x50) {
Serial.print(F(" LastKeyUse[C:F] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x54) {
Serial.print(F(" UserExtra | Selector | LockValue | LockConfig | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
}
}
#endif // not USE_SOFT_SIGNING
}

/** @brief Sketch setup code */
void setup()
{
// Delay startup a bit for serial consoles to catch up
unsigned long enter = hwMillis();
while (hwMillis() - enter &lt; (unsigned long)500);
#ifndef USE_SOFT_SIGNING
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
uint8_t lockConfig = 0;
uint8_t lockValue = 0;
uint16_t crc;
(void)crc;
#else
// initialize pseudo-RNG
randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN));
#endif
uint8_t key[32];
(void)key;

Serial.begin(115200);
hwInit();
Serial.println(F("Personalization sketch for MySensors usage."));
Serial.println(F("-------------------------------------------"));

#ifndef USE_SOFT_SIGNING
// Wake device before starting operations
//ret_code = sha204.sha204c_wakeup(rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to wake device. Response: "));
Serial.println(ret_code, HEX);
halt();
}
// Read out lock config bits to determine if locking is possible
//ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15&lt;&lt;2);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to determine device lock status. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
#endif

#ifdef STORE_SOFT_KEY
#ifdef USER_SOFT_KEY
memcpy(key, user_soft_key_data, 32);
Serial.println(F("Using this user supplied soft HMAC key:"));
#else
// Retrieve random value to use as soft HMAC key
#ifdef USE_SOFT_SIGNING
for (int i = 0; i &lt; 32; i++) {
key[i] = random(256) ^ micros();
unsigned long enter = hwMillis();
while (hwMillis() - enter &lt; (unsigned long)2);
}
Serial.println(F("This value will be stored in EEPROM as soft HMAC key:"));
#else
ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Random key generation failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32);
}
if (lockConfig == 0x00) {
Serial.println(F("This value will be stored in EEPROM as soft HMAC key:"));
} else {
Serial.println(F("Key is not randomized (configuration not locked):"));
}
#endif // not USE_SOFT_SIGNING
#endif // not USER_SOFT_KEY
Serial.print("#define MY_SOFT_HMAC_KEY ");
for (int i=0; i&lt;32; i++) {
Serial.print("0x");
if (key[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
if (i &lt; 31) {
Serial.print(',');
}
}
Serial.println();
hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
#endif // STORE_SOFT_KEY

#ifdef STORE_SOFT_SERIAL
#ifdef USER_SOFT_SERIAL
memcpy(key, user_soft_serial, 9);
Serial.println(F("Using this user supplied soft serial:"));
#else
// Retrieve random value to use as serial
#ifdef USE_SOFT_SIGNING
for (int i = 0; i &lt; 9; i++) {
key[i] = random(256) ^ micros();
unsigned long enter = hwMillis();
while (hwMillis() - enter &lt; (unsigned long)2);
}
Serial.println(F("This value will be stored in EEPROM as soft serial:"));
#else
ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Random serial generation failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 9);
}
if (lockConfig == 0x00) {
Serial.println(F("This value will be stored in EEPROM as soft serial:"));
} else {
Serial.println(F("Serial is not randomized (configuration not locked):"));
}
#endif // not USE_SOFT_SIGNING
#endif // not USER_SOFT_SERIAL
Serial.print("#define MY_SOFT_SERIAL ");
for (int i=0; i&lt;9; i++) {
Serial.print("0x");
if (key[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
if (i &lt; 8) {
Serial.print(',');
}
}
Serial.println();
hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
#endif // STORE_SOFT_SERIAL

#ifdef STORE_AES_KEY
#ifdef USER_AES_KEY
memcpy(key, user_aes_key, 16);
Serial.println(F("Using this user supplied AES key:"));
#else
// Retrieve random value to use as key
#ifdef USE_SOFT_SIGNING
for (int i = 0; i &lt; 16; i++) {
key[i] = random(256) ^ micros();
unsigned long enter = hwMillis();
while (hwMillis() - enter &lt; (unsigned long)2);
}
Serial.println(F("This key will be stored in EEPROM as AES key:"));
#else
ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Random key generation failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32);
}
if (lockConfig == 0x00) {
Serial.println(F("This key will be stored in EEPROM as AES key:"));
} else {
Serial.println(F("Key is not randomized (configuration not locked):"));
}
#endif // not USE_SOFT_SIGNING
#endif // not USER_AES_KEY
Serial.print("#define MY_AES_KEY ");
for (int i=0; i&lt;16; i++) {
Serial.print("0x");
if (key[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
if (i &lt; 15) {
Serial.print(',');
}
}
Serial.println();
hwWriteConfigBlock((void*)key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
#endif // STORE_AES_KEY

#ifdef USE_SOFT_SIGNING
Serial.println(F("EEPROM configuration:"));
dump_configuration();
#else
// Output device revision on console
//ret_code = sha204.sha204m_dev_rev(tx_buffer, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to determine device revision. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
Serial.print(F("Device revision: "));
for (int i=0; i&lt;4; i++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+i], HEX);
}
Serial.println();
}

// Output serial number on console
//ret_code = sha204.getSerialNumber(rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to obtain device serial number. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
Serial.print(F("Device serial: "));
Serial.print('{');
for (int i=0; i&lt;9; i++) {
Serial.print(F("0x"));
if (rx_buffer[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[i], HEX);
if (i &lt; 8) {
Serial.print(',');
}
}
Serial.print('}');
Serial.println();
for (int i=0; i&lt;9; i++) {
if (rx_buffer[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[i], HEX);
}
Serial.println();
}

if (lockConfig != 0x00) {
// Write config and get CRC for the updated config
crc = write_config_and_get_crc();

// List current configuration before attempting to lock
Serial.println(F("Chip configuration:"));
dump_configuration();

#ifdef LOCK_CONFIGURATION
// Purge serial input buffer
#ifndef SKIP_UART_CONFIRMATION
while (Serial.available()) {
Serial.read();
}
Serial.println(F("Send SPACE character now to lock the configuration..."));

while (Serial.available() == 0);
if (Serial.read() == ' ')
#endif //not SKIP_UART_CONFIRMATION
{
Serial.println(F("Locking configuration..."));

// Correct sequence, resync chip
ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer);
if (ret_code != SHA204_SUCCESS &amp;&amp; ret_code != SHA204_RESYNC_WITH_WAKEUP) {
Serial.print(F("Resync failed. Response: "));
Serial.println(ret_code, HEX);
halt();
}

// Lock configuration zone
ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_CONFIG,
crc, 0, NULL, 0, NULL, 0, NULL,
LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Configuration lock failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
Serial.println(F("Configuration locked."));

// Update lock flags after locking
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15&lt;&lt;2);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to determine device lock status. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
}
}
#ifndef SKIP_UART_CONFIRMATION
else {
Serial.println(F("Unexpected answer. Skipping lock."));
}
#endif //not SKIP_UART_CONFIRMATION
#else //LOCK_CONFIGURATION
Serial.println(F("Configuration not locked. Define LOCK_CONFIGURATION to lock for real."));
#endif
} else {
Serial.println(F("Skipping configuration write and lock (configuration already locked)."));
Serial.println(F("Chip configuration:"));
dump_configuration();
}

#ifdef SKIP_KEY_STORAGE
Serial.println(F("Disable SKIP_KEY_STORAGE to store key."));
#else
#ifdef USER_KEY
memcpy(key, user_key_data, 32);
Serial.println(F("Using this user supplied HMAC key:"));
#else
// Retrieve random value to use as key
//ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Random key generation failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32);
}
if (lockConfig == 0x00) {
Serial.println(F("Take note of this key, it will never be the shown again:"));
} else {
Serial.println(F("Key is not randomized (configuration not locked):"));
}
#endif
Serial.print("#define MY_HMAC_KEY ");
for (int i=0; i&lt;32; i++) {
Serial.print("0x");
if (key[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
if (i &lt; 31) {
Serial.print(',');
}
if (i+1 == 16) {
Serial.print("\\\n ");
}
}
Serial.println();

// It will not be possible to write the key if the configuration zone is unlocked
if (lockConfig == 0x00) {
// Write the key to the appropriate slot in the data zone
Serial.println(F("Writing key to slot 0..."));
write_key(key);
} else {
Serial.println(F("Skipping key storage (configuration not locked)."));
Serial.println(F("The configuration must be locked to be able to write a key."));
}
#endif

if (lockValue != 0x00) {
#ifdef LOCK_DATA
#ifndef SKIP_UART_CONFIRMATION
while (Serial.available()) {
Serial.read();
}
Serial.println(F("Send SPACE character to lock data..."));
while (Serial.available() == 0);
if (Serial.read() == ' ')
#endif //not SKIP_UART_CONFIRMATION
{
// Correct sequence, resync chip
ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer);
if (ret_code != SHA204_SUCCESS &amp;&amp; ret_code != SHA204_RESYNC_WITH_WAKEUP) {
Serial.print(F("Resync failed. Response: "));
Serial.println(ret_code, HEX);
halt();
}

// If configuration is unlocked, key is not updated. Locking data in this case will cause
// slot 0 to contain an unknown (or factory default) key, and this is in practically any
// usecase not the desired behaviour, so ask for additional confirmation in this case.
if (lockConfig != 0x00) {
while (Serial.available()) {
Serial.read();
}
Serial.println(F("*** ATTENTION ***"));
Serial.println(F("Configuration is not locked. Are you ABSULOUTELY SURE you want to lock data?"));
Serial.println(F("Locking data at this stage will cause slot 0 to contain a factory default key"));
Serial.println(
F("which cannot be change after locking is done. This is in practically any usecase"));
Serial.println(F("NOT the desired behavour. Send SPACE character now to lock data anyway..."));
while (Serial.available() == 0);
if (Serial.read() != ' ') {
Serial.println(F("Unexpected answer. Skipping lock."));
halt();
}
}

// Lock data zone
ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_DATA | LOCK_ZONE_NO_CRC,
0x0000, 0, NULL, 0, NULL, 0, NULL,
LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Data lock failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
Serial.println(F("Data locked."));

// Update lock flags after locking
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15&lt;&lt;2);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to determine device lock status. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
}
}
#ifndef SKIP_UART_CONFIRMATION
else {
Serial.println(F("Unexpected answer. Skipping lock."));
}
#endif //not SKIP_UART_CONFIRMATION
#else //LOCK_DATA
Serial.println(F("Data not locked. Define LOCK_DATA to lock for real."));
#endif
} else {
Serial.println(F("Skipping OTP/data zone lock (zone already locked)."));
}
#endif // not USE_SOFT_SIGNING

Serial.println(F("--------------------------------"));
Serial.println(F("Personalization is now complete."));
#ifndef USE_SOFT_SIGNING
Serial.print(F("Configuration is "));
if (lockConfig == 0x00) {
Serial.println("LOCKED");
} else {
Serial.println("UNLOCKED");
}
Serial.print(F("Data is "));
if (lockValue == 0x00) {
Serial.println("LOCKED");
} else {
Serial.println("UNLOCKED");
}
#endif
}

/** @brief Sketch execution code */
void loop()
{
}

Mysensors: sicurezza e criptazione dati tra nodi e gateway

Mysensors criptazione dati

Mysensors: sicurezza dei dati

Questo è l’articolo numero 1 di una serie totale di 3 articoli su “MySensors e criptazione dati”

Articolo 2: Leggi

Finchè usiamo Mysensors per scambiare dati tra temperatura, umidità etc non c’è sicuramente un bisogno impellente di proteggere la nostra rete fatta di sensori.

Ma nel momento in cui aggiungiamo nodi fatti da relè – e per chi ci si avventura anche per aperture porte, garage… – oppure da sensori di allarme diventa estremamente importante far si che ogni nodo possa rispondere soltanto al nostro gateway Arduino autorizzato e non ad altri.

La procedura per mettere in sicurezza i nostri nodi non è complessa, ma è composta da alcuni passaggi fondamentali, che dividerò su più articoli.

Sicurezza Mysensors: i passi da fare

Lo sketch da utilizzare per ogni passaggio è esattamente lo stesso; basta definire (un-commentare!) alcune istruzioni e lo sketch si comporterà di conseguenza.

I passaggi sono questi, in linea generale:

  1. Verificare che il nodo o il gateway non contengano già nella EEPROM una configurazione valida (magari precedenti esperimenti; nel caso la sovrascriveremo);
  2. Generare SOLO LA PRIMA VOLTA due chiavi che avremo cura di annotare perchè serviranno per ogni singolo nodo da aggiungere:
    1. SOFT_HMAC_KEY
    2. AES_KEY
  3. Lo sketch si occupa anche di generare un indirizzo seriale univoco. Anche questo va trascritto nel caso in cui si utilizzi la funzionalità di whitelist.
  4. Inserire nello sketch le due chiavi (consiglio di salvare questo sketch con un altro nome, cosicchè per aggiungere un nuovo nodo ci metteremo pochissimi secondi) e far generare in automatico un indirizzo seriale
  5. Riverificare – punto 1 – che il nodo ora abbia le nostre chiavi ed un indirizzo univoco.

Tutte queste stringhe come detto sono salvate all’interno della EEPROM. Noi dobbiamo:

  1. Uploadare ed eseguire gli sketch per la sicurezza / configurazione
  2. Fatto questo uplodare lo sketch “definitivo”

Mysensors: verificare configurazione EEPROM di sicurezza

Questo è il primo passaggio. Usiamo lo sketch presente alla pagina https://github.com/mysensors/MySensors/blob/master/examples/SecurityPersonalizer/SecurityPersonalizer.ino che come notate ha solamente definito

#define SKIP_KEY_STORAGE

nome semantico per dire di non salvare al momento nulla.

Dobbiamo solo abilitare

#define SOFT_KEY_SIGNING

e lo sketch stamperà nel monitor seriale l’attuale configurazione leggendola dalla EEPROM.

Di seguito ecco lo sketch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
/*
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad &lt;henrik.ekblad@mysensors.org&gt;
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*******************************
*/
/**
* @ingroup MySigninggrp
* @{
* @file SecurityPersonalizer.ino
* @brief Security personalization sketch
*
* REVISION HISTORY
* - See git log (git log libraries/MySensors/examples/SecurityPersonalizer/SecurityPersonalizer.ino)
*/

/**
* @example SecurityPersonalizer.ino
* This sketch will personalize either none-volatile memory or ATSHA204A for security functions
* available in the MySensors library.
*
* For ATSHA204A:
* It will write factory default settings to the configuration zone
* and then lock it.&lt;br&gt;
* It will then either&lt;br&gt;
* -# Generate a random value to use as a key which will be stored in
* slot 0. The key is printed on UART (115200) in clear text for the user to be
* able to use it as a user-supplied key in other personalization executions
* where the same key is needed.
* -# Use a user-supplied value to use as a key which will be stored in
* slot 0.
* Finally it will lock the data zone.
*
* By default, no locking is performed. User have to manually enable the flags that
* turn on the locking. Furthermore, user have to send a SPACE character on serial
* console when prompted to do any locking. On boards that does not provide UART
* input it is possible to configure the sketch to skip this confirmation.
* Default settings use ATSHA204A on @ref MY_SIGNING_ATSHA204_PIN.
*
* For Soft signing:
* It will&lt;br&gt;
* -# Generate a random value to use as a key which will be stored in EEPROM.
* The key is printed on UART (115200) in clear text for the user to be ablle to
* use it as a user-supplied key in other personalization executions where the same
* key is needed.
* -# Use a user-supplied value to use as a key which will be stored in EEPROM.
* -# Generate a random value to use as a serial number which will be stored in EEPROM.
* The serial number is printed on UART (115200) in clear text for the user to be ablle to
* use it as a user-supplied serial number in other personalization executions where the
* serial is needed (typically for a whitelist).
* -# Use a user-supplied value to use as a serial which will be stored in EEPROM.
*
* For Encryption support:
* -# Generate a random value to use as a AES key which will be stored in EEPROM.
* The AES key is printed on UART (115200) in clear text for the user to be ablle to
* use it as a user-supplied AES key in other personalization executions where the
* AES key is needed (typically for RF encryption).
* -# Use a user-supplied value to use as a AES key which will be stored in EEPROM.
*
* Personalizing EEPROM or ATSHA204A still require the appropriate configuration of the
* library to actually have an effect. There is no problem personalizing EEPROM and
* ATSHA204A at the same time. There is however a security risk with using the same
* data for EEPROM and ATSHA204A so it is recommended to use different serial and HMAC
* keys on the same device for ATSHA204A vs soft signing settings.
*
* Details on personalization procedure is given in @ref personalization.
*/

#include "sha204_library.h"
#include "sha204_lib_return_codes.h"
#define MY_CORE_ONLY
#include &lt;MySensors.h&gt;

// Doxygen specific constructs, not included when built normally
// This is used to enable disabled macros/definitions to be included in the documentation as well.
#if DOXYGEN
#define LOCK_CONFIGURATION
#define LOCK_DATA
#define SKIP_KEY_STORAGE
#define USER_KEY
#define SKIP_UART_CONFIRMATION
#define USE_SOFT_SIGNING
#define STORE_SOFT_KEY
#define USER_SOFT_KEY
#define STORE_SOFT_SERIAL
#define USER_SOFT_SERIAL
#define STORE_AES_KEY
#define USER_AES_KEY
#endif

/**
* @def LOCK_CONFIGURATION
* @brief Uncomment this to enable locking the configuration zone.
*
* It is still possible to change the key, and this also enable random key generation.
* @warning BE AWARE THAT THIS PREVENTS ANY FUTURE CONFIGURATION CHANGE TO THE CHIP
*/
//#define LOCK_CONFIGURATION

/**
* @def LOCK_DATA
* @brief Uncomment this to enable locking the data zone.
*
* It is not required to lock data, key cannot be retrieved anyway, but by locking
* data, it can be guaranteed that nobody even with physical access to the chip,
* will be able to change the key.
* @warning BE AWARE THAT THIS PREVENTS THE KEY TO BE CHANGED
*/
//#define LOCK_DATA

/**
* @def SKIP_KEY_STORAGE
* @brief Uncomment this to skip key storage (typically once key has been written once)
*/
#define SKIP_KEY_STORAGE

/**
* @def USER_KEY
* @brief Uncomment this to skip key generation and use @ref user_key_data as key instead.
*/
//#define USER_KEY

/**
* @def SKIP_UART_CONFIRMATION
* @brief Uncomment this for boards that lack UART
*
* @b Important&lt;br&gt; No confirmation will be required for locking any zones with this configuration!
* Also, key generation is not permitted in this mode as there is no way of presenting the generated key.
*/
//#define SKIP_UART_CONFIRMATION

/**
* @def USE_SOFT_SIGNING
* @brief Uncomment this to store data to EEPROM instead of ATSHA204A
*/
#define USE_SOFT_SIGNING

/**
* @def STORE_SOFT_KEY
* @brief Uncomment this to store soft HMAC key to EEPROM
*/
//#define STORE_SOFT_KEY

/**
* @def USER_SOFT_KEY
* @brief Uncomment this to skip soft HMAC key generation and use @ref user_soft_key_data as HMAC key instead.
*/
//#define USER_SOFT_KEY

/**
* @def STORE_SOFT_SERIAL
* @brief Uncomment this to store soft serial to EEPROM
*/
//#define STORE_SOFT_SERIAL

/**
* @def USER_SOFT_SERIAL
* @brief Uncomment this to skip soft serial generation and use @ref user_soft_serial as serial instead.
*/
//#define USER_SOFT_SERIAL

/**
* @def STORE_AES_KEY
* @brief Uncomment this to store AES key to EEPROM
*/
//#define STORE_AES_KEY

/**
* @def USER_AES_KEY
* @brief Uncomment this to skip AES key generation and use @ref user_aes_key as key instead.
*/
//#define USER_AES_KEY

#if defined(SKIP_UART_CONFIRMATION) &amp;&amp; !defined(USER_KEY)
#error You have to define USER_KEY for boards that does not have UART
#endif

#ifdef USER_KEY
/** @brief The user-defined HMAC key to use for personalization */
#define MY_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/** @brief The data to store in key slot 0 */
const uint8_t user_key_data[32] = {MY_HMAC_KEY};
#endif

#ifdef USER_SOFT_KEY
/** @brief The user-defined soft HMAC key to use for EEPROM personalization */
#define MY_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/** @brief The data to store as soft HMAC key in EEPROM */
const uint8_t user_soft_key_data[32] = {MY_SOFT_HMAC_KEY};
#endif

#ifdef USER_SOFT_SERIAL
/** @brief The user-defined soft serial to use for EEPROM personalization */
#define MY_SOFT_SERIAL 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/** @brief The data to store as soft serial in EEPROM */
const uint8_t user_soft_serial[9] = {MY_SOFT_SERIAL};
#endif

#ifdef USER_AES_KEY
/** @brief The user-defined AES key to use for EEPROM personalization */
#define MY_AES_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
/** @brief The data to store as AES key in EEPROM */
const uint8_t user_aes_key[16] = {MY_AES_KEY};
#endif

#ifndef USE_SOFT_SIGNING
const int sha204Pin = MY_SIGNING_ATSHA204_PIN; //!&lt; The IO pin to use for ATSHA204A
atsha204Class sha204(sha204Pin);
#endif

/** @brief Print a error notice and halt the execution */
void halt()
{
Serial.println(F("Halting!"));
while(1);
}

#ifndef USE_SOFT_SIGNING
/**
* @brief Write default configuration and return CRC of the configuration bits
* @returns CRC over the configuration bits
*/
uint16_t write_config_and_get_crc()
{
uint16_t crc = 0;
uint8_t config_word[4];
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
bool do_write;

// We will set default settings from datasheet on all slots. This means that we can use slot 0 for the key
// as that slot will not be readable (key will therefore be secure) and slot 8 for the payload digest
// calculationon as that slot can be written in clear text even when the datazone is locked.
// Other settings which are not relevant are kept as is.

for (int i=0; i &lt; 88; i += 4) {
do_write = true;
if (i == 20) {
config_word[0] = 0x8F;
config_word[1] = 0x80;
config_word[2] = 0x80;
config_word[3] = 0xA1;
} else if (i == 24) {
config_word[0] = 0x82;
config_word[1] = 0xE0;
config_word[2] = 0xA3;
config_word[3] = 0x60;
} else if (i == 28) {
config_word[0] = 0x94;
config_word[1] = 0x40;
config_word[2] = 0xA0;
config_word[3] = 0x85;
} else if (i == 32) {
config_word[0] = 0x86;
config_word[1] = 0x40;
config_word[2] = 0x87;
config_word[3] = 0x07;
} else if (i == 36) {
config_word[0] = 0x0F;
config_word[1] = 0x00;
config_word[2] = 0x89;
config_word[3] = 0xF2;
} else if (i == 40) {
config_word[0] = 0x8A;
config_word[1] = 0x7A;
config_word[2] = 0x0B;
config_word[3] = 0x8B;
} else if (i == 44) {
config_word[0] = 0x0C;
config_word[1] = 0x4C;
config_word[2] = 0xDD;
config_word[3] = 0x4D;
} else if (i == 48) {
config_word[0] = 0xC2;
config_word[1] = 0x42;
config_word[2] = 0xAF;
config_word[3] = 0x8F;
} else if (i == 52 || i == 56 || i == 60 || i == 64) {
config_word[0] = 0xFF;
config_word[1] = 0x00;
config_word[2] = 0xFF;
config_word[3] = 0x00;
} else if (i == 68 || i == 72 || i == 76 || i == 80) {
config_word[0] = 0xFF;
config_word[1] = 0xFF;
config_word[2] = 0xFF;
config_word[3] = 0xFF;
} else {
// All other configs are untouched
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to read config. Response: "));
Serial.println(ret_code, HEX);
halt();
}
// Set config_word to the read data
config_word[0] = rx_buffer[SHA204_BUFFER_POS_DATA+0];
config_word[1] = rx_buffer[SHA204_BUFFER_POS_DATA+1];
config_word[2] = rx_buffer[SHA204_BUFFER_POS_DATA+2];
config_word[3] = rx_buffer[SHA204_BUFFER_POS_DATA+3];
do_write = false;
}

// Update crc with CRC for the current word
crc = sha204.calculateAndUpdateCrc(4, config_word, crc);

// Write config word
if (do_write) {
ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_CONFIG,
i &gt;&gt; 2, 4, config_word, 0, NULL, 0, NULL,
WRITE_COUNT_SHORT, tx_buffer, WRITE_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to write config word at address "));
Serial.print(i);
Serial.print(F(". Response: "));
Serial.println(ret_code, HEX);
halt();
}
}
}
return crc;
}

/**
* @brief Write provided key to slot 0
* @param key The key data to write
*/
void write_key(uint8_t* key)
{
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;

// Write key to slot 0
ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG,
0, SHA204_ZONE_ACCESS_32, key, 0, NULL, 0, NULL,
WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to write key to slot 0. Response: "));
Serial.println(ret_code, HEX);
halt();
}
}
#endif // not USE_SOFT_SIGNING

/** @brief Dump current configuration to UART */
void dump_configuration()
{
uint8_t buffer[32];
#ifndef USE_SOFT_SIGNING
Serial.println(F("EEPROM DATA:"));
#endif
hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
Serial.print(F("SOFT_HMAC_KEY | "));
for (int j=0; j&lt;32; j++) {
if (buffer[j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(buffer[j], HEX);
}
Serial.println();
hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
Serial.print(F("SOFT_SERIAL | "));
for (int j=0; j&lt;9; j++) {
if (buffer[j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(buffer[j], HEX);
}
Serial.println();
hwReadConfigBlock((void*)buffer, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
Serial.print(F("AES_KEY | "));
for (int j=0; j&lt;16; j++) {
if (buffer[j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(buffer[j], HEX);
}
Serial.println();
#ifndef USE_SOFT_SIGNING
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
Serial.println(F("ATSHA204A DATA:"));
for (int i=0; i &lt; 88; i += 4) {
//ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to read config. Response: "));
Serial.println(ret_code, HEX);
halt();
}
if (i == 0x00) {
Serial.print(F(" SN[0:1] | SN[2:3] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x04) {
Serial.print(F(" Revnum | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x08) {
Serial.print(F(" SN[4:7] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x0C) {
Serial.print(F(" SN[8] | Reserved13 | I2CEnable | Reserved15 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x10) {
Serial.print(F(" I2CAddress | TempOffset | OTPmode | SelectorMode | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x14) {
Serial.print(F(" SlotConfig00 | SlotConfig01 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x18) {
Serial.print(F(" SlotConfig02 | SlotConfig03 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x1C) {
Serial.print(F(" SlotConfig04 | SlotConfig05 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x20) {
Serial.print(F(" SlotConfig06 | SlotConfig07 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x24) {
Serial.print(F(" SlotConfig08 | SlotConfig09 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x28) {
Serial.print(F(" SlotConfig0A | SlotConfig0B | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x2C) {
Serial.print(F(" SlotConfig0C | SlotConfig0D | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x30) {
Serial.print(F(" SlotConfig0E | SlotConfig0F | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x34) {
Serial.print(F(" UseFlag00 | UpdateCount00 | UseFlag01 | UpdateCount01 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x38) {
Serial.print(F(" UseFlag02 | UpdateCount02 | UseFlag03 | UpdateCount03 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x3C) {
Serial.print(F(" UseFlag04 | UpdateCount04 | UseFlag05 | UpdateCount05 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x40) {
Serial.print(F(" UseFlag06 | UpdateCount06 | UseFlag07 | UpdateCount07 | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
} else if (i == 0x44) {
Serial.print(F(" LastKeyUse[0:3] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x48) {
Serial.print(F(" LastKeyUse[4:7] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x4C) {
Serial.print(F(" LastKeyUse[8:B] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x50) {
Serial.print(F(" LastKeyUse[C:F] | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
} else if (i == 0x54) {
Serial.print(F(" UserExtra | Selector | LockValue | LockConfig | "));
for (int j=0; j&lt;4; j++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j &lt; 3) {
Serial.print(F(" | "));
} else {
Serial.print(F(" "));
}
}
Serial.println();
}
}
#endif // not USE_SOFT_SIGNING
}

/** @brief Sketch setup code */
void setup()
{
// Delay startup a bit for serial consoles to catch up
unsigned long enter = hwMillis();
while (hwMillis() - enter &lt; (unsigned long)500);
#ifndef USE_SOFT_SIGNING
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
uint8_t lockConfig = 0;
uint8_t lockValue = 0;
uint16_t crc;
(void)crc;
#else
// initialize pseudo-RNG
randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN));
#endif
uint8_t key[32];
(void)key;

Serial.begin(115200);
hwInit();
Serial.println(F("Personalization sketch for MySensors usage."));
Serial.println(F("-------------------------------------------"));

#ifndef USE_SOFT_SIGNING
// Wake device before starting operations
//ret_code = sha204.sha204c_wakeup(rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to wake device. Response: "));
Serial.println(ret_code, HEX);
halt();
}
// Read out lock config bits to determine if locking is possible
//ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15&lt;&lt;2);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to determine device lock status. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
#endif

#ifdef STORE_SOFT_KEY
#ifdef USER_SOFT_KEY
memcpy(key, user_soft_key_data, 32);
Serial.println(F("Using this user supplied soft HMAC key:"));
#else
// Retrieve random value to use as soft HMAC key
#ifdef USE_SOFT_SIGNING
for (int i = 0; i &lt; 32; i++) {
key[i] = random(256) ^ micros();
unsigned long enter = hwMillis();
while (hwMillis() - enter &lt; (unsigned long)2);
}
Serial.println(F("This value will be stored in EEPROM as soft HMAC key:"));
#else
ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Random key generation failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32);
}
if (lockConfig == 0x00) {
Serial.println(F("This value will be stored in EEPROM as soft HMAC key:"));
} else {
Serial.println(F("Key is not randomized (configuration not locked):"));
}
#endif // not USE_SOFT_SIGNING
#endif // not USER_SOFT_KEY
Serial.print("#define MY_SOFT_HMAC_KEY ");
for (int i=0; i&lt;32; i++) {
Serial.print("0x");
if (key[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
if (i &lt; 31) {
Serial.print(',');
}
}
Serial.println();
hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
#endif // STORE_SOFT_KEY

#ifdef STORE_SOFT_SERIAL
#ifdef USER_SOFT_SERIAL
memcpy(key, user_soft_serial, 9);
Serial.println(F("Using this user supplied soft serial:"));
#else
// Retrieve random value to use as serial
#ifdef USE_SOFT_SIGNING
for (int i = 0; i &lt; 9; i++) {
key[i] = random(256) ^ micros();
unsigned long enter = hwMillis();
while (hwMillis() - enter &lt; (unsigned long)2);
}
Serial.println(F("This value will be stored in EEPROM as soft serial:"));
#else
ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Random serial generation failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 9);
}
if (lockConfig == 0x00) {
Serial.println(F("This value will be stored in EEPROM as soft serial:"));
} else {
Serial.println(F("Serial is not randomized (configuration not locked):"));
}
#endif // not USE_SOFT_SIGNING
#endif // not USER_SOFT_SERIAL
Serial.print("#define MY_SOFT_SERIAL ");
for (int i=0; i&lt;9; i++) {
Serial.print("0x");
if (key[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
if (i &lt; 8) {
Serial.print(',');
}
}
Serial.println();
hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
#endif // STORE_SOFT_SERIAL

#ifdef STORE_AES_KEY
#ifdef USER_AES_KEY
memcpy(key, user_aes_key, 16);
Serial.println(F("Using this user supplied AES key:"));
#else
// Retrieve random value to use as key
#ifdef USE_SOFT_SIGNING
for (int i = 0; i &lt; 16; i++) {
key[i] = random(256) ^ micros();
unsigned long enter = hwMillis();
while (hwMillis() - enter &lt; (unsigned long)2);
}
Serial.println(F("This key will be stored in EEPROM as AES key:"));
#else
ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Random key generation failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32);
}
if (lockConfig == 0x00) {
Serial.println(F("This key will be stored in EEPROM as AES key:"));
} else {
Serial.println(F("Key is not randomized (configuration not locked):"));
}
#endif // not USE_SOFT_SIGNING
#endif // not USER_AES_KEY
Serial.print("#define MY_AES_KEY ");
for (int i=0; i&lt;16; i++) {
Serial.print("0x");
if (key[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
if (i &lt; 15) {
Serial.print(',');
}
}
Serial.println();
hwWriteConfigBlock((void*)key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
#endif // STORE_AES_KEY

#ifdef USE_SOFT_SIGNING
Serial.println(F("EEPROM configuration:"));
dump_configuration();
#else
// Output device revision on console
//ret_code = sha204.sha204m_dev_rev(tx_buffer, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to determine device revision. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
Serial.print(F("Device revision: "));
for (int i=0; i&lt;4; i++) {
if (rx_buffer[SHA204_BUFFER_POS_DATA+i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+i], HEX);
}
Serial.println();
}

// Output serial number on console
//ret_code = sha204.getSerialNumber(rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to obtain device serial number. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
Serial.print(F("Device serial: "));
Serial.print('{');
for (int i=0; i&lt;9; i++) {
Serial.print(F("0x"));
if (rx_buffer[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[i], HEX);
if (i &lt; 8) {
Serial.print(',');
}
}
Serial.print('}');
Serial.println();
for (int i=0; i&lt;9; i++) {
if (rx_buffer[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[i], HEX);
}
Serial.println();
}

if (lockConfig != 0x00) {
// Write config and get CRC for the updated config
crc = write_config_and_get_crc();

// List current configuration before attempting to lock
Serial.println(F("Chip configuration:"));
dump_configuration();

#ifdef LOCK_CONFIGURATION
// Purge serial input buffer
#ifndef SKIP_UART_CONFIRMATION
while (Serial.available()) {
Serial.read();
}
Serial.println(F("Send SPACE character now to lock the configuration..."));

while (Serial.available() == 0);
if (Serial.read() == ' ')
#endif //not SKIP_UART_CONFIRMATION
{
Serial.println(F("Locking configuration..."));

// Correct sequence, resync chip
ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer);
if (ret_code != SHA204_SUCCESS &amp;&amp; ret_code != SHA204_RESYNC_WITH_WAKEUP) {
Serial.print(F("Resync failed. Response: "));
Serial.println(ret_code, HEX);
halt();
}

// Lock configuration zone
ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_CONFIG,
crc, 0, NULL, 0, NULL, 0, NULL,
LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Configuration lock failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
Serial.println(F("Configuration locked."));

// Update lock flags after locking
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15&lt;&lt;2);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to determine device lock status. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
}
}
#ifndef SKIP_UART_CONFIRMATION
else {
Serial.println(F("Unexpected answer. Skipping lock."));
}
#endif //not SKIP_UART_CONFIRMATION
#else //LOCK_CONFIGURATION
Serial.println(F("Configuration not locked. Define LOCK_CONFIGURATION to lock for real."));
#endif
} else {
Serial.println(F("Skipping configuration write and lock (configuration already locked)."));
Serial.println(F("Chip configuration:"));
dump_configuration();
}

#ifdef SKIP_KEY_STORAGE
Serial.println(F("Disable SKIP_KEY_STORAGE to store key."));
#else
#ifdef USER_KEY
memcpy(key, user_key_data, 32);
Serial.println(F("Using this user supplied HMAC key:"));
#else
// Retrieve random value to use as key
//ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Random key generation failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32);
}
if (lockConfig == 0x00) {
Serial.println(F("Take note of this key, it will never be the shown again:"));
} else {
Serial.println(F("Key is not randomized (configuration not locked):"));
}
#endif
Serial.print("#define MY_HMAC_KEY ");
for (int i=0; i&lt;32; i++) {
Serial.print("0x");
if (key[i] &lt; 0x10) {
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
if (i &lt; 31) {
Serial.print(',');
}
if (i+1 == 16) {
Serial.print("\\\n ");
}
}
Serial.println();

// It will not be possible to write the key if the configuration zone is unlocked
if (lockConfig == 0x00) {
// Write the key to the appropriate slot in the data zone
Serial.println(F("Writing key to slot 0..."));
write_key(key);
} else {
Serial.println(F("Skipping key storage (configuration not locked)."));
Serial.println(F("The configuration must be locked to be able to write a key."));
}
#endif

if (lockValue != 0x00) {
#ifdef LOCK_DATA
#ifndef SKIP_UART_CONFIRMATION
while (Serial.available()) {
Serial.read();
}
Serial.println(F("Send SPACE character to lock data..."));
while (Serial.available() == 0);
if (Serial.read() == ' ')
#endif //not SKIP_UART_CONFIRMATION
{
// Correct sequence, resync chip
ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer);
if (ret_code != SHA204_SUCCESS &amp;&amp; ret_code != SHA204_RESYNC_WITH_WAKEUP) {
Serial.print(F("Resync failed. Response: "));
Serial.println(ret_code, HEX);
halt();
}

// If configuration is unlocked, key is not updated. Locking data in this case will cause
// slot 0 to contain an unknown (or factory default) key, and this is in practically any
// usecase not the desired behaviour, so ask for additional confirmation in this case.
if (lockConfig != 0x00) {
while (Serial.available()) {
Serial.read();
}
Serial.println(F("*** ATTENTION ***"));
Serial.println(F("Configuration is not locked. Are you ABSULOUTELY SURE you want to lock data?"));
Serial.println(F("Locking data at this stage will cause slot 0 to contain a factory default key"));
Serial.println(
F("which cannot be change after locking is done. This is in practically any usecase"));
Serial.println(F("NOT the desired behavour. Send SPACE character now to lock data anyway..."));
while (Serial.available() == 0);
if (Serial.read() != ' ') {
Serial.println(F("Unexpected answer. Skipping lock."));
halt();
}
}

// Lock data zone
ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_DATA | LOCK_ZONE_NO_CRC,
0x0000, 0, NULL, 0, NULL, 0, NULL,
LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Data lock failed. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
Serial.println(F("Data locked."));

// Update lock flags after locking
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15&lt;&lt;2);
if (ret_code != SHA204_SUCCESS) {
Serial.print(F("Failed to determine device lock status. Response: "));
Serial.println(ret_code, HEX);
halt();
} else {
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
}
}
#ifndef SKIP_UART_CONFIRMATION
else {
Serial.println(F("Unexpected answer. Skipping lock."));
}
#endif //not SKIP_UART_CONFIRMATION
#else //LOCK_DATA
Serial.println(F("Data not locked. Define LOCK_DATA to lock for real."));
#endif
} else {
Serial.println(F("Skipping OTP/data zone lock (zone already locked)."));
}
#endif // not USE_SOFT_SIGNING

Serial.println(F("--------------------------------"));
Serial.println(F("Personalization is now complete."));
#ifndef USE_SOFT_SIGNING
Serial.print(F("Configuration is "));
if (lockConfig == 0x00) {
Serial.println("LOCKED");
} else {
Serial.println("UNLOCKED");
}
Serial.print(F("Data is "));
if (lockValue == 0x00) {
Serial.println("LOCKED");
} else {
Serial.println("UNLOCKED");
}
#endif
}

/** @brief Sketch execution code */
void loop()
{
}

Ed ecco il risultato finale. In questo caso il nodo è “vergine”, non ha alcuna configurazione e pertanto possiamo procedere – nel prossimo articolo – a generare delle chiavi uniche che ci salveremo.

1
2
3
4
5
6
7
8
Personalization sketch for MySensors usage.
-------------------------------------------
EEPROM configuration:
SOFT_HMAC_KEY | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
SOFT_SERIAL | FFFFFFFFFFFFFFFFFF
AES_KEY | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
--------------------------------
Personalization is now complete.

Domoticz + Raspberry PI + Arduino su USB

Arduino Raspberry tramite USB

Perchè Arduino collegato al Raspberry tramite USB?

Malgrado abbia riportato in precedenza una configurazione perfettamente funzionante (qui il vecchio post), non sono più riuscito a far funzionare su una nuova installazione il tutto (basta vedere sul forum di MySensors come malgrado abbia ricevuto qualche consiglio, non sia stato minimamente possibile replicare la mia installazione).

Dunque, nonostante il Raspberry PI v1 sia totalmente in grado di poter fare da gateway (MySensors) e controller (Domoticz), sono dovuto ricorrere ad un Arduino acquistato allo scopo connesso tramite porta USB al Raspberry stesso e sfruttare MySensors come Gateway USB.

Arduino su USB Raspberry

Fortunatamente in questo caso tutto è molto più facile, l’unico problema è il dover dedicare un Arduino intero a fare da gateway quando basterebbe il PI stesso, ma tant’è, prendiamo di buono che è sicuramente più veloce fare l’upload di uno sketch sull’Arduino che non una compilazione su PI.

Come sempre, elenco tutti i passi che ho fatto, al fine di ritrovare sempre facilmente una linea guida funzionante.

  1. Ho installato su una SD Raspbian Jessie Lite
    Version: June 2017
    Release date: 2017-06-21
    Kernel version:4.9
  2. Nella cartella di boot (l’unica leggibile da Windows dopo aver scritto l’immagine di Raspbian) ho copiato un file chiamato “ssh” vuoto e senza estensione, questo per poter abilitare subito la SSH e senza dover accendere la TV (per chi lo volesse, il file è disponibile a questo link, zippato: http://www.webtemplum.com/ssh)
  3. Ho fatto l’avvio dunque del Raspberry, atteso qualche secondo e connesso tramite Putty (sono su Windows) sulla SSH
  4. La prima cosa che ho fatto è mettere in sicurezza il Raspberry.  A breve un articolo dedicato ad hoc, cmq i passi sono i seguenti:
    1. Cambiare immediatamente la password di PI;
    2. Cambiare la porta alla SSH
    3. Creare nuovo utente con gli stessi privilegi di “pi”
    4. Cancellare completamente l’utente “pi”
    5. Attivare fail2ban per bannare i tentativi di accesso alla SSH
    6. Inibire il login da root su SSH
  5. Ho eseguito la configurazione base di raspi-config:
    1. Espandere il file system
    2. Impostare la timezone
    3. 1
      sudo apt-get update &amp;&amp; sudo apt-get upgrade

      Attenzione… sul mio povero PI ci ha messo oltre mezz’ora!

  6. Scaricare domoticz, nella modalità “easy”, la guida è sul loro sito: https://www.domoticz.com/wiki/Installing_and_running_Domoticz_on_a_Raspberry_PI
  7. Seguire le istruzioni a video per installare Domoticz
  8. Collegare alla fine Arduino tramite la porta USB (attenzione, Arduino deve avere già caricato lo sketch come gateway)
  9. Se tutto è andato per il meglio, nella voce MySensors Gateway USB dovreste trovare almeno due seriali, di cui una è Arduino – nel mio caso la ACM0

Arduino USB su Raspberry per Domoticz

Se avete già un nodo esistente in casa che sta trasmettendo, potete poi ad esempio “sniffare” la seriale di Arduino in maniera molto semplice, lascio il link all’altro articolo: Come leggere la seriale di Arduino tramite Raspberry

Posso assicurare che rispetto al primo tentativo di compilazione del gateway direttamente sul Raspberry, in questa maniera tutto è molto stabile e sopratutto facilissimo da implementare.

Come sempre, vi invito a lasciare le vostre esperienze qui nei commenti!

Come leggere la seriale di Arduino direttamente dal Raspberry

Leggere la seriale Arduino direttamente da Raspberry

Se come me avete connesso un Arduino direttamente alla porta USB di un Raspberry e volete leggere i messaggi che Arduino manda su monitor seriale (ad esempio, nel mio caso, Arduino funge da gateway per Domoticz ed i nodi basati su MySensors), il comando è semplicissimo:

1
sudo cat /dev/ttyAMA0

oppure, se avete Arduino su altra seriale

1
sudo cat /dev/ttyACM0

Facile facile.

Per uscire poi è sufficiente premere la combinazione CTRL+C

Arduino e Atmega come cambiare i fuse tramite IDE

Atmega328P-PU

Per diversi progetti di domotica (legati principalmente alla realizzazione di nodi per la rivelazione di temperatura ed altri sensori) volevo cambiare i fuse degli Atmega, sopratutto quello “Extended” per disabilitare il BOD.

Cosa sono i fuse

Su internet si trova moltissimo materiale, cito www.leonardomiliani.com:

I microcontrollori Atmel possiedono al loro interno alcuni registri che servono a modificare alcune caratteristiche particolari del microcontrollore, ad esempio le opzioni riguardanti il clock, l’area di memoria da riservare al bootloader, l’attivazione di circuiti interni quali il WatchDog (WD) o il Brown-out Detector (BOD), l’abilitazione del pin del reset ed altro ancora. Questi registri sono detti Fuse […]

(potete approfondire qui)

Cos’è il Brown-out Detector

Il Brown-out detector è quel particolare registro esteso che sostanzialmente fa resettare il nostro microcontroller se la tensione in ingresso è più bassa di una certa soglia. I chip vergini non contengono alcun bootloader ed è disabilitato di default, mentre quello che andiamo a flashare per Arduino li imposta, a mio avviso, molto conservativi. Citando sempre il link di cui sopra di www.leonardomiliani.com

Il microcontrollore può operare ad una tensione variabile che, nel caso dell’Atmega328P, può oscillare da un minimo di 1,8V ad un massimo di 5,5V. Anche la frequenza operativa è variabile, potendo oscillare fra 1 e 20 MHz. Esiste un problema: la stabilità. Più la frequenza sale di valore e più la tensione deve stare sopra ad una certa soglia per garantire la stabilità di funzionamento del microcontrollore […] Nell’Arduino il microcontrollore è impostato a 16 MHz: a tale frequenza, necessita di una tensione minima che si aggira intorno ai 4,5V. Per questo motivo, l’Arduino imposta un livello di BOD di 4,3V. I possibili libelli di BOD sono: 4,3 V (fuse “1-0-0” rispettivamente per BODLEVEL2..0), 2,7 V (fuse “1-0-1”) e 1,8 V (fuse “1-1-0”).

Dato che:

  1. 2 batterie stilo ricaricabili erogano circa 2.90 volt quando cariche
  2. A 2.90 volt il nostro Atmega, sopratutto se a 8MHZ non ha problemi

Ho deciso di disabilitare proprio la funzionalità. Cambierò le batterie prima che si scarichino completamente e che quindi scendano sotto ad una certa soglia.

Come modificare i fuse tramite IDE

Dobbiamo modificare il file boards.txt che si trova all’interno della nostra cartella di installazione Arduino IDE (se siete su Windows, il percorso dovrebbe essere

1
C:\Program Files (x86)\Arduino\hardware\arduino\avr

.

Vi do un consiglio: non modificate direttamente la board, in quanto un aggiornamento vi farebbe perdere tutte le modifiche.

Aprire l’IDE e nella pagina delle impostazioni (File > Impostazioni) inserite un nuovo percorso (io ad esempio salvo sempre nell’hard disk secondario)

Arduino IDE impostazioni

In questa cartella create un nuovo percorso:

1
D:\ARCHIVI\ARDUINO\hardware\breadboard\avr

ed in questo percorso salvate il bootloader per l’Arduino a 8 Mhz (istruzioni più dettagliate sul link ufficiale)

Ora modificare il file boards.txt che avete in questo secondo spazio, aggiungendo una nuova board che comunque punti al bootloader già presente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
##############################################################

atmega328bbnobod.name=ATmega328 Bare 8MHZ No BOD
atmega328bbnobod.upload.protocol=arduino
atmega328bbnobod.upload.maximum_size=30720
atmega328bbnobod.upload.speed=57600
atmega328bbnobod.bootloader.low_fuses=0xE2
atmega328bbnobod.bootloader.high_fuses=0xDA
atmega328bbnobod.bootloader.extended_fuses=0x07
atmega328bbnobod.bootloader.file=atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex
atmega328bbnobod.bootloader.unlock_bits=0x3F
atmega328bbnobod.bootloader.lock_bits=0x0F
atmega328bbnobod.build.mcu=atmega328p
atmega328bbnobod.build.f_cpu=8000000L
atmega328bbnobod.build.core=arduino:arduino
atmega328bbnobod.build.variant=arduino:standard
atmega328bbnobod.build.board = AVR_ATMEGA328BB
atmega328bbnobod.bootloader.tool=arduino:avrdude
atmega328bbnobod.upload.tool=arduino:avrdude

Non ho fatto altro che:

  1. Copiare tutte le righe della breadboard “ufficiale”
  2. Cambiare l’extended fuses a 0x07 che vuol dire “NO BOD”
  3. Cambiare il nome alla board dandone uno più accurato (ATmega328 Bare 8MHZ No BOD)

Una volta che scriveremo il bootloader, sarà scritto con i fuse che noi desideriamo.

Facile facile!

Avete già provato questa modalità? Fatemi sapere nei commenti!

 

Guadagnare ed aumentare spazio Dropbox con referral

Logo Dropbox

Sono un fan di Dropbox, lo ammetto.

La popolare soluzione cloud di storage vi permette di avere i file sempre con voi, nonchè la profonda integrazione con i cellulari permette di salvare automaticamente le foto scattate dentro di lui.

Lascio qui il mio link referral: se vi registrate seguendo questo link, sia voi che io guadagneremo entrambi 500 MB. Che sembrano pochini, però meglio di niente!

Link referral a Dropbox: https://db.tt/CcWugFwJ

Raspberry con NRF24L01+ come gateway MySensors per Domoticz

Raspberry NRF24L01 gateway MySensors

Riporto qui la mia configurazione testata, al momento in cui scrivo, da oltre 7 giorni, in cui utilizzo un Raspberry PI 1 Model B (quello per capirci con 2 porte USB, nessuna wifi e 26 GPIO) con un’antenna NRF24L01+.

Raspberry NRF24L01 gateway MySensors

Raspberry + NRF24L01 come gateway basato su MySensors

Il mio Raspberry è acceso 24 ore su 24, agisce come gateway e come controller, allo stesso tempo.

Più in dettaglio, il gateway è basato su MySensors (link alla pagina) mentre il controller (quindi il cuore ed il cervello del sistema) è basato su Domoticz (link)

Raspberry come gateway MySensors

La guida da seguire è esattamente questa qui, avendo però l’accortezza di lanciare solamente una volta il comando

1
./configure

(vedremo tra un attimo il tutto).

Gli esatti step che ho seguito sono i seguenti:

  1. Ho installato Raspbian Jessie LITE su una scheda SD (potete trovare le immagini ufficiali qui)
  2. Appena avviato il Raspberry, ho:
    1. Cambiato la password dell’utente
      1
      pi

      con il comando 

      1
      passwd
    2. Lanciato 
      1
      sudo raspi-config

       per:

      1. Attivare la SSH (così ho rilasciato la tv alla morosa)
      2. Espandere il filesystem
      3. Attivare SPI all’avvio
      4. Cambiare la timezone con Europe/Rome
  3. Lanciato
    1
    sudo apt-get update &amp;&amp; sudo apt-get install git -y

    al fine di aggiornare i componenti già installati ed installare successivamente git

  4. Clonato lo script di MySensors, al momento in cui scrivo (28/06/2017) quello funzionante sul mio Raspberry fa parte del branch development ed è la versione 2.2.0-beta 
    1
    git clone https://github.com/mysensors/MySensors.git --branch development
  5. Dopo che il comando git ha clonato lo script, entrare nella folder di MySensors con 
    1
    cd MySensors

A questo punto si può procedere a configurare il gateway, come dicevo all’inizio, lanciando una ed una sola volta il comando ./configure con tutte le opzioni che desideriamo.

Se leggete nel forum è capitato infatti (come è successo a me!) che alcuni non riuscivano a far partire il tutto perchè lanciavano ogni volta il comando ./configure. Ma il suo funzionamento è quello di sovrascrivere ogni volta quanto lanciato in precedenza!

L’esatta istruzione quindi per avere come gateway MySensors su seriale Raspberry è questa:

./configure --my-transport=nrf24
--my-rf24-irq-pin=15 --my-gateway=serial
--my-serial-is-pty --my-serial-pty=/dev/ttyUSB020

Come avete notato, il nome della seriale è stato impostato a ttyUSB020 per massimizzare la compatibilità con Domoticz (vedi sempre le istruzioni presenti sul sito di MySensors).

Io inoltre utilizzo anche il PIN 15 come IRQ (maggiori dettagli sempre sul sito MySensors).

La configurazione si completa con:

1
make
1
sudo ./bin/mysgw –d

Per testare in modalità debug che tutto funzioni

1
sudo make install
1
sudo systemctl enable mysgw.service
1
sudo systemctl start mysgw.service

Dove le ultime due istruzioni servono per far avviare il gateway al boot del sistema.

Se ancora non funziona… controllate come sempre i cablaggi (io ho aggiunto in più il PIN per l’IRQ) e lasciate un commento!