path: root/utils/nwztools/upgtools/upg.h
diff options
authorAmaury Pouly <>2020-06-13 16:21:16 +0200
committerAmaury Pouly <>2020-10-11 13:08:03 +0200
commit53d2742a482eba04fab02a5f1b8a5b2fa48206e2 (patch)
tree10f04b099fad6bd3bb42b597f536c0a247fc10ab /utils/nwztools/upgtools/upg.h
parentcda16f9439359c79c4d8f54f63b0cdb10dc79bfb (diff)
nwztools: add support for new UPG format on post-WM1/A30 devices
The new code supports reading and writing UPG files. I kept the old keysig search code but it only supports the old format (the new format has too long keys anyway). Since we now have to support two types of encryption(DES and AES), I reorganized the crypto routines and clean-up some code. Change-Id: Ie9be220ec2431ec6d0bd11699fa0493b62e1cec2
Diffstat (limited to 'utils/nwztools/upgtools/upg.h')
1 files changed, 42 insertions, 16 deletions
diff --git a/utils/nwztools/upgtools/upg.h b/utils/nwztools/upgtools/upg.h
index bc7c9787c9..e6cdaba1f7 100644
--- a/utils/nwztools/upgtools/upg.h
+++ b/utils/nwztools/upgtools/upg.h
@@ -22,10 +22,9 @@
#define __UPG_H__
#include "misc.h"
-#include "fwp.h"
#include "mg.h"
-/** Firmware format
+/** Firmware format V1/V2
* The firmware starts with the MD5 hash of the entire file (except the MD5 hash
* itself of course). This is used to check that the file was not corrupted.
@@ -35,7 +34,20 @@
* the key and finding the right signature serves to authenticate the firmware.
* The header is followed by N entries (where N is the number of files) giving
* the offset, within the file, and size of each file. Note that the files in
- * the firmware have no name. */
+ * the firmware have no name. The only difference between V1 and V2 is that the
+ * size of the signature is 16 bytes instead of 8 and the upg entries are 16 bytes
+ * long so they are padded.
+ *
+ * There is, however a practical difference between how the OF performs the update on
+ * newer devices (and hence corrolates exactly with V2 usage). On these devices, the
+ * update script will first extract the first file (the bash script) and the second file
+ * which is called "md5.txt". At this point it then runs the script. Hence it is not
+ * important what the content of the second file is, it is not checked unless fwpup is
+ * called. For the records, here is an exerct of such a file:
+ * 838860800 eae2acabcd6523a750f61f5ea3e9a80b system.img
+ */
+#define NWZ_MD5_SIZE 16
struct upg_md5_t
@@ -44,7 +56,7 @@ struct upg_md5_t
struct upg_header_t
- uint8_t sig[NWZ_SIG_SIZE];
+ uint8_t sig[8];
uint32_t nr_files;
uint32_t pad; // make sure structure size is a multiple of 8
} __attribute__((packed));
@@ -55,6 +67,20 @@ struct upg_entry_t
uint32_t size;
} __attribute__((packed));
+struct upg_header_v2_t
+ uint8_t sig[16];
+ uint32_t nr_files;
+ uint32_t pad[3]; // make sure structure size is a multiple of 16
+} __attribute__((packed));
+struct upg_entry_v2_t
+ uint32_t offset;
+ uint32_t size;
+ uint32_t pad[2]; // make sure structure size is a multiple of 16
+} __attribute__((packed));
/** KAS / Key / Signature
* Since this is all very confusing, we need some terminology and notations:
@@ -131,7 +157,7 @@ struct nwz_model_t
* it is a KAS built from a key and sig brute-forced from an upgrade. In this
* case, the KAS might be different from the 'official' one although for all
* intent and purposes it should not make any difference. */
- char *kas;
+ const char *kas;
/* list of models with keys and status. Sentinel NULL entry at the end */
@@ -150,21 +176,21 @@ struct upg_file_t
struct upg_file_entry_t *files;
-/* decrypt a KAS into a key and signature, return <0 if the KAS contains a non-hex
- * character */
-int decrypt_keysig(const char kas[NWZ_KAS_SIZE], char key[NWZ_KEY_SIZE],
- char sig[NWZ_SIG_SIZE]);
-/* encrypt a key and signature into a KAS */
-void encrypt_keysig(char kas[NWZ_KEY_SIZE],
- const char key[NWZ_SIG_SIZE], const char sig[NWZ_KAS_SIZE]);
+/* IMPORTANT: all functions assume that the kas/key/sig are string and are zero terminated */
+/* Decrypt a KAS into a key and signature, return <0 if the KAS contains a non-hex
+ * character. The function will allocate key and sig if *key and/or *sig is NULL */
+int decrypt_keysig(const char *kas, char **key, char **sig);
+/* Encrypt a key and signature into a KAS, it will allocate kas if *kas is NULL */
+void encrypt_keysig(char **kas, const char *key, const char *sig);
/* Read a UPG file: return a structure on a success or NULL on error.
* Note that the memory buffer is modified to perform in-place decryption. */
-struct upg_file_t *upg_read_memory(void *file, size_t size, char key[NWZ_KEY_SIZE],
- char sig[NWZ_SIG_SIZE], void *u, generic_printf_t printf);
+struct upg_file_t *upg_read_memory(void *file, size_t size, const char *key,
+ const char *sig, void *u, generic_printf_t printf);
/* Write a UPG file: return a buffer containing the whole image, or NULL on error. */
-void *upg_write_memory(struct upg_file_t *file, char key[NWZ_KEY_SIZE],
- char sig[NWZ_SIG_SIZE], size_t *out_size, void *u, generic_printf_t printf);
+void *upg_write_memory(struct upg_file_t *file, const char *key,
+ const char *sig, size_t *out_size, void *u, generic_printf_t printf);
/* create empty upg file */
struct upg_file_t *upg_new(void);
/* append a file to a upg, data is NOT copied */