[openwrt/openwrt] image: add support for Netgear encrypted image

LEDE Commits lede-commits at lists.infradead.org
Tue Jul 19 05:49:35 PDT 2022


ansuel pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/efca76ffce5cf464e82d8269d79877f442209a0a

commit efca76ffce5cf464e82d8269d79877f442209a0a
Author: Wenli Looi <wlooi at ucalgary.ca>
AuthorDate: Sat Jul 2 20:16:21 2022 +0000

    image: add support for Netgear encrypted image
    
    Netgear encrypted image is used in various devices including WAX202,
    WAX206, and EX6400v3. This image format also requires a dummy squashfs4
    image which is added here as well.
    
    References in WAX202 GPL source:
    https://www.downloads.netgear.com/files/GPL/WAX202_V1.0.5.1_Source.rar
    
    * openwrt/bootloader/u-boot-mt7621-2018.09-gitb178829-20200526/board/ralink/common/dual_image.c
      Bootloader code that verifies the presence of a squashfs4 image, thus
      a dummy image is added here.
    
    * openwrt/tools/imgencoder/src/gj_enc.c
      Contains code that generates the encrypted image. There is support for
      adding an RSA signature, but it does not look like the signature is
      verified by the stock firmware or bootloader.
    
    * openwrt/tools/imgencoder/src/imagekey.h
      Contains the encryption key and IV. It appears the same key/IV is used
      for other Netgear devices including WAX206 and EX6400v3.
    
    Signed-off-by: Wenli Looi <wlooi at ucalgary.ca>
---
 include/image-commands.mk            | 22 ++++++++++++
 scripts/netgear-encrypted-factory.py | 68 ++++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+)

diff --git a/include/image-commands.mk b/include/image-commands.mk
index 376553b8d2..402e3d71ed 100644
--- a/include/image-commands.mk
+++ b/include/image-commands.mk
@@ -112,6 +112,15 @@ define Build/append-squashfs-fakeroot-be
 	cat $@.fakesquashfs >> $@
 endef
 
+define Build/append-squashfs4-fakeroot
+	rm -rf $@.fakefs $@.fakesquashfs
+	mkdir $@.fakefs
+	$(STAGING_DIR_HOST)/bin/mksquashfs4 \
+		$@.fakefs $@.fakesquashfs \
+		-nopad -noappend -root-owned
+	cat $@.fakesquashfs >> $@
+endef
+
 define Build/append-string
 	echo -n $(1) >> $@
 endef
@@ -376,6 +385,19 @@ define Build/netgear-dni
 	mv $@.new $@
 endef
 
+define Build/netgear-encrypted-factory
+	$(TOPDIR)/scripts/netgear-encrypted-factory.py \
+		--input-file $@ \
+		--output-file $@ \
+		--model $(NETGEAR_ENC_MODEL) \
+		--region $(NETGEAR_ENC_REGION) \
+		--version V1.0.0.0.$(VERSION_DIST).$(firstword $(subst -, ,$(REVISION))) \
+		--encryption-block-size 0x20000 \
+		--openssl-bin "$(STAGING_DIR_HOST)/bin/openssl" \
+		--key 6865392d342b4d212964363d6d7e7765312c7132613364316e26322a5a5e2538 \
+		--iv 4a253169516c38243d6c6d2d3b384145
+endef
+
 define Build/openmesh-image
 	$(TOPDIR)/scripts/om-fwupgradecfg-gen.sh \
 		"$(call param_get_default,ce_type,$(1),$(DEVICE_NAME))" \
diff --git a/scripts/netgear-encrypted-factory.py b/scripts/netgear-encrypted-factory.py
new file mode 100755
index 0000000000..b6bb72f3b8
--- /dev/null
+++ b/scripts/netgear-encrypted-factory.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+
+import argparse
+import re
+import struct
+import subprocess
+import zlib
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--input-file', type=str, required=True)
+    parser.add_argument('--output-file', type=str, required=True)
+    parser.add_argument('--model', type=str, required=True)
+    parser.add_argument('--region', type=str, required=True)
+    parser.add_argument('--version', type=str, required=True)
+    parser.add_argument('--encryption-block-size', type=str, required=True)
+    parser.add_argument('--openssl-bin', type=str, required=True)
+    parser.add_argument('--key', type=str, required=True)
+    parser.add_argument('--iv', type=str, required=True)
+    args = parser.parse_args()
+
+    assert re.match(r'V[0-9]\.[0-9]\.[0-9]\.[0-9]',
+                    args.version), 'Version must start with Vx.x.x.x'
+    encryption_block_size = int(args.encryption_block_size, 0)
+    assert (encryption_block_size > 0 and encryption_block_size % 16 ==
+            0), 'Encryption block size must be a multiple of the AES block size (16)'
+
+    image = open(args.input_file, 'rb').read()
+    image_enc = []
+    for i in range(0, len(image), encryption_block_size):
+        chunk = image[i:i + encryption_block_size]
+        chunk += b'\x00' * ((-len(chunk)) % 16)  # pad to AES block size (16)
+        res = subprocess.run([
+            args.openssl_bin,
+            'enc',
+            '-aes-256-cbc',
+            '-nosalt',
+            '-nopad',
+            '-K', args.key,
+            '-iv', args.iv
+        ],
+            check=True, input=chunk, stdout=subprocess.PIPE)
+        image_enc.append(res.stdout)
+    image_enc = b''.join(image_enc)
+
+    image_with_header = struct.pack(
+        '>32s32s64s64s64s256s12sII',
+        args.model.encode('ascii'),
+        args.region.encode('ascii'),
+        args.version.encode('ascii'),
+        b'Thu Jan 1 00:00:00 1970',  # static date for reproducibility
+        b'',  # reserved
+        b'',  # RSA signature - omitted for now
+        b'encrpted_img',
+        len(image_enc),
+        encryption_block_size,
+    ) + image_enc
+
+    checksum = zlib.crc32(image_with_header, 0xffffffff) ^ 0xffffffff
+
+    with open(args.output_file, 'wb') as outfile:
+        outfile.write(image_with_header)
+        outfile.write(struct.pack('>I', checksum))
+
+
+if __name__ == "__main__":
+    main()




More information about the lede-commits mailing list