Selaa lähdekoodia

nvs_partition_gen/mass_mfg: Support for HMAC-based scheme for generating NVS encr-keys

Laukik Hase 2 vuotta sitten
vanhempi
sitoutus
9ac87fcc8b

+ 127 - 46
components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py

@@ -18,11 +18,13 @@ import os
 import random
 import struct
 import sys
+import textwrap
 import zlib
 from io import open
 
 try:
     from cryptography.hazmat.backends import default_backend
+    from cryptography.hazmat.primitives import hashes, hmac
     from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
 except ImportError:
     print('The cryptography package is not installed.'
@@ -44,6 +46,13 @@ def reverse_hexbytes(addr_tmp):
     return reversed_bytes
 
 
+def desc_format(*args):
+    desc = ''
+    for arg in args:
+        desc += textwrap.fill(replace_whitespace=False, text=arg) + '\n'
+    return desc
+
+
 """ Class for standard NVS page structure """
 
 
@@ -842,16 +851,63 @@ def generate_key(args):
         distutils.dir_util.mkpath(keys_outdir)
     keys_outdir, output_keyfile = set_target_filepath(keys_outdir, args.keyfile)
 
-    key = ''.join(random.choice('0123456789abcdef') for _ in range(128)).strip()
-    encr_key_bytes = codecs.decode(key, 'hex')
-    key_len = len(encr_key_bytes)
-
     keys_buf = bytearray(b'\xff') * page_max_size
-    keys_buf[0:key_len] = encr_key_bytes
-    crc_data = keys_buf[0:key_len]
-    crc_data = bytes(crc_data)
-    crc = zlib.crc32(crc_data, 0xFFFFFFFF)
-    struct.pack_into('<I', keys_buf, key_len,  crc & 0xFFFFFFFF)
+    key = ''
+
+    if args.key_protect_hmac:
+        HMAC_EKEY_SEED_ELEMENT = b'\x5A\x5A\xBE\xAE'
+        HMAC_TKEY_SEED_ELEMENT = b'\xA5\xA5\xDE\xCE'
+        hmac_key = b''
+
+        if args.kp_hmac_keygen:
+            hmac_key_str = ''.join(random.choice('0123456789abcdef') for _ in range(64)).strip()
+            hmac_key = codecs.decode(hmac_key_str, 'hex')
+            hmac_keyfile = ''
+
+            if args.kp_hmac_keyfile:
+                hmac_keyfile = args.kp_hmac_keyfile
+            else:
+                hmac_keyfile = 'hmac-' + args.keyfile
+
+            hmac_keyfile = set_target_filepath(keys_outdir, hmac_keyfile)[1]
+            with open(hmac_keyfile, 'wb') as hmac_key_file:
+                hmac_key_file.write(hmac_key)
+        else:
+            if not args.kp_hmac_inputkey:
+                raise RuntimeError('HMAC Key input file (HMAC-based encryption scheme) missing!')
+
+            with open(args.kp_hmac_inputkey, 'rb') as input_keys_file:
+                hmac_key = input_keys_file.read()
+
+        ekey_seed = HMAC_EKEY_SEED_ELEMENT * 8
+        h_e = hmac.HMAC(hmac_key, hashes.SHA256())
+        h_e.update(ekey_seed)
+        e_key = h_e.finalize()
+
+        tkey_seed = HMAC_TKEY_SEED_ELEMENT * 8
+        h_t = hmac.HMAC(hmac_key, hashes.SHA256())
+        h_t.update(tkey_seed)
+        t_key = h_t.finalize()
+
+        encr_key_bytes = e_key + t_key
+        key_len = len(encr_key_bytes)
+        key = f"{int.from_bytes(encr_key_bytes, 'big'):x}"
+
+        keys_buf[0:key_len] = encr_key_bytes
+        crc_data = keys_buf[0:key_len]
+        crc_data = bytes(crc_data)
+        crc = zlib.crc32(crc_data, 0xFFFFFFFF)
+        struct.pack_into('<I', keys_buf, key_len,  crc & 0xFFFFFFFF)
+    else:
+        key = ''.join(random.choice('0123456789abcdef') for _ in range(128)).strip()
+        encr_key_bytes = codecs.decode(key, 'hex')
+        key_len = len(encr_key_bytes)
+
+        keys_buf[0:key_len] = encr_key_bytes
+        crc_data = keys_buf[0:key_len]
+        crc_data = bytes(crc_data)
+        crc = zlib.crc32(crc_data, 0xFFFFFFFF)
+        struct.pack_into('<I', keys_buf, key_len,  crc & 0xFFFFFFFF)
 
     with open(output_keyfile, 'wb') as output_keys_file:
         output_keys_file.write(keys_buf)
@@ -918,101 +974,126 @@ def generate(args, is_encr_enabled=False, encr_key=None):
 
 
 def main():
-    parser = argparse.ArgumentParser(description='\nESP NVS partition generation utility', formatter_class=argparse.RawTextHelpFormatter)
+    parser = argparse.ArgumentParser(description=desc_format('ESP NVS partition generation utility'), formatter_class=argparse.RawTextHelpFormatter)
     subparser = parser.add_subparsers(title='Commands',
                                       dest='command',
-                                      help='\nRun nvs_partition_gen.py {command} -h for additional help\n\n')
+                                      help=desc_format('Run nvs_partition_gen.py {command} -h for additional help'))
 
     parser_gen = subparser.add_parser('generate',
-                                      help='Generate NVS partition',
+                                      help=desc_format('Generate NVS partition'),
                                       formatter_class=argparse.RawTextHelpFormatter)
     parser_gen.set_defaults(func=generate)
     parser_gen.add_argument('input',
                             default=None,
-                            help='Path to CSV file to parse')
+                            help=desc_format('Path to CSV file to parse'))
     parser_gen.add_argument('output',
                             default=None,
-                            help='Path to output NVS binary file')
+                            help=desc_format('Path to output NVS binary file'))
     parser_gen.add_argument('size',
                             default=None,
-                            help='Size of NVS partition in bytes\
-                            \n(must be multiple of 4096)')
+                            help=desc_format('Size of NVS partition in bytes (must be multiple of 4096)'))
     parser_gen.add_argument('--version',
                             choices=[1,2],
                             default=2,
                             type=int,
-                            help='''Set multipage blob version.\
-                            \nVersion 1 - Multipage blob support disabled.\
-                            \nVersion 2 - Multipage blob support enabled.\
-                            \nDefault: Version 2''')
+                            help=desc_format(
+                                'Set multipage blob version.',
+                                'Version 1 - Multipage blob support disabled.',
+                                'Version 2 - Multipage blob support enabled.',
+                                'Default: Version 2'))
     parser_gen.add_argument('--outdir',
                             default=os.getcwd(),
-                            help='Output directory to store files created\
-                            \n(Default: current directory)')
+                            help=desc_format('Output directory to store files created (Default: current directory)'))
     parser_gen_key = subparser.add_parser('generate-key',
-                                          help='Generate keys for encryption',
+                                          help=desc_format('Generate keys for encryption'),
                                           formatter_class=argparse.RawTextHelpFormatter)
     parser_gen_key.set_defaults(func=generate_key)
