/* ** KindleTool, kindle_tool.h ** ** Copyright (C) 2011-2012 Yifan Lu ** Copyright (C) 2012-2018 NiLuJe ** Concept based on an original Python implementation by Igor Skochinsky & Jean-Yves Avenard, ** cf., http://www.mobileread.com/forums/showthread.php?t=63225 ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ #ifndef __KINDLETOOL_H #define __KINDLETOOL_H // NOTE: Mainly to shut KDevelop up without any actual impact... // We do build MinGW w/ _GNU_SOURCE though. #if defined(__linux__) #ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE #endif #endif #include #include #include #include #include #include #include #include #include #include #include #if defined(__linux__) #include #endif #include // libarchive does not pull that in for us anymore ;). #if defined(_WIN32) && !defined(__CYGWIN__) #define WIN32_LEAN_AND_MEAN #include #endif #include #include #include #include #include #include #include #include #include // Die in a slightly more graceful manner than by spewing a whole lot of warnings & errors if we're not building against at least libarchive 3.0.3 #if ARCHIVE_VERSION_NUMBER < 3000003 #error Your libarchive version is too old, KindleTool depends on libarchive >= 3.0.3 #endif #define BUFFER_SIZE 1024 #define BLOCK_SIZE 64 #define RECOVERY_BLOCK_SIZE 131072 #define MAGIC_NUMBER_LENGTH 4 #define MD5_HASH_LENGTH 32 #define OTA_UPDATE_BLOCK_SIZE 60 #define OTA_UPDATE_V2_BLOCK_SIZE 18 #define OTA_UPDATE_V2_PART_2_BLOCK_SIZE 36 #define RECOVERY_UPDATE_BLOCK_SIZE 131068 #define UPDATE_SIGNATURE_BLOCK_SIZE 60 #define CERTIFICATE_DEV_SIZE 128 #define CERTIFICATE_1K_SIZE 128 #define CERTIFICATE_2K_SIZE 256 #define INDEX_FILE_NAME "update-filelist.dat" #define SERIAL_NO_LENGTH 16 #define DEFAULT_BYTES_PER_BLOCK (20*512) #define IS_SCRIPT(filename) (strncasecmp(filename+(strlen(filename)-4), ".ffs", 4) == 0) #define IS_SHELL(filename) (strncasecmp(filename+(strlen(filename)-3), ".sh", 3) == 0) #define IS_SIG(filename) (strncasecmp(filename+(strlen(filename)-4), ".sig", 4) == 0) #define IS_BIN(filename) (strncasecmp(filename+(strlen(filename)-4), ".bin", 4) == 0) #define IS_STGZ(filename) (strncasecmp(filename+(strlen(filename)-5), ".stgz", 5) == 0) #define IS_TGZ(filename) (strncasecmp(filename+(strlen(filename)-4), ".tgz", 4) == 0) #define IS_TARBALL(filename) (strncasecmp(filename+(strlen(filename)-7), ".tar.gz", 7) == 0) #define IS_DAT(filename) (strncasecmp(filename+(strlen(filename)-4), ".dat", 4) == 0) #define IS_UIMAGE(filename) (strncmp(filename+(strlen(filename)-6), "uImage", 6) == 0) // Don't break tempfiles on Win32... (it doesn't like paths starting with // because that means an 'extended' path (network shares and more weird stuff like that), but P_tmpdir defaults to / on Win32, and we prepend our own constants with / because it's /tmp on POSIX...) // Note that this is only used as a last resort, if for some reason GetTempPath returns something we can't use... // In any case, don't even try to put tempfiles on the root drive (because unprivileged users can't write there), so use "./" (current dir) instead as a crappy workaround. // NOTE: Geekmaster also experimented with using "../" (parent dir), which may or may not be a better idea... #if defined(_WIN32) && !defined(__CYGWIN__) #define KT_TMPDIR "." // NOTE: cf. kindle_tool.c int kt_win_mkstemp(char *); FILE *kt_win_tmpfile(void); // NOTE: Override the functions the hard way, shutting up GCC in the proces... #ifdef mkstemp #undef mkstemp #endif #define mkstemp kt_win_mkstemp #ifdef tmpfile #undef tmpfile #endif #define tmpfile kt_win_tmpfile // -> POSIX, assume P_tmpdir (usually /tmp) is a sane fallback. #else #define KT_TMPDIR P_tmpdir #endif // Bundlefile status bitmasks #define BUNDLE_OPEN 1 // 1 << 0 (bit 0) #define BUNDLE_CREATED 2 // 1 << 1 (bit 1) // Version tag fallback #ifndef KT_VERSION #define KT_VERSION "v1.6.5-GIT" #endif // user@host tag fallback #ifndef KT_USERATHOST #define KT_USERATHOST "someone@somewhere on something" #endif // nettle version fallback #ifndef NETTLE_VERSION #define NETTLE_VERSION ">= 2.6" #endif // GCC version checks... (We check !clang in addition to GCC, because Clang 'helpfully' defines __GNUC__ ...) #if !defined(__clang__) && defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif typedef enum { UpdateSignature, OTAUpdateV2, OTAUpdate, RecoveryUpdate, RecoveryUpdateV2, UserDataPackage, // Actually just a gzipped tarball, but easier to implement this way... AndroidUpdate, // Actually a JAR, designed for the weird Kindle X Migu Chinese exclusive UnknownUpdate = -1 } BundleVersion; typedef enum { CertificateDeveloper = 0x00, Certificate1K = 0x01, Certificate2K = 0x02, CertificateUnknown = 0xFF } CertificateNumber; typedef enum { Kindle1 = 0x01, Kindle2US = 0x02, Kindle2International = 0x03, KindleDXUS = 0x04, KindleDXInternational = 0x05, KindleDXGraphite = 0x09, Kindle3WiFi = 0x08, Kindle3WiFi3G = 0x06, Kindle3WiFi3GEurope = 0x0A, Kindle4NonTouch = 0x0E, // Kindle 4 with a silver bezel, released fall 2011 Kindle5TouchWiFi3G = 0x0F, Kindle5TouchWiFi = 0x11, Kindle5TouchWiFi3GEurope = 0x10, Kindle5TouchUnknown = 0x12, Kindle4NonTouchBlack = 0x23, // Kindle 4 with a black bezel, released fall 2012 KindlePaperWhiteWiFi = 0x24, // Kindle PaperWhite (black bezel), released fall 2012 on FW 5.2.0 KindlePaperWhiteWiFi3G = 0x1B, KindlePaperWhiteWiFi3GCanada = 0x1C, KindlePaperWhiteWiFi3GEurope = 0x1D, KindlePaperWhiteWiFi3GJapan = 0x1F, KindlePaperWhiteWiFi3GBrazil = 0x20, KindlePaperWhite2WiFi = 0xD4, // Kindle PaperWhite 2 (black bezel), released fall 2013 on FW 5.4.0 KindlePaperWhite2WiFiJapan = 0x5A, KindlePaperWhite2WiFi3G = 0xD5, KindlePaperWhite2WiFi3GCanada = 0xD6, KindlePaperWhite2WiFi3GEurope = 0xD7, KindlePaperWhite2WiFi3GRussia = 0xD8, KindlePaperWhite2WiFi3GJapan = 0xF2, KindlePaperWhite2WiFi4GBInternational = 0x17, KindlePaperWhite2WiFi3G4GBEurope = 0x60, KindlePaperWhite2Unknown_0xF4 = 0xF4, KindlePaperWhite2Unknown_0xF9 = 0xF9, KindlePaperWhite2WiFi3G4GB = 0x62, KindlePaperWhite2WiFi3G4GBBrazil = 0x61, KindlePaperWhite2WiFi3G4GBCanada = 0x5F, KindleBasic = 0xC6, // Kindle Basic (Pearl, Touch), released fall 2014 on FW 5.6.0 KindleVoyageWiFi = 0x13, // Kindle Voyage, released fall 2014 on FW 5.5.0 ValidKindleUnknown_0x16 = 0x16, ValidKindleUnknown_0x21 = 0x21, KindleVoyageWiFi3G = 0x54, KindleVoyageWiFi3GJapan = 0x2A, KindleVoyageUnknown_0x4F = 0x4F, KindleVoyageWiFi3GMexico = 0x52, KindleVoyageWiFi3GEurope = 0x53, ValidKindleUnknown_0x07 = 0x07, ValidKindleUnknown_0x0B = 0x0B, ValidKindleUnknown_0x0C = 0x0C, ValidKindleUnknown_0x0D = 0x0D, ValidKindleUnknown_0x99 = 0x99, KindleBasicKiwi = 0xDD, /* KindlePaperWhite3 = 0x90, */ // Kindle PaperWhite 3, released summer 2015 on FW 5.6.1 (NOTE: This is a bogus ID, the proper one is now found at chars 4 to 6 of the S/N) KindlePaperWhite3WiFi = 0x201, // 0G1 KindlePaperWhite3WiFi3G = 0x202, // 0G2 KindlePaperWhite3WiFi3GMexico = 0x204, // 0G4 NOTE: This, as well as all the other "Brazil" variants, might be better flagged as "Southern America"? KindlePaperWhite3WiFi3GEurope = 0x205, // 0G5 KindlePaperWhite3WiFi3GCanada = 0x206, // 0G6 KindlePaperWhite3WiFi3GJapan = 0x207, // 0G7 // Kindle PaperWhite 3, White, appeared w/ FW 5.7.3.1, released summer 2016 on FW 5.7.x? KindlePaperWhite3WhiteWiFi = 0x26B, // 0KB KindlePaperWhite3WhiteWiFi3GJapan = 0x26C, // 0KC KindlePW3WhiteUnknown_0KD = 0x26D, // 0KD? KindlePaperWhite3WhiteWiFi3GInternational = 0x26E, // 0KE KindlePaperWhite3WhiteWiFi3GInternationalBis = 0x26F, // 0KF KindlePW3WhiteUnknown_0KG = 0x270, // 0KG? KindlePaperWhite3BlackWiFi32GBJapan = 0x293,// 0LK KindlePaperWhite3WhiteWiFi32GBJapan = 0x294,// 0LL // Kindle Oasis, released late spring 2016 on FW 5.7.1.1 KindleOasisWiFi = 0x20C, // 0GC KindleOasisWiFi3G = 0x20D, // 0GD KindleOasisWiFi3GInternational = 0x219, // 0GR KindleOasisUnknown_0GS = 0x21A, // 0GS? KindleOasisUnknown_0GT = 0x21B, // 0GT? KindleOasisWiFi3GEurope = 0x21C, // 0GU // Kindle Basic 2, released summer 2016 on FW 5.8.0 KindleBasic2Unknown_0DU = 0x1BC, // 0DU?? FIXME: Confirming that one will probably make or break my base 32 tweaks... KindleBasic2 = 0x269, // 0K9 (Black) KindleBasic2White = 0x26A, // 0KA (White) // Kindle Oasis 2, released winter 2017 on FW 5.9.0.6 KindleOasis2Unknown_0LM = 0x295, // 0LM? KindleOasis2Unknown_0LN = 0x296, // 0LN? KindleOasis2Unknown_0LP = 0x297, // 0LP? KindleOasis2Unknown_0LQ = 0x298, // 0LQ? KindleOasis2Unknown_0P1 = 0x2E1, // 0P1? KindleOasis2Unknown_0P2 = 0x2E2, // 0P2? KindleOasis2Unknown_0P6 = 0x2E6, // 0P6? KindleOasis2Unknown_0P7 = 0x2E7, // 0P7? KindleOasis2WiFi8GB = 0x2E8, // 0P8 KindleOasis2WiFi3G32GB = 0x341, // 0S1 KindleOasis2WiFi3G32GBEurope = 0x342, // 0S2 KindleOasis2Unknown_0S3 = 0x343, // 0S3? KindleOasis2Unknown_0S4 = 0x344, // 0S4? KindleOasis2Unknown_0S7 = 0x347, // 0S7? KindleOasis2WiFi32GB = 0x34A, // 0SA KindleUnknown = 0x00 } Device; typedef enum { Plat_Unspecified = 0x00, MarioDeprecated = 0x01, // Kindle 2 Luigi = 0x02, // Kindle 3 Banjo = 0x03, // ?? Yoshi = 0x04, // Kindle Touch (and Kindle 4) YoshimeProto = 0x05, // Early PW proto? (NB: Platform AKA Yoshime) Yoshime = 0x06, // Kindle PW (NB: Platform AKA Yoshime3) Wario = 0x07, // Kindle PW2, Basic, Voyage, PW3 Duet = 0x08, // Kindle Oasis Heisenberg = 0x09, // Kindle Basic 2 (8th gen) Zelda = 0x0A // Kindle Oasis 2 } Platform; typedef enum { Board_Unspecified = 0x00, // Used since the PW (skip board check) Tequila = 0x03, // Silver Kindle 4 Whitney = 0x05 // Kindle Touch // Other potentially relevant (OTA|Recovery)v2 ready boards: /* Sauza = 0xFF // Black Kindle 4 Celeste = 0xFF // PW Icewine = 0xFF // Kindle Voyage (also a dev/proto on the Yoshime3 platform) Pinot = 0xFF // PW2 Bourbon = 0xFF // Kindle Basic Muscat = 0xFF // PW3 Whisky = 0xFF // Kindle Oasis Woody = 0xFF // ?? (in the Basic line? (no 3G)) Eanab = 0xFF // Kindle Basic 2 Cognac = 0xFF // Kindle Oasis 2 */ } Board; // For reference, list of boards (AFAICT, in chronological order): // ADS // K1 proto? (w/ ETH) // Fiona // Kindle 1 // Mario // Kindle 2? (w/ ETH) [Also a platform] // Nell/NellSL/NellWW // DX & DXG & DXi? // Turing/TuringWW // Kindle 2 & Kindle 2 International // Luigi/Luigi3 // ?? (r3 w/ ETH) [Also a platform] // Shasta (+ WFO variant) // Kindle 3 // Yoshi // ?? [Also a platform] // Primer // Deprecated proto // Harv // K4 proto? // Tequila (is WFO) // Silver Kindle 4 // Sauza // Black Kindle 4? (NOT in chronological order) // Finkle // Touch proto? // Whitney (+ WFO variant) // Kindle Touch // Yoshime // Temp. Yoshime dev board [Also a Platform, which we call YoshimeProto] // Yoshime3 // Temp. Yoshime3 dev boards (w/ ETH). PW proto? [Also a Platform, which we call Yoshime] // Celeste (+ WFO variant) // Kindle PW // Icewine (+ WFO variants) // Dev/Proto, next rumored product [Used on two different platforms (so far), Yoshime3 & Wario] // Wario // Temp. Wario dev boards [Also a Platform] // Pinot (+ WFO variant) // Kindle PW2 // Bourbon // Kindle Basic // Icewine (on Wario) // Kindle Voyage // Muscat // Kindle PW3 // Whisky // Kindle Oasis // Woody // ?? (Dev/Proto? Duet platform, Basic line) // Eanab // Kindle Basic 2 // Cognac // Kindle Oasis 2 typedef struct { CertificateNumber certificate_number; } UpdateSignatureHeader; typedef struct { uint32_t source_revision; uint32_t target_revision; uint16_t device; unsigned char optional; unsigned char unused; char md5_sum[MD5_HASH_LENGTH]; } OTAUpdateHeader; typedef struct { unsigned char unused[12]; char md5_sum[MD5_HASH_LENGTH]; uint32_t magic_1; uint32_t magic_2; uint32_t minor; uint32_t device; } RecoveryUpdateHeader; typedef struct { unsigned char unused[12]; char md5_sum[MD5_HASH_LENGTH]; uint32_t magic_1; uint32_t magic_2; uint32_t minor; uint32_t platform; uint32_t header_rev; uint32_t board; } RecoveryH2UpdateHeader; // FB02 with V2 Header, not FB03 typedef struct { char magic_number[MAGIC_NUMBER_LENGTH]; union { OTAUpdateHeader ota_update; RecoveryUpdateHeader recovery_update; RecoveryH2UpdateHeader recovery_h2_update; UpdateSignatureHeader signature; unsigned char ota_header_data[OTA_UPDATE_BLOCK_SIZE]; unsigned char signature_header_data[UPDATE_SIGNATURE_BLOCK_SIZE]; unsigned char recovery_header_data[RECOVERY_UPDATE_BLOCK_SIZE]; } data; } UpdateHeader; // Ugly global. Used to cache the state of the KT_WITH_UNKNOWN_DEVCODES env var... // NOTE: While this looks like the ideal candidate to be a bool, we can't do that because we use its value in unsigned operations and I can't be arsed to add a bunch of casts there (because for some mystical reason, bool is signed :?) extern unsigned int kt_with_unknown_devcodes; // And another to store the tmpdir... extern char kt_tempdir[PATH_MAX]; unsigned long int from_base(char *, unsigned int); void md(unsigned char *, size_t); void dm(unsigned char *, size_t); int munger(FILE *, FILE *, size_t, const bool); int demunger(FILE *, FILE *, size_t, const bool); const char *convert_device_id(Device); const char *convert_platform_id(Platform); const char *convert_board_id(Board); BundleVersion get_bundle_version(char *); int md5_sum(FILE *, char *); int kindle_convert_main(int, char **); int kindle_extract_main(int, char **); int kindle_create_main(int, char **); int nettle_rsa_privkey_from_pem(char *, struct rsa_private_key *); #endif // kate: indent-mode cstyle; indent-width 4; replace-tabs on;