+    parser_gen_key.add_argument('--key_protect_hmac',
+                                action='store_true',
+                                help=desc_format(
+                                    'If set, the NVS encryption key protection scheme based on HMAC',
+                                    'peripheral is used; else the default scheme based on Flash Encryption',
+                                    'is used'))
+    parser_gen_key.add_argument('--kp_hmac_keygen',
+                                action='store_true',
+                                help=desc_format('Generate the HMAC key for HMAC-based encryption scheme'))
+    parser_gen_key.add_argument('--kp_hmac_keyfile',
+                                default=None,
+                                help=desc_format('Path to output HMAC key file'))
+    parser_gen_key.add_argument('--kp_hmac_inputkey',
+                                default=None,
+                                help=desc_format('File having the HMAC key for generating the NVS encryption keys'))
     parser_gen_key.add_argument('--keyfile',
                                 default=None,
-                                help='Path to output encryption keys file')
+                                help=desc_format('Path to output encryption keys file'))
     parser_gen_key.add_argument('--outdir',
                                 default=os.getcwd(),
-                                help='Output directory to store files created.\
-                                \n(Default: current directory)')
+                                help=desc_format('Output directory to store files created. (Default: current directory)'))
     parser_encr = subparser.add_parser('encrypt',
-                                       help='Generate NVS encrypted partition',
+                                       help=desc_format('Generate NVS encrypted partition'),
                                        formatter_class=argparse.RawTextHelpFormatter)
     parser_encr.set_defaults(func=encrypt)
     parser_encr.add_argument('input',
                              default=None,
-                             help='Path to CSV file to parse')
+                             help=desc_format('Path to CSV file to parse'))
     parser_encr.add_argument('output',
                              default=None,
-                             help='Path to output NVS binary file')
+                             help=desc_format('Path to output NVS binary file'))
     parser_encr.add_argument('size',
                              default=None,
-                             help='Size of NVS partition in bytes\
-                             \n(must be multiple of 4096)')
+                             help=desc_format('Size of NVS partition in bytes (must be multiple of 4096)'))
     parser_encr.add_argument('--version',
                              choices=[1,2],
                              default=2,
                              type=int,
-                             help='''Set multipage blob version.\
-                             \nVersion 1 - Multipage blob support disabled.\
-                             \nVersion 2 - Multipage blob support enabled.\
-                             \nDefault: Version 2''')
+                             help=desc_format(
+                                 'Set multipage blob version.',
+                                 'Version 1 - Multipage blob support disabled.',
+                                 'Version 2 - Multipage blob support enabled.',
+                                 'Default: Version 2'))
     parser_encr.add_argument('--keygen',
                              action='store_true',
-                             default=False,
-                             help='Generates key for encrypting NVS partition')
+                             help=desc_format('Generates key for encrypting NVS partition'))
     parser_encr.add_argument('--keyfile',
                              default=None,
-                             help='Path to output encryption keys file')
+                             help=desc_format('Path to output encryption keys file'))
     parser_encr.add_argument('--inputkey',
                              default=None,
-                             help='File having key for encrypting NVS partition')
+                             help=desc_format('File having key for encrypting NVS partition'))
     parser_encr.add_argument('--outdir',
                              default=os.getcwd(),
-                             help='Output directory to store files created.\
-                             \n(Default: current directory)')
+                             help=desc_format('Output directory to store files created. (Default: current directory)'))
+    parser_encr.add_argument('--key_protect_hmac',
+                             action='store_true',
+                             help=desc_format(
+                                 'If set, the NVS encryption key protection scheme based on HMAC',
+                                 'peripheral is used; else the default scheme based on Flash Encryption',
+                                 'is used'))
+    parser_encr.add_argument('--kp_hmac_keygen',
+                             action='store_true',
+                             help=desc_format('Generate the HMAC key for HMAC-based encryption scheme'))
+    parser_encr.add_argument('--kp_hmac_keyfile',
+                             default=None,
+                             help=desc_format('Path to output HMAC key file'))
+    parser_encr.add_argument('--kp_hmac_inputkey',
+                             default=None,
+                             help=desc_format('File having the HMAC key for generating the NVS encryption keys'))
     parser_decr = subparser.add_parser('decrypt',
-                                       help='Decrypt NVS encrypted partition',
+                                       help=desc_format('Decrypt NVS encrypted partition'),
                                        formatter_class=argparse.RawTextHelpFormatter)
     parser_decr.set_defaults(func=decrypt)
     parser_decr.add_argument('input',
                              default=None,
-                             help='Path to encrypted NVS partition file to parse')
+                             help=desc_format('Path to encrypted NVS partition file to parse'))
     parser_decr.add_argument('key',
                              default=None,
-                             help='Path to file having keys for decryption')
+                             help=desc_format('Path to file having keys for decryption'))
     parser_decr.add_argument('output',
                              default=None,
                              help='Path to output decrypted binary file')
     parser_decr.add_argument('--outdir',
                              default=os.getcwd(),
-                             help='Output directory to store files created.\
-                             \n(Default: current directory)')
+                             help=desc_format('Output directory to store files created. (Default: current directory)'))
     args = parser.parse_args()
 
     args.func(args)

+ 13 - 0
components/nvs_flash/nvs_partition_generator/sample_val.csv

@@ -0,0 +1,13 @@
+# Sample csv file
+key,type,encoding,value
+storage,namespace,,
+u8_key,data,u8,255
+i8_key,data,i8,-128
+u16_key,data,u16,65535
+u32_key,data,u32,4294967295
+i32_key,data,i32,-2147483648
+str_key,data,string,"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Fusce quis risus justo.
+Suspendisse egestas in nisi sit amet auctor.
+Pellentesque rhoncus dictum sodales.
+In justo erat, viverra at interdum eget, interdum vel dui."

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
components/nvs_flash/nvs_partition_generator/testdata/sample_encryption_keys_hmac.bin


+ 2 - 0
components/nvs_flash/nvs_partition_generator/testdata/sample_hmac_key.bin

@@ -0,0 +1,2 @@
+	
+
 

+ 28 - 1
tools/mass_mfg/mfg_gen.py

@@ -420,7 +420,6 @@ def main():
                                     \nDefault: Version 2 ''')
         parser_gen.add_argument('--keygen',
                                 action='store_true',
-                                default=False,
                                 help='Generates key for encrypting NVS partition')
         parser_gen.add_argument('--keyfile',
                                 default=None,
@@ -432,6 +431,20 @@ def main():
                                 default=os.getcwd(),
                                 help='Output directory to store files created\
                                     \n(Default: current directory)')
+        parser_gen.add_argument('--key_protect_hmac',
+                                action='store_true',
+                                help='''If set, the NVS encryption key protection scheme based on HMAC\
+                                \nperipheral is used; else the default scheme based on Flash Encryption\
+                                \nis used''')
+        parser_gen.add_argument('--kp_hmac_keygen',
+                                action='store_true',
+                                help='Generate the HMAC key for HMAC-based encryption scheme')
+        parser_gen.add_argument('--kp_hmac_keyfile',
+                                default=None,
+                                help='Path to output HMAC key file')
+        parser_gen.add_argument('--kp_hmac_inputkey',
+                                default=None,
+                                help='File having the HMAC key for generating the NVS encryption keys')
         parser_gen.add_argument('--input',
                                 default=None,
                                 help=argparse.SUPPRESS)
@@ -449,6 +462,20 @@ def main():
                                     default=os.getcwd(),
                                     help='Output directory to store files created.\
                                         \n(Default: current directory)')
+        parser_gen_key.add_argument('--key_protect_hmac',
+                                    action='store_true',
+                                    help='''If set, the NVS encryption key protection scheme based on HMAC\
+                                    \nperipheral is used; else the default scheme based on Flash Encryption\
+                                    \nis used''')
+        parser_gen_key.add_argument('--kp_hmac_keygen',
+                                    action='store_true',
+                                    help='Generate the HMAC key for HMAC-based encryption scheme')
+        parser_gen_key.add_argument('--kp_hmac_keyfile',
+                                    default=None,
+                                    help='Path to output HMAC key file')
+        parser_gen_key.add_argument('--kp_hmac_inputkey',
+                                    default=None,
+                                    help='File having the HMAC key for generating the NVS encryption keys')
 
         args = parser.parse_args()
         args.func(args)

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
tools/mass_mfg/testdata/sample_encryption_keys_hmac.bin


+ 2 - 0
tools/mass_mfg/testdata/sample_hmac_key.bin

@@ -0,0 +1,2 @@
+	
+
 

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä