mi4code.c
/*
* mi4 (de/en)coder
*
* Notes:
* - The crypto algorithm is a 16 round variation of TEA.
* - So it is a 'real' crypto algorithm and not just something
* some idiot hacked together in a hurry.
* - The keys so far have been stored in the bootloader. So
* if new mi4 files are found, a corresponding bootloader
* is needed.
* - In the new 010301 header version the integrity check uses
* DSA. Unless we somehow get the private key, we just can't
* sign our own firmware with the original key.
* - We can however replace the public key in the bootloader
* and then sign with our own private key.
* - Or we can try to fool the DSA check completely. There seems
* to be some 'interesting' features in the DSA implementation
* in the bootloader.
* - DSA support now requires libgcrypt. It should be possible
* to turn it off to build mi4code without real DSA signing
* or verifying capability.
*
* Thanks to
*
* Daniel Stenberg for hosting the project.
* Benjamin Larsson for the MSI P640 key + some ideas.
*
* (c) MrH 2008
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#define SUPPORT_DSA /* requires libgcrypt, undef if not available */
#define VERSION "v1.1.2"
/* Known TEA keys */
struct tea_key {
const char * name;
uint32_t key[4];
};
struct tea_key tea_keytable[] = {
{ "default" , { 0x20d36cc0, 0x10e8c07d, 0xc0e7dcaa, 0x107eb080 } },
{ "sansa", { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 } },
{ "sansa_gh", { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 } },
{ "sansa_103", { 0x1d29ddc0, 0x2579c2cd, 0xce339e1a, 0x75465dfe } },
{ "rhapsody", { 0x7aa9c8dc, 0xbed0a82a, 0x16204cc7, 0x5904ef38 } },
{ "p610", { 0x950e83dc, 0xec4907f9, 0x023734b9, 0x10cfb7c7 } },
{ "p640", { 0x220c5f23, 0xd04df68e, 0x431b5e25, 0x4dcc1fa1 } },
{ "virgin", { 0xe83c29a1, 0x04862973, 0xa9b3f0d4, 0x38be2a9c } },
{ "20gc_eng", { 0x0240772c, 0x6f3329b5, 0x3ec9a6c5, 0xb0c9e493 } },
{ "20gc_fre", { 0xbede8817, 0xb23bfe4f, 0x80aa682d, 0xd13f598c } },
{ "elio_p722", { 0x6af3b9f8, 0x777483f5, 0xae8181cc, 0xfa6d8a84 } },
{ "c200", { 0xbf2d06fa, 0xf0e23d59, 0x29738132, 0xe2d04ca7 } },
{ "c200_003", { 0x2a7968de, 0x15127979, 0x142e60a7, 0xe49c1893 } },
{ "c200_106", { 0xa913d139, 0xf842f398, 0x3e03f1a6, 0x060ee012 } },
{ "view", { 0x70e19bda, 0x0c69ea7d, 0x2b8b1ad1, 0xe9767ced } },
{ "sa9200", { 0x33ea0236, 0x9247bdc5, 0xdfaedf9f, 0xd67c9d30 } },
};
#define NUM_TEA_KEYS (sizeof(tea_keytable) / sizeof(tea_keytable[0]))
/* Known DSA keys */
struct dsa_key {
const char * name;
int known;
uint8_t p[128];
uint8_t q[20];
uint8_t g[128];
uint8_t y[128];
uint8_t x[20];
};
struct dsa_key dsa_keytable[] = {
{
"mi4code", 1,
{
0xbe, 0x9e, 0x39, 0xb6, 0xae, 0x8c, 0x57, 0xe2,
0x82, 0xfb, 0x45, 0xaf, 0x9d, 0x88, 0x25, 0x60,
0x6f, 0x2a, 0x2b, 0x1c, 0x74, 0x6e, 0x41, 0xe0,
0xc0, 0xfc, 0xc4, 0xb6, 0x78, 0x98, 0x54, 0x71,
0x49, 0xbe, 0x18, 0x88, 0xdc, 0x02, 0x8a, 0x62,
0xe5, 0xbd, 0xae, 0x62, 0xfe, 0xa6, 0x19, 0xda,
0x5f, 0x8c, 0xa8, 0xec, 0xd0, 0x67, 0x9a, 0xf0,
0x34, 0x45, 0x8f, 0x05, 0x50, 0xdc, 0x48, 0x9d,
0xb4, 0xee, 0xb1, 0x1c, 0xb4, 0x73, 0x80, 0xb2,
0x67, 0x8d, 0xd7, 0x32, 0xed, 0x6d, 0x87, 0xa3,
0xd6, 0x15, 0xa6, 0x3c, 0xde, 0x44, 0x0a, 0x79,
0xe6, 0xed, 0x53, 0xea, 0x8c, 0x6b, 0x1d, 0xd4,
0x53, 0x3f, 0x3d, 0x64, 0xc2, 0x32, 0x30, 0x39,
0x5f, 0x8e, 0x51, 0x3f, 0x09, 0xf0, 0xa2, 0x39,
0x53, 0x1e, 0xd2, 0xa3, 0xc0, 0x9e, 0x86, 0x26,
0x3a, 0x87, 0x4a, 0x8b, 0x4c, 0xf8, 0x46, 0xdf
},
{
0xe1, 0x27, 0xd5, 0x23, 0x2c, 0x5d, 0xb9, 0x72,
0x52, 0x44, 0xd2, 0xd7, 0xaf, 0x03, 0xee, 0x37,
0xd5, 0x67, 0x21, 0xfd
},
{
0x55, 0x06, 0x71, 0x4b, 0x0a, 0xde, 0x46, 0xb7,
0x42, 0xde, 0xf6, 0xae, 0x96, 0xc7, 0x20, 0x06,
0x99, 0x2c, 0x72, 0x7f, 0xd5, 0x40, 0xfd, 0xc0,
0x40, 0xd7, 0xe5, 0xd0, 0x0e, 0x4d, 0x03, 0x0f,
0x61, 0xfd, 0x75, 0x36, 0x61, 0x6a, 0x80, 0x8f,
0x63, 0xa9, 0xfd, 0x50, 0x67, 0xd2, 0x35, 0xd0,
0xea, 0xb3, 0x18, 0x6e, 0xf0, 0x62, 0xd2, 0x60,
0x86, 0x6c, 0x62, 0x58, 0x5b, 0xc4, 0x8f, 0xf2,
0x5f, 0x9e, 0x54, 0x3b, 0xd4, 0xcb, 0xfe, 0xc4,
0x91, 0xe9, 0x3a, 0xb2, 0xe4, 0x12, 0x90, 0x9e,
0xfe, 0xd5, 0xd4, 0x6e, 0x6b, 0xf8, 0x33, 0x5b,
0xea, 0x57, 0x63, 0x43, 0xe2, 0xfc, 0x3b, 0x80,
0xca, 0x51, 0x50, 0xa1, 0x8e, 0x51, 0x62, 0xe8,
0x3d, 0xeb, 0x38, 0x56, 0xce, 0x4e, 0x54, 0x07,
0x1f, 0x52, 0x35, 0x2e, 0x77, 0x33, 0xc3, 0x67,
0x9e, 0xf3, 0x47, 0xb7, 0xe7, 0x32, 0xd9, 0x63
},
{
0x3f, 0xe6, 0x4e, 0x71, 0x3c, 0x49, 0x73, 0x17,
0xab, 0xcc, 0x06, 0x20, 0x0c, 0xff, 0x76, 0x0c,
0xcc, 0xee, 0x2b, 0x86, 0xa0, 0x82, 0x2e, 0xed,
0x11, 0x85, 0x04, 0x68, 0x55, 0xdb, 0x42, 0x18,
0xd3, 0x06, 0x02, 0x58, 0xcb, 0x2f, 0x21, 0xe7,
0x9d, 0xec, 0x1e, 0xd2, 0x8f, 0xce, 0xad, 0x58,
0x9a, 0xb1, 0xba, 0x7e, 0x69, 0xcf, 0x4f, 0x2f,
0x8a, 0x8f, 0x4a, 0x4f, 0xd5, 0x81, 0xbe, 0x88,
0xa6, 0x92, 0xad, 0x9b, 0x70, 0x84, 0x84, 0x96,
0x5f, 0xde, 0x70, 0xc6, 0xdc, 0xb8, 0x56, 0x63,
0x9b, 0xef, 0x58, 0xf6, 0x58, 0xe6, 0xc5, 0xeb,
0xeb, 0x1b, 0xa0, 0x7e, 0x9e, 0x52, 0xde, 0x00,
0xf5, 0x05, 0x94, 0x05, 0x74, 0x68, 0x0e, 0x27,
0x30, 0x1e, 0x2c, 0xb1, 0x98, 0x06, 0xdb, 0x1c,
0x6c, 0x35, 0x9f, 0xda, 0x5a, 0x52, 0xec, 0x1b,
0xba, 0x98, 0x59, 0xc1, 0xc3, 0x9c, 0x55, 0x8f
},
{
0x0e, 0x85, 0xd8, 0x46, 0xa2, 0x69, 0x86, 0x14,
0x6f, 0xb8, 0x42, 0x83, 0xeb, 0xbc, 0x2b, 0x94,
0xd2, 0xb3, 0x75, 0xd7
}
},
{
"sansa", 0,
{
0xa8, 0x0c, 0x7c, 0x63, 0x0b, 0xd0, 0x0b, 0xd2,
0xa1, 0x9e, 0xd4, 0xeb, 0x15, 0x1c, 0x8b, 0xd5,
0xc1, 0x11, 0x55, 0xa3, 0x60, 0x50, 0x45, 0xdb,
0x7d, 0x44, 0xe4, 0xb4, 0xde, 0xed, 0xcb, 0xe2,
0xdb, 0x28, 0xd5, 0xcf, 0xc0, 0xbc, 0x44, 0x56,
0x9d, 0x62, 0x7b, 0x5a, 0x97, 0x96, 0x13, 0xac,
0x8c, 0x4c, 0xf7, 0x6b, 0x06, 0xa6, 0xf3, 0x9b,
0xd5, 0xe4, 0xe0, 0x14, 0x4e, 0xb1, 0x4a, 0x5d,
0x2f, 0xb3, 0xa0, 0x66, 0x89, 0xeb, 0x1e, 0x46,
0xc3, 0x21, 0x65, 0x15, 0x63, 0x68, 0x7e, 0xf3,
0x75, 0xd5, 0x5d, 0xd3, 0x70, 0x17, 0xcc, 0x97,
0xb4, 0xce, 0xe3, 0x21, 0x0a, 0x99, 0xfc, 0xcb,
0x60, 0x05, 0xc7, 0x13, 0xd7, 0x0b, 0x34, 0xcd,
0x56, 0xaf, 0x8d, 0x4c, 0x59, 0xe8, 0xe3, 0xd7,
0x2f, 0xef, 0xf1, 0x58, 0xf1, 0xa0, 0xb2, 0x07,
0xac, 0x07, 0xce, 0x2c, 0x5d, 0xe1, 0x1d, 0x85
},
{
0xa9, 0xd0, 0xdf, 0xef, 0xa3, 0x3a, 0x10, 0x65,
0xb6, 0x4f, 0x86, 0x46, 0x39, 0xa9, 0xea, 0xc9,
0x00, 0xea, 0x48, 0xed
},
{
0x1b, 0x5b, 0xe5, 0x3e, 0xf6, 0xd6, 0x50, 0x17,
0xc0, 0x93, 0x87, 0x73, 0x5b, 0x6d, 0x0e, 0xb0,
0x86, 0xb9, 0x78, 0x7b, 0x4e, 0x6c, 0x2d, 0x2a,
0xf3, 0x2c, 0x4c, 0x49, 0xac, 0xca, 0x01, 0xa4,
0x10, 0x83, 0x1a, 0xac, 0x1c, 0x1e, 0x24, 0xbf,
0x25, 0x2d, 0x02, 0x3b, 0x78, 0x29, 0xb6, 0xde,
0x1b, 0x67, 0xef, 0x95, 0xc9, 0xe9, 0x60, 0x95,
0x95, 0x4f, 0xfd, 0xb2, 0x69, 0x16, 0x78, 0xdf,
0x8b, 0x4a, 0xf2, 0xf8, 0xbc, 0xa4, 0x31, 0x7a,
0x1c, 0xb7, 0xc6, 0xa4, 0x0a, 0xb1, 0x36, 0xa2,
0x31, 0x9f, 0x2b, 0x20, 0x31, 0x72, 0x65, 0xa0,
0x4b, 0x99, 0x9a, 0xd0, 0x39, 0xb2, 0x50, 0x27,
0x7b, 0x4f, 0x2b, 0x2f, 0x08, 0x58, 0x6a, 0x62,
0x28, 0xb3, 0xa9, 0x9f, 0x87, 0xe9, 0x33, 0xe4,
0x4d, 0x73, 0x52, 0x1a, 0xcf, 0x5a, 0x79, 0x98,
0xa6, 0xd1, 0x60, 0xc6, 0x59, 0xc9, 0x6e, 0xb7
},
{
0x5b, 0xb9, 0xd2, 0x9b, 0x6e, 0x29, 0x2d, 0x38,
0xd4, 0x11, 0x12, 0x6f, 0xb0, 0x97, 0x40, 0x2d,
0xef, 0xde, 0xd4, 0x93, 0xfc, 0x5e, 0x70, 0x5d,
0x1f, 0xfe, 0x7f, 0xac, 0x56, 0xba, 0x48, 0x8a,
0x9c, 0xa0, 0x39, 0x9c, 0xea, 0x8b, 0xa6, 0x2a,
0x1d, 0x08, 0x53, 0x79, 0x6a, 0xf7, 0xeb, 0xb6,
0xde, 0xf3, 0x58, 0x0a, 0x63, 0x89, 0x98, 0x0d,
0x83, 0x8e, 0x3c, 0x6c, 0xd3, 0x77, 0x8e, 0x71,
0x90, 0x2d, 0xc1, 0xe3, 0x31, 0xb5, 0x26, 0x21,
0xb2, 0x9b, 0x47, 0x7d, 0x56, 0x9b, 0x4c, 0x87,
0x2b, 0x74, 0xc5, 0xbc, 0xa4, 0x35, 0xc9, 0x26,
0xe0, 0x88, 0xff, 0xc6, 0xaf, 0x69, 0x19, 0x5f,
0x6c, 0x1d, 0xff, 0xd9, 0x79, 0x46, 0x33, 0x14,
0xea, 0xb1, 0x2b, 0x50, 0xe4, 0xa9, 0xce, 0x9e,
0x13, 0x4b, 0x87, 0x92, 0x4a, 0x5f, 0x65, 0x1e,
0x83, 0x71, 0x25, 0x56, 0x6d, 0x05, 0x2f, 0x7f
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{ "sansa_gh", 0,
{
0xe2, 0x63, 0xaa, 0x46, 0x26, 0x43, 0xd7, 0x78,
0xf0, 0x4e, 0x6c, 0x91, 0x7c, 0xc1, 0xca, 0x0d,
0xa8, 0xff, 0x1d, 0xbb, 0xcd, 0x30, 0x2a, 0x98,
0x16, 0x9e, 0x48, 0x3a, 0x3f, 0x39, 0xbc, 0xe4,
0xd1, 0xb6, 0xdd, 0xf7, 0x86, 0x50, 0x4b, 0x69,
0x14, 0xa4, 0xe7, 0xd1, 0x36, 0xdd, 0xf7, 0xd5,
0x7f, 0xf0, 0x31, 0xdb, 0xa0, 0x3b, 0x3a, 0x7b,
0xc3, 0x88, 0xa6, 0xce, 0x03, 0x54, 0x3d, 0x8a,
0xf6, 0x8a, 0xf0, 0x07, 0xd1, 0x0b, 0x28, 0x84,
0xe6, 0x3a, 0xbb, 0x7b, 0x51, 0x8e, 0xb0, 0xe5,
0x2f, 0xdd, 0x81, 0xde, 0x17, 0x0c, 0x77, 0xac,
0x47, 0xdf, 0x0f, 0xf8, 0x2a, 0x1a, 0xf6, 0x10,
0xb4, 0xca, 0x04, 0xa5, 0x9d, 0xda, 0xa7, 0xc3,
0xb3, 0xf2, 0x26, 0xd0, 0x2c, 0x01, 0x80, 0x4c,
0xf9, 0xf1, 0xb4, 0xe9, 0x20, 0x9d, 0xc8, 0xf4,
0x79, 0x1e, 0x64, 0x8d, 0x52, 0x35, 0x9e, 0xa9
},
{
0xa8, 0xca, 0xd9, 0x11, 0xab, 0xba, 0x6e, 0x7a,
0x99, 0xce, 0x5d, 0x96, 0xf4, 0x47, 0xa2, 0xf8,
0xb9, 0xbc, 0xf4, 0x95
},
{
0x4e, 0x89, 0x34, 0x05, 0x8d, 0x6f, 0xbf, 0x5f,
0x2f, 0x3d, 0x01, 0x81, 0xdf, 0x53, 0xbd, 0x18,
0x9a, 0x41, 0x79, 0xfc, 0x50, 0x12, 0x3f, 0x29,
0xbb, 0xf0, 0x04, 0x4b, 0x81, 0xd7, 0x7c, 0x36,
0x58, 0xeb, 0x6d, 0xca, 0x5f, 0xb5, 0xac, 0xf4,
0x95, 0xdc, 0x9d, 0x3b, 0x64, 0xba, 0x1b, 0x02,
0xc4, 0x0a, 0xdf, 0x4f, 0xa1, 0x1f, 0x47, 0xae,
0xe0, 0x96, 0x79, 0x14, 0x02, 0x17, 0xc0, 0x26,
0x16, 0xf5, 0xbd, 0x13, 0x81, 0x64, 0x2c, 0xd6,
0x2d, 0x0d, 0xf9, 0x06, 0x3e, 0xbe, 0x0b, 0x9a,
0xdf, 0x25, 0xe9, 0xa8, 0x50, 0xcb, 0x65, 0x31,
0x3f, 0x32, 0xc8, 0xe2, 0xc4, 0x51, 0x2a, 0x29,
0xdc, 0x8f, 0xb2, 0x7a, 0xd7, 0x8a, 0xe4, 0x5f,
0x68, 0xd0, 0x61, 0x7b, 0x66, 0xaf, 0x5f, 0x0c,
0x7d, 0xc1, 0x74, 0x11, 0x8d, 0x3d, 0xdf, 0x36,
0xcc, 0x06, 0x27, 0x19, 0xac, 0x88, 0x2f, 0xdd
},
{
0x8c, 0x2f, 0x28, 0x3f, 0x94, 0x60, 0xc5, 0xb6,
0xae, 0xa7, 0x0e, 0xea, 0x92, 0x24, 0xbd, 0x65,
0xc1, 0xc4, 0x6c, 0xe1, 0x7e, 0xc0, 0x0b, 0x29,
0xdd, 0xcf, 0xbe, 0x5f, 0xab, 0x7d, 0x12, 0xda,
0x46, 0x4c, 0x57, 0xda, 0xff, 0x63, 0xd3, 0x18,
0xab, 0x4f, 0x4e, 0xcf, 0x18, 0x93, 0x4b, 0xb8,
0x05, 0x44, 0xc6, 0x64, 0x3a, 0xe1, 0x8d, 0x76,
0x94, 0xc6, 0x4c, 0xa6, 0x4b, 0x16, 0xec, 0x00,
0xcc, 0xe6, 0xc0, 0xc8, 0x73, 0x70, 0x14, 0x81,
0xea, 0xde, 0x4e, 0xae, 0x67, 0x78, 0x61, 0x90,
0x7d, 0x4b, 0x45, 0xca, 0x23, 0x69, 0x26, 0x68,
0xf1, 0xa0, 0x77, 0x03, 0x09, 0x33, 0x25, 0xa1,
0x12, 0xe8, 0x30, 0x8f, 0x30, 0xf4, 0xaf, 0xbd,
0xea, 0xe0, 0x66, 0x59, 0x5f, 0x81, 0xd6, 0x3b,
0x20, 0xc9, 0x80, 0x61, 0xb1, 0xa1, 0x6b, 0x81,
0x21, 0x83, 0x5f, 0xeb, 0x43, 0x0e, 0xf1, 0xe1
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{ "sansa_103", 0,
{
0xfd, 0xfc, 0xe0, 0xbd, 0x38, 0xdd, 0x8c, 0x7a,
0xf5, 0xbc, 0x5a, 0x38, 0x9a, 0xf8, 0x83, 0xab,
0x4b, 0x3b, 0xf6, 0xc9, 0xcd, 0x47, 0x4c, 0xaa,
0x83, 0xd0, 0x1d, 0xbe, 0xbc, 0x85, 0x48, 0x9d,
0x97, 0x3e, 0x12, 0xef, 0xa3, 0x8b, 0xd9, 0xf6,
0xd6, 0x9c, 0x2d, 0x6d, 0x3e, 0xb9, 0xe4, 0x5c,
0x0c, 0xea, 0xf1, 0x3d, 0xfd, 0x17, 0x96, 0xa5,
0xf1, 0x7f, 0x0f, 0xf3, 0x23, 0x15, 0x67, 0xb2,
0xfc, 0x1a, 0x6d, 0xc9, 0xb4, 0x59, 0x93, 0xdb,
0xb8, 0x22, 0x1a, 0xbf, 0xc2, 0x7e, 0xd0, 0xb9,
0x8a, 0x75, 0xe3, 0x8a, 0x6a, 0x34, 0x15, 0x19,
0x66, 0x66, 0xcb, 0xb0, 0x74, 0x95, 0x80, 0x51,
0xd6, 0x94, 0xb3, 0x23, 0x4a, 0xd4, 0xee, 0xa2,
0x29, 0xaa, 0xf2, 0x2f, 0x1e, 0x56, 0x36, 0x87,
0x66, 0x48, 0x30, 0x55, 0xc7, 0x92, 0x81, 0x59,
0xe9, 0x41, 0xdc, 0xa2, 0x4d, 0x0c, 0x80, 0x6b
},
{
0xb0, 0xfc, 0xd0, 0x79, 0xdb, 0x66, 0xdd, 0xde,
0x86, 0x31, 0x96, 0xdb, 0x63, 0xb1, 0x7f, 0xf9,
0xd4, 0x06, 0xaa, 0xbd
},
{
0xed, 0xb2, 0x59, 0x43, 0xa0, 0x4f, 0x36, 0xb8,
0x20, 0x6a, 0x09, 0x87, 0xfa, 0xd3, 0xf6, 0x32,
0x35, 0x7d, 0xed, 0xbc, 0x6c, 0xca, 0x38, 0x8b,
0x82, 0xb9, 0x82, 0x1f, 0x31, 0x80, 0x6b, 0xe1,
0x74, 0xc6, 0x6b, 0xc2, 0x85, 0x8b, 0x43, 0x84,
0xda, 0xd1, 0x7e, 0xc1, 0xff, 0x2c, 0xb1, 0x78,
0x00, 0x76, 0x55, 0x46, 0x94, 0x68, 0x56, 0x42,
0x4d, 0x7b, 0xb2, 0x91, 0x90, 0x2f, 0xb0, 0xff,
0x0a, 0x52, 0x66, 0x35, 0x3b, 0x10, 0x9d, 0x4b,
0x26, 0x5b, 0x0b, 0x1f, 0x8a, 0x6c, 0x71, 0x35,
0x5d, 0x03, 0x87, 0x69, 0x28, 0xd1, 0x59, 0x35,
0x3c, 0xd9, 0x12, 0x3a, 0x08, 0x37, 0xd7, 0x3c,
0x33, 0x22, 0x82, 0xcc, 0xab, 0x24, 0x3b, 0x48,
0x56, 0x15, 0xbf, 0xb3, 0x18, 0x3a, 0xe5, 0x80,
0xa5, 0x25, 0xa8, 0xdf, 0x69, 0x5f, 0x03, 0x75,
0x64, 0xe4, 0x31, 0xc5, 0xd9, 0x43, 0x29, 0xf6
},
{
0xb3, 0x03, 0x82, 0x02, 0xa7, 0x1d, 0x65, 0xd4,
0x9e, 0xe1, 0xee, 0xfc, 0x16, 0x91, 0x82, 0xaf,
0x7f, 0xb9, 0x2f, 0x83, 0x55, 0xe8, 0xb3, 0x6b,
0x1c, 0x00, 0x72, 0x20, 0x6c, 0x3a, 0xa6, 0x58,
0x70, 0x2b, 0xec, 0x31, 0x45, 0x5f, 0x56, 0x9d,
0x62, 0x18, 0xb3, 0x9e, 0xeb, 0x5a, 0x9d, 0x81,
0x50, 0xa2, 0x6f, 0xe9, 0xd2, 0x83, 0xd4, 0x7a,
0x71, 0xbf, 0x4e, 0x73, 0xf7, 0xeb, 0x26, 0x2d,
0x32, 0x22, 0xec, 0xfb, 0x7f, 0x42, 0x68, 0x9d,
0x73, 0xb5, 0x3b, 0xbd, 0x6a, 0xec, 0x01, 0x23,
0x9a, 0x20, 0x16, 0x6d, 0x72, 0x86, 0x47, 0x18,
0xd6, 0xea, 0x6a, 0x9a, 0xa7, 0xe4, 0xfe, 0x2c,
0x1f, 0x63, 0x92, 0x12, 0x78, 0x12, 0x58, 0x88,
0x27, 0x63, 0x78, 0xa0, 0x26, 0x11, 0x7b, 0xa4,
0x00, 0x56, 0x2a, 0xc0, 0x7e, 0xc4, 0xde, 0x0f,
0x92, 0x05, 0x30, 0x42, 0xd9, 0x02, 0x4c, 0xad
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{ "rhapsody", 0,
{
0xdc, 0xa3, 0xcd, 0xec, 0x52, 0x1a, 0x04, 0xc5,
0xd4, 0xf6, 0x6f, 0x9d, 0x66, 0x31, 0x48, 0xd4,
0x3b, 0xe8, 0x2c, 0x18, 0x33, 0x66, 0x11, 0x22,
0x05, 0xf5, 0xce, 0x09, 0xaf, 0x63, 0x9b, 0x45,
0xc0, 0x74, 0x5d, 0x2f, 0xd0, 0x53, 0x4f, 0xbd,
0xdf, 0xe5, 0xa0, 0x47, 0xc1, 0xe5, 0x18, 0x11,
0xee, 0x70, 0x57, 0x37, 0xeb, 0x8d, 0x48, 0xe5,
0x91, 0x09, 0x82, 0xf3, 0x20, 0x95, 0x44, 0xbb,
0xcf, 0xc2, 0x2f, 0x47, 0x65, 0x4b, 0x3c, 0xf2,
0xe4, 0xbf, 0x7c, 0x92, 0x22, 0xd6, 0x54, 0xb7,
0x2c, 0x15, 0x19, 0x99, 0x10, 0x54, 0xe6, 0x9b,
0x50, 0xf3, 0xdc, 0xae, 0x7f, 0x35, 0xca, 0xeb,
0xe8, 0x51, 0xa5, 0x9a, 0xfc, 0x9b, 0x30, 0x58,
0x5a, 0xe9, 0x17, 0xc8, 0x58, 0x19, 0x51, 0x92,
0xa6, 0xe3, 0xd6, 0x50, 0x0b, 0x43, 0x02, 0x6f,
0x5c, 0x0c, 0x71, 0x6f, 0x66, 0x17, 0xb6, 0xf5
},
{
0x87, 0xa0, 0x96, 0xfe, 0x31, 0x4e, 0x8e, 0xe0,
0x5c, 0xcf, 0xc0, 0x0d, 0x2c, 0xa9, 0xe8, 0xd9,
0x3d, 0x9f, 0x9c, 0x63
},
{
0x47, 0xee, 0xad, 0x3c, 0x5f, 0x41, 0xe3, 0x46,
0x75, 0xa9, 0x51, 0xeb, 0xed, 0xbc, 0xb3, 0xe1,
0x4e, 0x99, 0x05, 0x62, 0x37, 0xc6, 0xd5, 0x53,
0x2c, 0x5f, 0xd9, 0xf0, 0xe9, 0xcd, 0x18, 0x25,
0xc2, 0x5b, 0x45, 0xc8, 0xfe, 0x6f, 0x6c, 0x63,
0x1f, 0xe2, 0x50, 0xeb, 0xba, 0x95, 0x08, 0xb8,
0x35, 0x1a, 0x83, 0x30, 0xd2, 0x3d, 0x64, 0x6f,
0xae, 0xec, 0x9f, 0x69, 0xbb, 0xa1, 0x89, 0xcd,
0x49, 0x4c, 0x8a, 0x71, 0x4f, 0xb1, 0x78, 0xc9,
0x05, 0x75, 0x27, 0xcb, 0x96, 0xe3, 0x48, 0x84,
0xf2, 0xb6, 0xec, 0x07, 0x89, 0x8a, 0x6e, 0xa6,
0xf3, 0x38, 0x3e, 0xb8, 0x50, 0x2c, 0xa3, 0x4e,
0x31, 0xf8, 0xaa, 0x1f, 0xe9, 0xea, 0xc4, 0x88,
0xaf, 0xd9, 0x1e, 0xa2, 0x9d, 0xeb, 0x03, 0x07,
0x83, 0x73, 0xd9, 0x79, 0xbd, 0xa8, 0xf7, 0x14,
0xd1, 0xbf, 0xbf, 0x1a, 0x92, 0x3a, 0x84, 0x7e
},
{
0x2d, 0x77, 0x4f, 0xb2, 0x52, 0x21, 0x92, 0x52,
0xf9, 0x9a, 0xa5, 0xb9, 0x81, 0xbf, 0x7e, 0x38,
0x60, 0xa0, 0x0a, 0x93, 0x0a, 0x3f, 0xec, 0xc6,
0x24, 0x70, 0xce, 0x8c, 0x1f, 0xf4, 0x1b, 0x2a,
0xdd, 0xf4, 0x4a, 0xaa, 0x79, 0xf6, 0x84, 0xc0,
0x2b, 0x7b, 0x55, 0x4b, 0xec, 0x23, 0x2c, 0x9f,
0xe7, 0x70, 0xf5, 0x68, 0xea, 0xf8, 0xf9, 0x09,
0x7c, 0x4f, 0x3a, 0x70, 0x7c, 0xb9, 0x7b, 0xf9,
0x7d, 0x79, 0x42, 0xfc, 0xd8, 0xfd, 0x54, 0xa4,
0x3e, 0xb6, 0xe4, 0x9a, 0xff, 0x0b, 0x2b, 0x59,
0x5c, 0xe5, 0x39, 0x35, 0xb7, 0x30, 0xfe, 0xa0,
0x56, 0xc5, 0x5e, 0xbb, 0x52, 0x95, 0xbf, 0xf4,
0x59, 0xf4, 0x0b, 0xc4, 0x24, 0xe9, 0x35, 0x17,
0x6c, 0x10, 0xc6, 0xb4, 0x69, 0xf2, 0xf3, 0x61,
0x86, 0x54, 0x9a, 0x94, 0x43, 0x1c, 0x1c, 0xa5,
0xd5, 0x20, 0xfa, 0xcb, 0xbc, 0x88, 0xef, 0x05
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{
"20gc_eng", 0,
{
0xfa, 0xdb, 0x17, 0x9c, 0x7a, 0x07, 0x70, 0xb7,
0x2e, 0x8b, 0xdf, 0x33, 0x82, 0x1c, 0x00, 0xa8,
0x31, 0xce, 0x64, 0x8f, 0xa4, 0x64, 0xb4, 0x0b,
0x23, 0x01, 0x0d, 0xcd, 0x49, 0x68, 0x1e, 0x32,
0xf6, 0x07, 0x89, 0xa7, 0x89, 0x8b, 0x40, 0xca,
0x7e, 0xd9, 0x78, 0xe7, 0x11, 0x1b, 0x17, 0x58,
0x9f, 0x90, 0xea, 0x2a, 0x01, 0xfd, 0xce, 0xfe,
0x17, 0x63, 0x9b, 0xf1, 0xdd, 0x18, 0x30, 0xc7,
0xfa, 0x10, 0x12, 0xb6, 0x82, 0x18, 0x0f, 0xf5,
0xc1, 0xb1, 0x88, 0xdb, 0xbb, 0xbd, 0x57, 0xcf,
0x93, 0x32, 0xc2, 0x35, 0x4d, 0x72, 0x92, 0xbb,
0x7c, 0xcd, 0xaa, 0x9c, 0x33, 0x1a, 0x41, 0xb0,
0xd9, 0x58, 0x0d, 0xbd, 0xc1, 0x2f, 0xb8, 0x1f,
0x45, 0xf4, 0x06, 0xc5, 0x61, 0x24, 0x2d, 0x6e,
0x4a, 0xe8, 0x55, 0x24, 0x41, 0x58, 0x05, 0xbf,
0x21, 0x75, 0x5b, 0x77, 0x88, 0x10, 0x93, 0x5d
},
{
0xad, 0xf1, 0xbe, 0x09, 0x32, 0x14, 0x76, 0x7c,
0x0b, 0xae, 0xc4, 0x74, 0xf5, 0xf7, 0xb1, 0x8b,
0x20, 0xd1, 0xac, 0x65
},
{
0x4d, 0xce, 0xf4, 0x78, 0x5d, 0x75, 0xed, 0x39,
0xd5, 0x58, 0x70, 0xfe, 0x1e, 0x25, 0x91, 0x9c,
0xaf, 0x20, 0x4f, 0x53, 0x38, 0x42, 0xea, 0x71,
0x26, 0x63, 0xe9, 0xcf, 0x54, 0x31, 0xe6, 0x77,
0xbd, 0x70, 0xd5, 0xcd, 0x94, 0x80, 0xcf, 0x05,
0xa3, 0x92, 0xac, 0x20, 0x77, 0xf2, 0x0f, 0xe5,
0xa1, 0x09, 0x90, 0xe0, 0x4b, 0xb6, 0x4b, 0x3c,
0x59, 0xdb, 0x2b, 0x63, 0x04, 0x15, 0xa0, 0xe9,
0xfc, 0x64, 0x94, 0x9e, 0x82, 0x8b, 0xa7, 0x3f,
0xa1, 0x80, 0x67, 0xfd, 0xf9, 0xc9, 0x30, 0x72,
0x2f, 0x9b, 0x2a, 0x37, 0xa2, 0xa4, 0x34, 0xc7,
0x87, 0x0d, 0x61, 0x37, 0x05, 0xa8, 0x91, 0x45,
0xde, 0xe6, 0xc1, 0xad, 0x93, 0xb3, 0x01, 0x84,
0x1b, 0x99, 0xa2, 0x79, 0xd5, 0xe9, 0x75, 0x49,
0x3e, 0x11, 0xd3, 0x3c, 0xaf, 0x18, 0xe8, 0x64,
0x9e, 0x1d, 0xf6, 0xd7, 0x4e, 0x77, 0xb2, 0xc8
},
{
0x18, 0x8c, 0xcd, 0x79, 0x0d, 0x2e, 0x5c, 0xd7,
0x82, 0x53, 0x69, 0xf2, 0x21, 0x15, 0x8d, 0x3e,
0x77, 0xae, 0xb5, 0x34, 0x3b, 0x1b, 0x4c, 0xe0,
0x67, 0xbe, 0x05, 0x99, 0x70, 0xd4, 0x53, 0x63,
0xb4, 0x84, 0xd1, 0xa7, 0xc0, 0xb3, 0xcb, 0xde,
0xc1, 0x25, 0x37, 0x81, 0xb8, 0x2c, 0x4b, 0x26,
0x85, 0xdb, 0xf9, 0xdd, 0xbd, 0xb6, 0x04, 0x57,
0xdd, 0xf0, 0xff, 0x74, 0xfb, 0x16, 0x71, 0xd6,
0xab, 0xcc, 0xfd, 0x05, 0x95, 0xd9, 0x77, 0xe5,
0x86, 0x06, 0x57, 0x1c, 0x7d, 0x37, 0xc3, 0x49,
0xcd, 0xcc, 0x60, 0x80, 0x12, 0x86, 0xc7, 0xac,
0xd5, 0xac, 0xd0, 0x90, 0x94, 0x0c, 0x05, 0xbc,
0x6c, 0x58, 0xdf, 0x3d, 0x51, 0xee, 0x92, 0x28,
0x39, 0x7b, 0xc1, 0x5f, 0x5e, 0xb9, 0x83, 0x59,
0xad, 0xf3, 0xfb, 0xe6, 0xd9, 0x37, 0xc8, 0x8b,
0xe7, 0x24, 0x65, 0xb1, 0xaa, 0xdd, 0x1e, 0x82
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{
"20gc_fre", 0,
{
0xa1, 0xe2, 0x86, 0x4b, 0x4b, 0x73, 0x73, 0x5a,
0x52, 0xb8, 0x5b, 0x79, 0xdb, 0xd6, 0xc9, 0x19,
0x98, 0xb4, 0x19, 0x24, 0xa6, 0x31, 0x68, 0x2f,
0x42, 0xe5, 0x16, 0x64, 0xd3, 0xb4, 0xf7, 0x6d,
0x8c, 0xf4, 0x51, 0x01, 0x91, 0xbb, 0xbe, 0x5d,
0xe5, 0x2f, 0x49, 0xe0, 0xfd, 0x20, 0x7f, 0xcf,
0xa7, 0xc0, 0xd0, 0x4f, 0x6d, 0x54, 0x58, 0xa7,
0xf0, 0x6b, 0x51, 0x19, 0x72, 0x5f, 0x4b, 0x27,
0xe9, 0xdf, 0x4a, 0x2e, 0xce, 0xa9, 0x32, 0xc7,
0x65, 0x61, 0x45, 0xba, 0x7a, 0x48, 0x8b, 0xe4,
0x84, 0x68, 0xb0, 0x68, 0x03, 0x65, 0x55, 0x23,
0x67, 0x58, 0xe3, 0x22, 0x1e, 0x02, 0xb4, 0x50,
0xf2, 0x74, 0x9a, 0x8b, 0x5d, 0x8e, 0x11, 0xa3,
0x66, 0xf4, 0x12, 0xfa, 0x91, 0x70, 0xf6, 0x3a,
0x47, 0x8c, 0xf6, 0x10, 0xa1, 0x22, 0xc5, 0xb5,
0xa4, 0xa0, 0x6f, 0x77, 0x2f, 0x90, 0x41, 0xcb
},
{
0x99, 0xe7, 0xd9, 0x89, 0x34, 0x0b, 0xf4, 0x35,
0xfb, 0xb8, 0xaf, 0x05, 0x55, 0xb6, 0x30, 0x9a,
0x47, 0xba, 0xd4, 0xb1
},
{
0x04, 0xea, 0x5e, 0x31, 0x8a, 0xd3, 0x57, 0x1a,
0x9a, 0xd2, 0x24, 0x78, 0xfa, 0xd7, 0xd5, 0x35,
0x46, 0xcf, 0x4a, 0xc4, 0xb9, 0x8d, 0x5d, 0x80,
0x3d, 0x23, 0xc5, 0x42, 0x06, 0x38, 0x59, 0x0c,
0x32, 0x2e, 0x52, 0xbd, 0x54, 0xd0, 0x40, 0xee,
0x78, 0x02, 0xb5, 0x5d, 0xd4, 0x87, 0xe2, 0xe7,
0x69, 0x90, 0x5a, 0x8b, 0xa1, 0x39, 0xcb, 0x40,
0x5f, 0xb9, 0xf0, 0xf7, 0x3d, 0x97, 0x32, 0x74,
0x20, 0x45, 0xeb, 0xbf, 0xcc, 0xd7, 0xf7, 0x32,
0x8a, 0x06, 0x1b, 0x35, 0xac, 0xaf, 0x12, 0xdb,
0x4e, 0x63, 0x57, 0x46, 0x64, 0xbf, 0x3b, 0xe3,
0x1a, 0xec, 0x50, 0x11, 0x39, 0x12, 0x8f, 0x8a,
0xe7, 0x58, 0xfa, 0xd5, 0x66, 0x30, 0x91, 0x3f,
0x81, 0x2c, 0x14, 0xa7, 0x21, 0xc3, 0x16, 0xd7,
0x5e, 0xf6, 0xc8, 0x09, 0x1f, 0x8b, 0x77, 0x99,
0x7e, 0x38, 0xcb, 0x08, 0xc1, 0x10, 0xb1, 0xd7
},
{
0x11, 0x82, 0x78, 0x83, 0x8d, 0x13, 0x49, 0xef,
0x86, 0x12, 0xa5, 0x5f, 0x34, 0x87, 0x02, 0x72,
0x04, 0x51, 0x6d, 0x77, 0x18, 0xbb, 0xf8, 0x23,
0xe0, 0x1e, 0xc8, 0x4d, 0x2e, 0x7d, 0x9b, 0x4c,
0xf0, 0xfc, 0x20, 0x7c, 0xe8, 0x83, 0x20, 0xb2,
0x18, 0x45, 0x0e, 0x91, 0x47, 0x4e, 0x46, 0xa7,
0x5c, 0xe9, 0x28, 0xff, 0x8a, 0xd5, 0xc2, 0xc3,
0xca, 0x40, 0xa0, 0xe0, 0x83, 0xca, 0x48, 0x1d,
0x15, 0x4c, 0xe4, 0xce, 0xf1, 0x11, 0x27, 0xcb,
0x4a, 0x63, 0xdc, 0x35, 0xe0, 0x40, 0xbd, 0x46,
0x6e, 0x08, 0x14, 0x60, 0x9f, 0xd2, 0x22, 0xde,
0x73, 0x9e, 0x6e, 0xc2, 0xf0, 0x7e, 0xa0, 0xc7,
0x48, 0xa3, 0xa2, 0x30, 0x8c, 0xb0, 0xcf, 0xd5,
0x7c, 0xdf, 0x2e, 0xdf, 0xc7, 0xe2, 0x4a, 0x2b,
0x1a, 0xf0, 0x2c, 0xe8, 0x89, 0x88, 0xb2, 0x94,
0x23, 0xfa, 0x92, 0x5c, 0x88, 0x06, 0x3a, 0xe4
}
},
{ "c200", 0,
{
0xcc, 0x4a, 0x93, 0x54, 0x92, 0xaf, 0x53, 0x4a,
0x35, 0xfe, 0xf5, 0x1f, 0xda, 0xe8, 0x9a, 0x44,
0x79, 0x67, 0xb8, 0xb0, 0xc4, 0xbe, 0x54, 0x9b,
0xfe, 0x90, 0x9e, 0x2b, 0x38, 0x3f, 0xdc, 0xc9,
0x9e, 0x5a, 0x21, 0x97, 0x76, 0x78, 0xb1, 0xa0,
0x65, 0x90, 0xb4, 0x19, 0x94, 0xc6, 0xee, 0xac,
0x37, 0x85, 0x1a, 0x5e, 0xda, 0xd2, 0x38, 0xbf,
0x1c, 0x5e, 0x62, 0x6b, 0x7e, 0x18, 0xbd, 0x54,
0x2d, 0xf8, 0x42, 0x48, 0xf1, 0x17, 0x79, 0x98,
0x0e, 0xe3, 0xba, 0x11, 0xbd, 0x2d, 0xc7, 0xd8,
0x79, 0xcc, 0x08, 0x5d, 0x07, 0x5b, 0x81, 0x23,
0x13, 0xf3, 0x93, 0x02, 0x36, 0x85, 0xa2, 0x85,
0x66, 0x9c, 0x19, 0x7f, 0x41, 0x24, 0x62, 0xc8,
0x0a, 0x41, 0xad, 0x0a, 0x4c, 0x47, 0x13, 0x18,
0xc8, 0x22, 0xb4, 0x11, 0x5e, 0xc9, 0x3e, 0xc2,
0x1b, 0xd9, 0xd6, 0x0b, 0x53, 0x6a, 0x52, 0x93
},
{
0xed, 0x8c, 0x60, 0x8f, 0xfe, 0x6f, 0xeb, 0xdf,
0xbd, 0x6c, 0xdf, 0x61, 0x98, 0x85, 0xe4, 0x66,
0x84, 0x63, 0xae, 0x99
},
{
0x5e, 0xd6, 0xde, 0x19, 0x4d, 0xc3, 0xea, 0x65,
0xe7, 0x87, 0x7a, 0x81, 0x01, 0xec, 0x58, 0x9d,
0xf7, 0xab, 0xf8, 0x08, 0x0e, 0x9c, 0x1f, 0x1a,
0xce, 0x81, 0x5a, 0xf3, 0x62, 0x0f, 0xa8, 0x72,
0x43, 0xb4, 0xf3, 0x1f, 0x9b, 0xe3, 0x8b, 0x05,
0x62, 0x36, 0xcc, 0x01, 0x72, 0x5d, 0x5e, 0x0c,
0x58, 0xd2, 0x76, 0x06, 0x0e, 0x03, 0x6f, 0xb5,
0xc6, 0xad, 0x29, 0x2a, 0xe1, 0x57, 0x59, 0xe1,
0x46, 0xde, 0x36, 0x7b, 0x5c, 0xde, 0xa7, 0x63,
0x70, 0x10, 0xd0, 0x6f, 0x65, 0xb4, 0x04, 0xfb,
0xe0, 0x25, 0x46, 0xf9, 0xd6, 0x93, 0xd5, 0x04,
0x8b, 0x31, 0x66, 0x6f, 0xb1, 0x7a, 0xe9, 0xae,
0x26, 0x7e, 0x3e, 0xd9, 0x41, 0x8f, 0x5d, 0x3d,
0xe7, 0x17, 0xe1, 0x58, 0x24, 0x64, 0x46, 0xa5,
0x68, 0x49, 0x66, 0x2f, 0x6c, 0xb3, 0x3c, 0x47,
0x74, 0x5a, 0x10, 0x3e, 0x35, 0xdf, 0xe0, 0x33
},
{
0x6d, 0x00, 0xd4, 0x8e, 0x0e, 0xa1, 0x37, 0x32,
0x83, 0xe3, 0x15, 0x13, 0x2a, 0xf5, 0x41, 0x7d,
0xcf, 0xb9, 0xde, 0x96, 0xd8, 0xb9, 0xed, 0x99,
0xc4, 0xb7, 0xf7, 0x0c, 0x9a, 0x54, 0x4b, 0x93,
0x3a, 0x93, 0x83, 0xb2, 0x99, 0x84, 0x60, 0xa7,
0x3e, 0x95, 0xc1, 0x1c, 0x8c, 0xf2, 0xb8, 0xa5,
0xfd, 0x19, 0x69, 0xf9, 0x57, 0xa5, 0xfc, 0x07,
0xb6, 0xc3, 0x90, 0x39, 0x35, 0xe3, 0x2c, 0x47,
0xd1, 0x20, 0x35, 0x77, 0x04, 0xdd, 0xed, 0xa4,
0x9b, 0x2f, 0x49, 0x14, 0xab, 0xf4, 0xdf, 0xa6,
0xbf, 0x78, 0x8b, 0x4d, 0x19, 0xf4, 0x8f, 0x79,
0xa0, 0x08, 0x65, 0x7e, 0x9b, 0xca, 0x6f, 0x9a,
0xb6, 0x25, 0xe9, 0x82, 0xfa, 0x3c, 0x80, 0x38,
0xfc, 0xa8, 0xb3, 0x9d, 0x5a, 0x2f, 0x93, 0x03,
0x89, 0xf9, 0x54, 0xc5, 0xa8, 0xb5, 0x6c, 0xd4,
0xfd, 0x14, 0x4a, 0x02, 0xcb, 0x9d, 0xd7, 0xb9
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{ "c200_003", 0,
{
0xfd, 0x5b, 0xe2, 0x00, 0xc5, 0x1b, 0x74, 0x03,
0x71, 0x44, 0x17, 0xd2, 0x4c, 0xce, 0xc0, 0x98,
0x71, 0xa7, 0x81, 0x08, 0xd7, 0x46, 0x50, 0x35,
0x26, 0xb8, 0xc6, 0x25, 0x13, 0x70, 0x75, 0x1c,
0x25, 0x56, 0x1a, 0xac, 0xeb, 0x48, 0x51, 0x39,
0x52, 0x92, 0x6a, 0x19, 0x99, 0x18, 0xe5, 0xd2,
0xa0, 0x58, 0x57, 0x12, 0x93, 0xc5, 0xc5, 0xd2,
0x13, 0xbc, 0x8d, 0x8e, 0xa7, 0xd8, 0x70, 0x96,
0x93, 0xba, 0x3f, 0x03, 0x7f, 0x63, 0xb4, 0x65,
0x8a, 0x62, 0xc9, 0x2a, 0x46, 0xdb, 0xe6, 0x68,
0x76, 0x0d, 0x1a, 0x8c, 0x3e, 0xeb, 0x54, 0x2a,
0xf5, 0xd7, 0x5f, 0xa6, 0x52, 0x0b, 0x6c, 0xa8,
0x47, 0x0e, 0x5a, 0x02, 0xa7, 0xff, 0x4b, 0x4a,
0x60, 0xe1, 0x21, 0x4b, 0x8e, 0x10, 0x21, 0x0a,
0x51, 0x6f, 0xde, 0xb1, 0xb0, 0x2d, 0x9e, 0x4a,
0x16, 0x8f, 0xd9, 0x46, 0xed, 0xdc, 0xc8, 0x53
},
{
0xb5, 0x04, 0x89, 0x06, 0xce, 0x8c, 0x0a, 0x57,
0xb8, 0xc9, 0xf6, 0xb6, 0x4d, 0x2f, 0x9f, 0x8a,
0xcf, 0xd2, 0xae, 0xbb
},
{
0x98, 0xc0, 0x07, 0xe7, 0xb7, 0x27, 0x0f, 0x53,
0x06, 0x33, 0xd3, 0xac, 0xee, 0x41, 0x28, 0x6f,
0xf6, 0xb6, 0x82, 0xdf, 0xc8, 0xa3, 0xee, 0x8a,
0xa0, 0x30, 0xc2, 0xec, 0x44, 0xbd, 0xa6, 0x8c,
0x06, 0x35, 0x97, 0x26, 0x02, 0x45, 0x97, 0x5c,
0xac, 0x9e, 0x9b, 0xb0, 0x09, 0xb9, 0x39, 0xaa,
0x86, 0xda, 0x0f, 0x0b, 0x67, 0x9d, 0xa5, 0xa2,
0xf1, 0x28, 0x7c, 0x03, 0x4d, 0x46, 0xcc, 0x52,
0x66, 0x3f, 0x19, 0x68, 0x31, 0x22, 0x2e, 0xaa,
0xa8, 0xc4, 0xbf, 0xcd, 0xc9, 0xc7, 0x24, 0x34,
0x63, 0xea, 0x36, 0xa8, 0x79, 0xba, 0x46, 0xf3,
0x0d, 0xd4, 0x28, 0x30, 0x2d, 0xdd, 0x57, 0xaa,
0x4a, 0x05, 0xf5, 0x14, 0xa4, 0xb6, 0xea, 0x5c,
0x2a, 0xe5, 0x28, 0x55, 0x06, 0x13, 0x2d, 0xdb,
0x2b, 0xe0, 0xfc, 0x23, 0x93, 0x1b, 0xb3, 0xa1,
0x47, 0xee, 0x27, 0x9d, 0x5c, 0xaa, 0x87, 0xdb
},
{
0x71, 0xbb, 0x19, 0x53, 0xa8, 0xf6, 0x04, 0x29,
0x62, 0xfd, 0xfc, 0xb9, 0x42, 0x03, 0x78, 0x75,
0xc9, 0xf6, 0x6a, 0x68, 0x93, 0xc3, 0x56, 0xf2,
0x0f, 0xd3, 0xb6, 0xa0, 0xc1, 0x08, 0xa8, 0x86,
0x5e, 0x7b, 0xbb, 0xaa, 0x1e, 0x42, 0x4c, 0x05,
0x09, 0x66, 0x3c, 0xac, 0x05, 0x75, 0x33, 0xcb,
0x44, 0xe7, 0x19, 0xa1, 0xe0, 0x7b, 0xc7, 0x93,
0xbd, 0x10, 0xc0, 0x5c, 0x09, 0xba, 0xf8, 0xe7,
0x19, 0xf9, 0x0c, 0x83, 0xe0, 0x51, 0x3d, 0x77,
0xb8, 0x3b, 0x56, 0x27, 0x98, 0xa5, 0x7c, 0xb1,
0xca, 0xc8, 0xfe, 0x98, 0xab, 0xc6, 0x9a, 0xd4,
0x1d, 0x8e, 0x8e, 0x75, 0x78, 0x79, 0xd4, 0x5e,
0xc1, 0xa1, 0x75, 0xbe, 0xdd, 0xd1, 0x1f, 0x2a,
0xc2, 0xda, 0x1c, 0x3d, 0x46, 0xd8, 0x5a, 0xec,
0x45, 0x95, 0x71, 0x79, 0x42, 0xa5, 0xd6, 0xae,
0x27, 0x4a, 0x7a, 0x80, 0x2d, 0x48, 0x84, 0x45
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{ "c200_106", 0,
{
0x8f, 0xa7, 0xf1, 0x03, 0xf0, 0x84, 0x50, 0xcf,
0x67, 0xff, 0x97, 0xdb, 0xdb, 0xdb, 0x6d, 0xc2,
0x75, 0x94, 0xee, 0x5b, 0xf5, 0xeb, 0x70, 0x41,
0x6a, 0x98, 0xc1, 0xff, 0x5b, 0x54, 0x74, 0x9d,
0x25, 0x1b, 0x6b, 0x80, 0x7a, 0xae, 0x62, 0xbe,
0xd5, 0xb8, 0xe7, 0x04, 0xc7, 0x0c, 0xf2, 0x3b,
0xc4, 0x5f, 0xc9, 0x47, 0xd2, 0xd7, 0x1b, 0xcf,
0xf7, 0xb9, 0xe0, 0xaa, 0xb0, 0x4c, 0x29, 0x04,
0xc5, 0xf0, 0x9f, 0xf0, 0xb0, 0xa0, 0x96, 0xf9,
0xd0, 0x15, 0x91, 0x77, 0xd1, 0xcb, 0x67, 0x3b,
0x6c, 0x4f, 0x7e, 0x3b, 0xe1, 0xce, 0x01, 0x18,
0x5d, 0xc1, 0xdc, 0x1b, 0xbd, 0xe5, 0x51, 0xe2,
0x0a, 0x99, 0x95, 0xd1, 0x9d, 0x55, 0x43, 0xc5,
0x1e, 0xaf, 0xc4, 0x29, 0x37, 0xc4, 0x86, 0x8f,
0xf8, 0xbc, 0x24, 0xb2, 0x65, 0x4a, 0x8e, 0x12,
0x25, 0x6f, 0x65, 0x96, 0x5c, 0xe9, 0x6e, 0xb7
},
{
0x9b, 0x96, 0x25, 0x25, 0x70, 0xf3, 0x26, 0x48,
0x42, 0x5a, 0x4e, 0x35, 0xa5, 0x72, 0x09, 0x8a,
0x1e, 0xd1, 0x04, 0x71
},
{
0x23, 0xd7, 0x86, 0x2c, 0x96, 0x23, 0x6e, 0x1c,
0x2c, 0xb6, 0xf0, 0x13, 0x5f, 0xb8, 0x5f, 0x17,
0x29, 0x58, 0x55, 0xb4, 0x7b, 0x4f, 0x82, 0x0f,
0xf0, 0xde, 0xf2, 0x28, 0xf6, 0xdc, 0x82, 0xf1,
0x63, 0xd8, 0x8c, 0xa1, 0xf9, 0xeb, 0xea, 0x18,
0x64, 0xeb, 0x4b, 0x13, 0xff, 0xb7, 0x6d, 0x5a,
0x5f, 0x14, 0x08, 0x7d, 0xbf, 0xb9, 0x44, 0x9c,
0x2e, 0xc7, 0x6e, 0x72, 0x33, 0xa0, 0x99, 0xd0,
0xac, 0x61, 0x6a, 0xf8, 0xa8, 0x7a, 0x96, 0x5d,
0x1a, 0xb6, 0x0f, 0xad, 0xb6, 0x5b, 0xf4, 0xd8,
0xf8, 0x85, 0xd0, 0xc2, 0x98, 0xf2, 0xf3, 0x30,
0xf8, 0x70, 0x52, 0x5d, 0xf3, 0xff, 0x64, 0xb3,
0x2a, 0xf4, 0x71, 0x00, 0x6c, 0x99, 0xa1, 0x7a,
0x0e, 0x8b, 0xf3, 0x08, 0xed, 0xbb, 0xb8, 0x44,
0x86, 0x36, 0x5c, 0xc0, 0xaa, 0x8c, 0xb3, 0xfe,
0xaa, 0x2d, 0x14, 0xd5, 0xbe, 0xc0, 0x57, 0x33
},
{
0x24, 0xc1, 0x4e, 0xb0, 0xcb, 0x1f, 0x39, 0x1b,
0x30, 0x9c, 0xaf, 0x98, 0x09, 0x32, 0xea, 0x0a,
0xb2, 0x21, 0xd6, 0xfd, 0xbb, 0x05, 0x1b, 0xa4,
0x93, 0xfe, 0xf5, 0x83, 0x76, 0x33, 0xb6, 0x97,
0x78, 0x26, 0xf4, 0x93, 0x1d, 0xd2, 0x22, 0x92,
0xce, 0xe1, 0x1d, 0xab, 0xac, 0xb9, 0xc2, 0xfb,
0x6e, 0x9b, 0xb2, 0xa0, 0x3a, 0x70, 0x4c, 0xa6,
0xa0, 0xbd, 0xc7, 0xe1, 0x12, 0x71, 0x23, 0x6e,
0xa7, 0x75, 0x85, 0x75, 0x2a, 0x70, 0x17, 0xfd,
0x49, 0x75, 0xd6, 0xce, 0x3a, 0x4d, 0x45, 0xa3,
0x1c, 0x88, 0x40, 0x3e, 0xb2, 0xea, 0x30, 0xae,
0x98, 0x54, 0x79, 0xdf, 0x5e, 0x53, 0xe8, 0xab,
0xa2, 0xd0, 0xf0, 0x90, 0x3e, 0x9e, 0x1d, 0x9e,
0x0e, 0x30, 0x34, 0x4b, 0xde, 0x85, 0xd9, 0x63,
0x03, 0xa5, 0x43, 0xee, 0xc0, 0x56, 0x9f, 0xbc,
0xf8, 0x2d, 0xc4, 0xbf, 0x52, 0x3a, 0xae, 0x10
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{ "view", 0,
{
0x91, 0xb6, 0x30, 0x25, 0xd5, 0x3c, 0xba, 0x5e,
0x49, 0xfd, 0x81, 0x0b, 0x84, 0xa5, 0x71, 0x56,
0x23, 0x1f, 0x89, 0xed, 0x45, 0xa1, 0x89, 0x16,
0xf1, 0x41, 0x3f, 0x69, 0x67, 0xeb, 0x56, 0x80,
0x0e, 0xe1, 0x6f, 0x2a, 0x17, 0x0e, 0xd9, 0x4b,
0xba, 0xb0, 0xdb, 0x8d, 0x03, 0x5c, 0x0f, 0xa1,
0x60, 0x91, 0x09, 0x6e, 0xb2, 0x7a, 0x5d, 0x36,
0x62, 0xc2, 0x55, 0x58, 0xb4, 0x40, 0x86, 0x2e,
0x88, 0x7d, 0xc2, 0xbd, 0x8d, 0x2e, 0xef, 0x05,
0xce, 0x5b, 0xa0, 0xcc, 0xdb, 0x52, 0x17, 0x6b,
0x04, 0x30, 0x46, 0x3b, 0x00, 0xf1, 0x77, 0xc0,
0x42, 0x27, 0xf9, 0xfe, 0x1e, 0x41, 0x15, 0x2b,
0x73, 0x2f, 0xc8, 0x21, 0x37, 0x1a, 0xd7, 0xf3,
0xf8, 0x46, 0x33, 0xbd, 0x08, 0x89, 0x15, 0xd7,
0xec, 0x4a, 0xf0, 0x3d, 0xa5, 0xa1, 0x03, 0xfb,
0xcc, 0x45, 0xef, 0x3c, 0x61, 0x91, 0xeb, 0x15
},
{
0x9d, 0xc3, 0x8d, 0xa7, 0x36, 0x03, 0x25, 0xe8,
0xac, 0xde, 0x76, 0xdc, 0x0d, 0xe0, 0x85, 0xb5,
0xf4, 0x99, 0xf3, 0x05
},
{
0x77, 0x3a, 0x24, 0x3d, 0xf2, 0xbd, 0xbf, 0xe3,
0xe8, 0x87, 0x25, 0x5f, 0x41, 0x01, 0x9c, 0x63,
0xc1, 0x35, 0x10, 0xfd, 0x9d, 0xb9, 0xe0, 0x32,
0x43, 0x5d, 0x14, 0x38, 0x55, 0x38, 0x2b, 0x7a,
0xd6, 0x7c, 0xcb, 0xd0, 0xdd, 0x6c, 0x8c, 0x42,
0x46, 0x1d, 0xb4, 0x79, 0xcf, 0x7f, 0x9d, 0x70,
0xa7, 0xfe, 0xd1, 0x26, 0x81, 0x90, 0xb8, 0x07,
0x4a, 0xfd, 0x8a, 0x4f, 0x55, 0x6e, 0x9e, 0xe0,
0xb3, 0x3a, 0xdf, 0xd2, 0x7a, 0xcd, 0xfc, 0x0b,
0x08, 0x3d, 0xab, 0xbd, 0xc0, 0x46, 0x31, 0x7b,
0x6c, 0xd0, 0xdc, 0x0c, 0x94, 0xf7, 0xd4, 0x71,
0x4e, 0xbd, 0x11, 0xe2, 0x3b, 0x37, 0xef, 0xec,
0x86, 0x6f, 0x2c, 0x43, 0x87, 0xf0, 0x1d, 0xc4,
0x3b, 0xea, 0xc7, 0xeb, 0xe2, 0x65, 0x34, 0x7e,
0xa1, 0x5d, 0xb8, 0xd3, 0x60, 0x17, 0x43, 0x02,
0xdb, 0x5c, 0xf9, 0x7b, 0x63, 0xcb, 0xdd, 0xd7
},
{
0x4a, 0x14, 0x6c, 0x63, 0x3b, 0xe6, 0xf8, 0x6e,
0x0b, 0xa2, 0x9d, 0x86, 0x91, 0xb0, 0xb8, 0x00,
0x1e, 0x4f, 0xd8, 0xad, 0x27, 0xb2, 0x26, 0xed,
0x73, 0x7e, 0x13, 0x5f, 0x55, 0xef, 0x24, 0xf5,
0xb3, 0x9d, 0x89, 0xce, 0x26, 0xa1, 0x89, 0xda,
0x3e, 0x3f, 0x2c, 0x13, 0x94, 0x82, 0x7a, 0x6c,
0x54, 0x43, 0x5c, 0x66, 0xf2, 0x3a, 0x18, 0xa7,
0x57, 0x69, 0x86, 0xc1, 0x7d, 0xe7, 0x55, 0x26,
0x62, 0x43, 0xef, 0xfa, 0x07, 0x9a, 0xae, 0xd7,
0x63, 0xc4, 0xd4, 0x9f, 0xb7, 0xe2, 0x75, 0xb5,
0xce, 0x9a, 0x0e, 0xc8, 0xd1, 0x40, 0xff, 0x0a,
0x76, 0xf9, 0xe1, 0x48, 0x4c, 0x19, 0x25, 0x56,
0x6f, 0x55, 0x5c, 0xd8, 0x99, 0xe8, 0x83, 0x2d,
0x19, 0x0a, 0x8a, 0x41, 0xc4, 0x69, 0xa3, 0xc6,
0xe6, 0x6e, 0x80, 0xd6, 0xec, 0xf9, 0xff, 0x96,
0x6e, 0xf1, 0x7d, 0x59, 0x40, 0x43, 0xfd, 0x21
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
{ "sa9200", 0,
{
0xed, 0x3b, 0x27, 0xbc, 0x19, 0x01, 0xb9, 0x49,
0x88, 0x1b, 0x45, 0x0b, 0xce, 0xac, 0xcc, 0xde,
0xc6, 0x44, 0x94, 0x5b, 0x07, 0x15, 0xa6, 0x88,
0x19, 0x3c, 0x4e, 0x0e, 0x3b, 0x60, 0xba, 0x2a,
0xa0, 0xc0, 0x61, 0x4c, 0x01, 0x5f, 0xd6, 0x7f,
0xdf, 0x6d, 0x92, 0x3c, 0x63, 0xe6, 0x61, 0x2a,
0x71, 0x5c, 0xc5, 0xa0, 0x16, 0x90, 0xec, 0x0d,
0x45, 0x54, 0x0f, 0xf6, 0xdf, 0x9a, 0xd4, 0xa9,
0x53, 0x30, 0xbc, 0x58, 0x8a, 0x5d, 0x7f, 0x04,
0xb5, 0x5e, 0x63, 0x2b, 0xca, 0x13, 0xb8, 0xf5,
0x54, 0x7d, 0xcb, 0x7b, 0x36, 0xcd, 0xe0, 0x5b,
0xb2, 0x0f, 0x36, 0x14, 0xec, 0x26, 0xca, 0x14,
0x0f, 0x06, 0x43, 0x08, 0xc3, 0x15, 0x13, 0x95,
0x3e, 0x15, 0x1b, 0x7b, 0x2f, 0x10, 0xa6, 0x92,
0x4d, 0xa4, 0xc4, 0xfd, 0xce, 0x4f, 0x5a, 0x46,
0xbf, 0x1c, 0x2a, 0x88, 0xc7, 0x31, 0xae, 0xb7
},
{
0x8c, 0xad, 0x85, 0x93, 0x19, 0x5c, 0x2c, 0x9f,
0xae, 0x37, 0x84, 0x95, 0xd9, 0xe2, 0xd5, 0x02,
0x37, 0xb0, 0x92, 0xc7
},
{
0x7e, 0x5d, 0x0f, 0xe0, 0x85, 0x92, 0x2c, 0x91,
0xd1, 0xa5, 0x6d, 0x37, 0xe1, 0x2f, 0x43, 0xba,
0xa4, 0x79, 0x76, 0x8c, 0x86, 0xc2, 0xc0, 0x98,
0xc1, 0xb0, 0x7a, 0xf6, 0x67, 0xc8, 0x0b, 0x88,
0x39, 0x34, 0xcd, 0x94, 0x07, 0x28, 0xc2, 0x98,
0x46, 0x77, 0xa0, 0xa9, 0x20, 0x67, 0x11, 0x99,
0x26, 0x5b, 0xba, 0x6a, 0xd1, 0xef, 0x06, 0xc7,
0x3f, 0x36, 0x78, 0xc9, 0x33, 0x71, 0x53, 0xb4,
0xcf, 0x53, 0xa3, 0x50, 0xef, 0x15, 0x95, 0x54,
0x3b, 0x97, 0xc6, 0x25, 0x49, 0x76, 0x92, 0xe9,
0xb8, 0x68, 0x25, 0x00, 0x5b, 0x51, 0xea, 0x7a,
0x69, 0xf6, 0xd3, 0x87, 0xd1, 0x6a, 0xbe, 0x1b,
0x3f, 0xd4, 0x04, 0x31, 0x6b, 0xfc, 0x48, 0xed,
0x8d, 0x2c, 0x28, 0x5a, 0x37, 0x1c, 0x64, 0x07,
0xff, 0x0b, 0x6f, 0xf2, 0x02, 0x4c, 0xd4, 0xe7,
0x7f, 0x90, 0xd9, 0x0f, 0x00, 0x72, 0x43, 0xc6
},
{
0x75, 0xc5, 0x62, 0xa7, 0x43, 0x45, 0x2a, 0xaa,
0xe1, 0xaa, 0x2a, 0x88, 0xb4, 0x47, 0x68, 0xd5,
0xc9, 0x85, 0xe5, 0x1c, 0x1c, 0x94, 0xe9, 0x30,
0x35, 0xe1, 0x84, 0x2c, 0x1f, 0x7f, 0xe7, 0x88,
0x1c, 0x7f, 0xb9, 0x7e, 0x3f, 0x64, 0x30, 0xf3,
0x38, 0xd6, 0xdd, 0x14, 0x9a, 0x4d, 0x9d, 0xb7,
0x33, 0x31, 0x4f, 0x77, 0x66, 0x00, 0x36, 0xf3,
0x08, 0x27, 0x1f, 0x28, 0x27, 0x86, 0x18, 0x06,
0x1a, 0xd2, 0xb2, 0x52, 0x97, 0xe7, 0x76, 0x72,
0x32, 0x3e, 0x93, 0x3e, 0x6c, 0xba, 0x0e, 0x9a,
0x06, 0xc4, 0x3b, 0x11, 0xe3, 0x64, 0x6f, 0xb5,
0x75, 0x6d, 0xac, 0x0a, 0x40, 0x8e, 0x7a, 0xd7,
0xd2, 0xa5, 0xa8, 0x55, 0xc1, 0xbc, 0xd8, 0x6d,
0x02, 0xef, 0x5a, 0x19, 0x25, 0x1e, 0x97, 0x35,
0xb9, 0x84, 0xbb, 0x30, 0x43, 0x99, 0xf2, 0x74,
0xfe, 0x24, 0x63, 0x2f, 0xdc, 0xc7, 0x58, 0x60
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
}
},
};
#define NUM_DSA_KEYS (sizeof(dsa_keytable) / sizeof(dsa_keytable[0]))
/* Known HEX keys */
#define HEX_BUFSIZE 512
#define HEX_BLKSIZE (HEX_BUFSIZE / 4)
#define HEX_KEYSIZE (HEX_BLKSIZE / 2)
struct hex_key {
const char * name;
uint8_t key[HEX_KEYSIZE];
};
struct hex_key hex_keytable[] = {
{
"20gc_eng",
{
0x07, 0x2b, 0x00, 0x18, 0x11, 0x26, 0x1a, 0x33,
0x2f, 0x0d, 0x39, 0x3b, 0x02, 0x19, 0x35, 0x1b,
0x32, 0x34, 0x0f, 0x21, 0x0a, 0x08, 0x03, 0x1f,
0x0e, 0x23, 0x09, 0x13, 0x06, 0x29, 0x12, 0x3e,
0x0c, 0x10, 0x05, 0x31, 0x0b, 0x37, 0x2d, 0x22,
0x20, 0x3a, 0x24, 0x2a, 0x1d, 0x01, 0x1c, 0x3c,
0x28, 0x27, 0x2e, 0x3d, 0x2c, 0x36, 0x38, 0x30,
0x25, 0x3f, 0x17, 0x14, 0x1e, 0x16, 0x15, 0x04
}
},
{
"20gc_fre",
{
0x05, 0x0b, 0x3d, 0x23, 0x07, 0x3c, 0x36, 0x34,
0x31, 0x09, 0x18, 0x1f, 0x3b, 0x3f, 0x21, 0x24,
0x03, 0x06, 0x1c, 0x16, 0x37, 0x1b, 0x20, 0x0e,
0x2c, 0x2a, 0x0c, 0x1e, 0x10, 0x22, 0x2e, 0x32,
0x00, 0x2b, 0x1a, 0x30, 0x0f, 0x15, 0x13, 0x3a,
0x38, 0x3e, 0x26, 0x19, 0x2d, 0x01, 0x02, 0x25,
0x11, 0x14, 0x1d, 0x17, 0x28, 0x08, 0x04, 0x0a,
0x29, 0x35, 0x0d, 0x2f, 0x33, 0x27, 0x12, 0x39
}
}
};
#define NUM_HEX_KEYS (sizeof(hex_keytable) / sizeof(hex_keytable[0]))
/* Known label end offsets */
#define LABEL_OFFSET 0xe0
#define LABEL_LEN 12
#define LABEL_END_MIN (LABEL_OFFSET + LABEL_LEN)
struct le_offs {
const char * name;
uint32_t offs;
};
struct le_offs le_offs_table[] = {
{ "default", 0xec },
{ "rhapsody", 0xfc },
{ "none", 0x00 }
};
#define NUM_LE_OFFS (sizeof(le_offs_table) / sizeof(le_offs_table[0]))
#define LABEL_MAGIC 0x100
/* Known commands */
typedef int (*cmd_func)(int, char **);
struct cmd {
const char * name;
cmd_func func;
const char * desc;
};
int cmd_decrypt(int, char **);
int cmd_encrypt(int, char **);
int cmd_build(int, char **);
int cmd_sign(int, char **);
int cmd_verify(int, char **);
int cmd_keyscan(int, char **);
int cmd_blpatch(int, char **);
int cmd_hexdec(int, char **);
int cmd_hexenc(int, char **);
struct cmd cmd_table[] = {
{ "decrypt", cmd_decrypt, "decrypt mi4 image" },
{ "encrypt", cmd_encrypt, "encrypt mi4 image" },
{ "build", cmd_build, "build mi4 image" },
{ "sign", cmd_sign, "sign mi4 with DSA" },
{ "verify", cmd_verify, "verify DSA siganture" },
{ "keyscan", cmd_keyscan, "scan file for potential keys" },
{ "blpatch", cmd_blpatch, "patch bootloader with custom DSA key" },
{ "hexdecode", cmd_hexdec, "decode 'hex' bootloader file" },
{ "hexencode", cmd_hexenc, "encode 'hex' bootloader file" },
};
#define NUM_CMDS (sizeof(cmd_table) / sizeof(cmd_table[0]))
void
help()
{
int i;
printf("\n"
"Usage:\tmi4code <command> [options] [arg1] ...\n"
"\n"
"commands:\n");
for (i = 0; i < NUM_CMDS; i++) {
printf("\t%-20.20s%s\n", cmd_table[i].name, cmd_table[i].desc);
}
printf("\nUse 'mi4code <command> -h' for help on specific command\n\n");
exit(1);
}
/* Big endian machines do exist too. */
uint32_t
get_le32(void * ptr)
{
uint8_t * b = ptr;
uint32_t val;
val = b[3];
val = (val << 8) | b[2];
val = (val << 8) | b[1];
val = (val << 8) | b[0];
return val;
}
void
put_le32(void * ptr, uint32_t val)
{
uint8_t * b = ptr;
b[0] = val;
b[1] = val >> 8;
b[2] = val >> 16;
b[3] = val >> 24;
}
uint32_t crc32table[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t
update_crc32(void * ptr, int size, uint32_t crc)
{
uint8_t * p = ptr;
while (size--) {
crc = (crc >> 8) ^ crc32table[(crc ^ *p++) & 0xff];
}
return crc;
}
uint32_t
update_sum32(void * ptr, int size, uint32_t sum)
{
uint32_t * d = ptr;
while (size > 0) {
sum += get_le32(d++);
size -= 4;
}
return sum;
}
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
enum verbosity {
V_ALL = 0,
V_LOW = 1,
V_MED = 2,
V_HIGH = 3,
V_DEBUG = 4
};
int verbose;
int
printv(int lvl, const char * fmt, ...)
{
va_list ap;
int r = 0;
if (verbose >= lvl) {
va_start(ap, fmt);
r = vprintf(fmt, ap);
va_end(ap);
}
return r;
}
#define BUFSIZE 0x10000
uint32_t inbuf[BUFSIZE / 4];
uint32_t outbuf[BUFSIZE / 4];
#define MI4MAGIC 0x534f5050 /* 'PPOS' */
struct mi4hdr {
uint32_t magic;
uint32_t version;
uint32_t datalen;
uint32_t crc32;
uint32_t crypto;
uint32_t totallen;
uint32_t plainlen;
uint32_t dsa_r[5];
uint32_t dsa_s[5];
uint32_t pad[111]; /* The size has to be 512 bytes */
};
struct mi4hdr mi4hdr;
int
mi4hdr_read(FILE * ifp)
{
fseek(ifp, 0, SEEK_SET);
fread(&mi4hdr, 1, sizeof(mi4hdr), ifp);
mi4hdr.magic = get_le32(&mi4hdr.magic);
mi4hdr.version = get_le32(&mi4hdr.version);
mi4hdr.datalen = get_le32(&mi4hdr.datalen);
mi4hdr.crc32 = get_le32(&mi4hdr.crc32);
mi4hdr.crypto = get_le32(&mi4hdr.crypto);
mi4hdr.totallen = get_le32(&mi4hdr.totallen);
mi4hdr.plainlen = get_le32(&mi4hdr.plainlen);
if (mi4hdr.magic != MI4MAGIC) {
fprintf(stderr, "Invalid magic in mi4 header (maybe not mi4 file)!\n");
return 0;
}
return 1;
}
void
mi4hdr_write(FILE * ofp)
{
struct mi4hdr tmp;
memcpy(&tmp, &mi4hdr, sizeof(tmp));
put_le32(&tmp.magic, mi4hdr.magic);
put_le32(&tmp.version, mi4hdr.version);
put_le32(&tmp.datalen, mi4hdr.datalen);
put_le32(&tmp.crc32, mi4hdr.crc32);
put_le32(&tmp.crypto, mi4hdr.crypto);
put_le32(&tmp.totallen, mi4hdr.totallen);
put_le32(&tmp.plainlen, mi4hdr.plainlen);
fseek(ofp, 0, SEEK_SET);
fwrite(&tmp, 1, sizeof(tmp), ofp);
}
int
mi4hdr_dsa_check()
{
if (mi4hdr.version != 0x010301) {
fprintf(stderr,
"The mi4 has version %06x header. Only version 010301 uses DSA!\n"
"Nothing to do!\n", mi4hdr.version);
return 0;
}
return 1;
}
struct hexhdr {
uint32_t id[8];
uint32_t sum1;
uint32_t len;
uint32_t sum2;
uint32_t pad[5]; /* the size must be 64 bytes */
};
struct hexhdr hexhdr;
int
hexhdr_read(FILE * ifp)
{
fseek(ifp, 0, SEEK_SET);
fread(&hexhdr, 1, sizeof(hexhdr), ifp);
if (memcmp(hexhdr.id, "iriver", 6)) {
fprintf(stderr, "Invalid file header (maybe not a iriver hex file)!\n");
return 0;
}
hexhdr.sum1 = get_le32(&hexhdr.sum1);
hexhdr.sum2 = get_le32(&hexhdr.sum2);
hexhdr.len = get_le32(&hexhdr.len);
return 1;
}
void
hexhdr_write(FILE * ofp)
{
struct hexhdr tmp;
tmp = hexhdr;
put_le32(&tmp.sum1, hexhdr.sum1);
put_le32(&tmp.sum2, hexhdr.sum2);
put_le32(&tmp.len, hexhdr.len);
fseek(ofp, 0, SEEK_SET);
fwrite(&tmp, 1, sizeof(tmp), ofp);
}
#ifdef SUPPORT_DSA
#include <gcrypt.h>
void
init_dsa()
{
gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0);
}
int
get_sha1(FILE * fp, uint8_t * hash)
{
gcry_md_hd_t md_handle;
gcry_error_t error;
long pos;
int len;
error = gcry_md_open(&md_handle, GCRY_MD_SHA1, 0);
if (error) {
fprintf(stderr, "%s\n", gcry_strerror(error));
return 0;
}
pos = ftell(fp);
fseek(fp, sizeof(struct mi4hdr), SEEK_SET);
while ((len = fread(inbuf, 1, BUFSIZE, fp)) > 0) {
gcry_md_write(md_handle, inbuf, len);
}
memcpy(hash, gcry_md_read(md_handle, GCRY_MD_SHA1), 20);
gcry_md_close(md_handle);
fseek(fp, pos, SEEK_SET);
return 1;
}
void
get_mpi(gcry_mpi_t * mpi, void * buf, int len)
{
gcry_error_t error;
error = gcry_mpi_scan(mpi, GCRYMPI_FMT_USG, buf, len, NULL);
if (error) {
fprintf(stderr, "Error %s getting mpi\n", gcry_strerror(error));
exit(1);
}
gcry_mpi_set_flag(*mpi, GCRYMPI_FLAG_SECURE);
}
void
get_signature(void * ptr, gcry_sexp_t sexp, const char * part)
{
gcry_sexp_t tmp;
const char * src;
char * dst;
size_t len;
dst = ptr;
tmp = gcry_sexp_find_token(sexp, part, 1);
if (!tmp) {
fprintf(stderr, "No '%s' in signature!?\n", part);
exit(1);
}
src = gcry_sexp_nth_data(tmp, 1, &len);
if (!src) {
fprintf(stderr, "No data in '%s' part of signature!?\n", part);
exit(1);
}
if (len < 20) {
memset(dst, 0, 20 - len);
dst += 20 - len;
} else if (len > 20) {
if (len == 21 && src[0] == 0) {
src++;
len--;
} else {
fprintf(stderr, "Invalid '%s' in signature (len = %d)!?\n",
part, (int)len);
gcry_sexp_dump(tmp);
exit(1);
}
}
memcpy(dst, src, len);
}
void
sign_image(FILE * fp, void * p, void * q, void * g, void * y,
void * x, void * r, void * s)
{
uint8_t hash[20];
gcry_mpi_t h_mpi, p_mpi, q_mpi, g_mpi, y_mpi, x_mpi;
gcry_sexp_t key_exp, hash_exp, sig_exp;
gcry_error_t error;
get_sha1(fp, hash);
get_mpi(&h_mpi, hash, 20);
get_mpi(&p_mpi, p, 128);
get_mpi(&q_mpi, q, 20);
get_mpi(&g_mpi, g, 128);
get_mpi(&y_mpi, y, 128);
get_mpi(&x_mpi, x, 20);
error = gcry_sexp_build(&key_exp, NULL,
"(private-key "
"(dsa (p %m) (q %m) (g %m) (y %m) (x %m)))",
p_mpi, q_mpi, g_mpi, y_mpi, x_mpi);
if (error) {
fprintf(stderr, "Error %s building private key\n", gcry_strerror(error));
exit(1);
}
error = gcry_sexp_build(&hash_exp, NULL,
"(data (flags raw) (value %m))", h_mpi);
if (error) {
fprintf(stderr, "Error %s building hash\n", gcry_strerror(error));
exit(1);
}
error = gcry_pk_sign(&sig_exp, hash_exp, key_exp);
if (error) {
fprintf(stderr, "Error %s signing the hash\n", gcry_strerror(error));
exit(1);
}
get_signature(r, sig_exp, "r");
get_signature(s, sig_exp, "s");
gcry_mpi_release(h_mpi);
gcry_mpi_release(p_mpi);
gcry_mpi_release(q_mpi);
gcry_mpi_release(g_mpi);
gcry_mpi_release(y_mpi);
gcry_mpi_release(x_mpi);
gcry_sexp_release(sig_exp);
gcry_sexp_release(key_exp);
gcry_sexp_release(hash_exp);
}
int
verify_image(FILE * fp, void * p, void * q, void * g, void * y,
void * r, void * s)
{
uint8_t hash[20];
gcry_mpi_t h_mpi, p_mpi, q_mpi, g_mpi, y_mpi, r_mpi, s_mpi;
gcry_sexp_t key_exp, hash_exp, sig_exp;
gcry_error_t error;
get_sha1(fp, hash);
get_mpi(&h_mpi, hash, 20);
get_mpi(&p_mpi, p, 128);
get_mpi(&q_mpi, q, 20);
get_mpi(&g_mpi, g, 128);
get_mpi(&y_mpi, y, 128);
get_mpi(&r_mpi, r, 20);
get_mpi(&s_mpi, s, 20);
error = gcry_sexp_build(&key_exp, NULL,
"(public-key "
"(dsa (p %m) (q %m) (g %m) (y %m)))",
p_mpi, q_mpi, g_mpi, y_mpi);
if (error) {
fprintf(stderr, "Error %s building public key\n", gcry_strerror(error));
exit(1);
}
error = gcry_sexp_build(&hash_exp, NULL,
"(data (flags raw) (value %m))", h_mpi);
if (error) {
fprintf(stderr, "Error %s building hash\n", gcry_strerror(error));
exit(1);
}
error = gcry_sexp_build(&sig_exp, NULL,
"(sig-val (dsa (r %m) (s %m)))", r_mpi, s_mpi);
if (error) {
fprintf(stderr, "Error %s building signature\n", gcry_strerror(error));
exit(1);
}
error = gcry_pk_verify(sig_exp, hash_exp, key_exp);
gcry_mpi_release(h_mpi);
gcry_mpi_release(p_mpi);
gcry_mpi_release(q_mpi);
gcry_mpi_release(g_mpi);
gcry_mpi_release(y_mpi);
gcry_mpi_release(r_mpi);
gcry_mpi_release(s_mpi);
gcry_sexp_release(sig_exp);
gcry_sexp_release(key_exp);
gcry_sexp_release(hash_exp);
return error == 0;
}
#else /* SUPPORT_DSA */
void init_dsa()
{
fprintf(stderr,
"DSA support disabled in compilation!\n"
"If you wish to perform real DSA operations you have to enable\n"
"SUPPORT_DSA and recompile (requires libgcrypt).\n");
exit(1);
}
void sign_image(FILE * fp, void * p, void * q, void * g, void * y,
void * x, void * r, void * s) {}
int verify_image(FILE * fp, void * p, void * q, void * g, void * y,
void * r, void * s) { return 0; }
#endif /* SUPPORT_DSA */
void
inc_key(uint32_t * key)
{
if (++key[0] != 0) {
return;
}
if (++key[1] != 0) {
return;
}
if (++key[2] != 0) {
return;
}
++key[3];
}
#define Y_INIT 0xf1bbcdc8
#define Y_STEP 0x61c88647
void
tea_decrypt(uint32_t * iptr, uint32_t * optr, size_t len, uint32_t * key)
{
uint32_t d1, d2;
uint32_t step, y;
uint32_t x;
int i;
step = Y_STEP;
for (; len >= 8; len -= 8) {
d1 = get_le32(iptr++);
d2 = get_le32(iptr++);
y = Y_INIT;
for (i = 0; i < 8; i++) {
x = key[2] + (d1 << 4);
x ^= d1 + y;
x ^= key[3] + (d1 >> 5);
d2 -= x;
x = key[0] + (d2 << 4);
x ^= d2 + y;
x ^= key[1] + (d2 >> 5);
d1 -= x;
y += step;
}
put_le32(optr++, d1);
put_le32(optr++, d2);
inc_key(key);
}
}
void
tea_encrypt(uint32_t * iptr, uint32_t * optr, size_t len, uint32_t * key)
{
uint32_t d1, d2;
uint32_t step, y;
uint32_t x;
int i;
step = Y_STEP;
for (; len >= 8; len -= 8) {
d1 = get_le32(iptr++);
d2 = get_le32(iptr++);
y = Y_INIT + 7 * step;
for (i = 0; i < 8; i++) {
x = key[0] + (d2 << 4);
x ^= d2 + y;
x ^= key[1] + (d2 >> 5);
d1 += x;
x = key[2] + (d1 << 4);
x ^= d1 + y;
x ^= key[3] + (d1 >> 5);
d2 += x;
y -= step;
}
put_le32(optr++, d1);
put_le32(optr++, d2);
inc_key(key);
}
}
#define VERIFY_MAGIC 0xaa55aa55
void
key_shift(uint32_t * key, int x)
{
key[0] <<= 8;
key[0] |= key[1] >> 24;
key[1] <<= 8;
key[1] |= key[2] >> 24;
key[2] <<= 8;
key[2] |= key[3] >> 24;
key[3] <<= 8;
key[3] |= x & 0xff;
}
void
key_add(uint32_t * okey, uint32_t * ikey, uint32_t x)
{
uint32_t c;
okey[0] = ikey[0] + x;
c = okey[0] < ikey[0] ? 1 : 0;
okey[1] = ikey[1] + c;
c = okey[1] < ikey[1] ? 1 : 0;
okey[2] = ikey[2] + c;
c = okey[2] < ikey[2] ? 1 : 0;
okey[3] = ikey[3] + c;
}
uint32_t
bswap(uint32_t x)
{
x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8);
x = ((x & 0xffff0000) >> 16) | ((x & 0x0000ffff) << 16);
return x;
}
void
key_swap(uint32_t * key)
{
key[0] = bswap(key[0]);
key[1] = bswap(key[1]);
key[2] = bswap(key[2]);
key[3] = bswap(key[3]);
}
int
key_first(FILE * kfp, uint32_t * key)
{
return 4 == fread(key, sizeof(uint32_t), 4, kfp);
}
int
key_next(FILE * kfp, uint32_t * key, int complete)
{
int x;
if (complete) {
return key_first(kfp, key);
}
x = fgetc(kfp);
if (x == EOF) {
return 0;
}
key_shift(key, x);
return 1;
}
int
key_scan(FILE * ifp, FILE * kfp, int complete)
{
uint32_t key[4];
uint32_t tmp[4];
uint32_t c_data[2];
uint32_t p_data[2];
uint32_t pos;
int i, count;
printv(V_ALL, "Scanning potential keys\n");
fseek(ifp, 8, SEEK_SET);
fread(&pos, 1, sizeof(pos), ifp);
pos = get_le32(&pos) - 4;
fseek(ifp, sizeof(struct mi4hdr) + (pos & ~7), SEEK_SET);
fread(c_data, 1, sizeof(c_data), ifp);
i = pos & 0x7 ? 1 : 0;
count = 0;
key_first(kfp, key);
do {
key_add(tmp, key, (pos - mi4hdr.plainlen) / 8);
tea_decrypt(c_data, p_data, sizeof(c_data), tmp);
if (get_le32(&p_data[i]) == VERIFY_MAGIC) {
printf("Potential key %08x %08x %08x %08x\n",
key[0], key[1], key[2], key[3]);
count++;
}
key_swap(key);
key_add(tmp, key, (pos - mi4hdr.plainlen) / 8);
tea_decrypt(c_data, p_data, sizeof(c_data), tmp);
if (get_le32(&p_data[i]) == VERIFY_MAGIC) {
printf("Potential key %08x %08x %08x %08x\n",
key[0], key[1], key[2], key[3]);
count++;
}
key_swap(key);
} while (key_next(kfp, key, complete));
if (!count) {
printv(V_ALL, "No potential keys found\n");
}
return 0;
}
void
le_offs_check(uint32_t offs)
{
int i;
if (offs == 0) {
printv(V_ALL, "No secondary label found ('none')!\n");
return;
}
for (i = 0; i < NUM_LE_OFFS; i++) {
if (le_offs_table[i].offs == offs) {
printv(V_ALL, "Secondary label end offset '%s' (0x%x)\n",
le_offs_table[i].name, offs);
return;
}
}
printv(V_ALL, "Warning: unknown label end offset 0x%x !\n", offs);
}
int
decode_ok(FILE * fp, int skip_header, long len)
{
long offset = skip_header ? sizeof(struct mi4hdr) : 0;
long pos;
uint32_t x, leo;
printv(V_LOW, "\nVerifying decoded data\n");
pos = offset + LABEL_OFFSET;
fseek(fp, pos, SEEK_SET);
fread(&x, 1, sizeof(x), fp);
x = get_le32(&x);
if (x == 0xeafffffe) {
printv(V_MED, "Secondary label does not seem to exist!\n");
leo = 0;
x = len;
} else {
if (x != LABEL_MAGIC) {
printv(V_MED, "Failed magic at 0x%x (%08x <> %08x)!\n",
pos, x, LABEL_MAGIC);
goto fail;
}
fread(&x, 1, sizeof(x), fp);
leo = get_le32(&x);
fread(&x, 1, sizeof(x), fp);
x = get_le32(&x);
}
pos = offset + x - 4;
fseek(fp, pos, SEEK_SET);
fread(&x, 1, sizeof(x), fp);
x = get_le32(&x);
if (x != VERIFY_MAGIC) {
printv(V_MED, "Failed magic at 0x%x (%08x <> %08x)!\n",
pos, x, VERIFY_MAGIC);
goto fail;
}
le_offs_check(leo);
printv(V_LOW, "Data verified ok!\n");
return 1;
fail:
printv(V_LOW, "Data verification failed!\n");
return 0;
}
uint32_t
sum_bytes(void * ptr, int size)
{
uint8_t * b = ptr;
uint32_t sum = 0;
while (size--) {
sum += *b++;
}
return sum;
}
uint32_t
get_hex_key(struct hex_key * hkey, uint32_t index)
{
index &= (HEX_KEYSIZE - 1);
return hkey->key[index];
}
uint32_t
hex_code(uint32_t * buf, struct hex_key * hkey, uint32_t x, int encode)
{
uint32_t tmp;
int i, k;
for (i = 0; i < (HEX_BLKSIZE / 2); i++) {
k = get_hex_key(hkey, x + i) + (HEX_BLKSIZE / 2);
tmp = buf[k];
buf[k] = buf[i];
buf[i] = tmp;
}
return get_hex_key(hkey, sum_bytes(&buf[encode ? k : (i - 1)], 4));
}
int
file_copy(FILE * ifp, FILE * ofp, int total, uint32_t * crc)
{
int len, todo, done;
todo = total >= 0 ? total : 0x7fffffff;
done = 0;
while (todo > 0) {
len = fread(inbuf, 1, todo < BUFSIZE ? todo : BUFSIZE, ifp);
if (!len) {
break;
}
fwrite(inbuf, 1, len, ofp);
if (crc) {
*crc = update_crc32(inbuf, len, *crc);
}
todo -= len;
done += len;
}
if (todo > 0 && total > 0) {
fprintf(stderr,
"Unexpected EOF while copying, %d bytes not copied!\n", todo);
}
return done;
}
int
__file_crypt(int encrypt, FILE * ifp, FILE * ofp,
const uint32_t * key, uint32_t * crc)
{
uint32_t tkey[4];
int len, done;
memcpy(tkey, key, sizeof(tkey));
done = 0;
while ((len = fread(inbuf, 1, BUFSIZE, ifp)) > 0) {
if (encrypt) {
tea_encrypt(inbuf, outbuf, len, tkey);
if (crc) {
*crc = update_crc32(outbuf, len, *crc);
}
} else {
if (crc) {
*crc = update_crc32(inbuf, len, *crc);
}
tea_decrypt(inbuf, outbuf, len, tkey);
}
fwrite(outbuf, 1, len, ofp);
done += len;
}
return done;
}
int
file_decrypt(FILE * ifp, FILE * ofp, uint32_t * key, uint32_t * crc)
{
return __file_crypt(0, ifp, ofp, key, crc);
}
int
file_encrypt(FILE * ifp, FILE * ofp, uint32_t * key, uint32_t * crc)
{
return __file_crypt(1, ifp, ofp, key, crc);
}
int
__file_hexcode(int encode, FILE * ifp, FILE * ofp,
struct hex_key * hkey, uint32_t * sum)
{
int x, len;
x = hexhdr.sum1 & (HEX_KEYSIZE - 1);
while ((len = fread(inbuf, 1, HEX_BUFSIZE, ifp)) == HEX_BUFSIZE) {
x = hex_code(inbuf, hkey, x, encode);
fwrite(inbuf, 1, len, ofp);
if (sum) {
*sum = update_sum32(inbuf, len, *sum);
}
}
if (len) {
fwrite(inbuf, 1, len, ofp);
if (sum) {
*sum = update_sum32(inbuf, len, *sum);
}
}
return 0;
}
int
file_hexdecode(FILE * ifp, FILE * ofp, struct hex_key * hkey, uint32_t * sum)
{
return __file_hexcode(0, ifp, ofp, hkey, sum);
}
int
file_hexencode(FILE * ifp, FILE * ofp, struct hex_key * hkey, uint32_t * sum)
{
return __file_hexcode(1, ifp, ofp, hkey, sum);
}
int
memmatch(void * p1, int s1, void * p2, int s2)
{
char * ptr = p1;
int i;
for (i = 0; i < (s1 - s2); i++) {
if (!memcmp(ptr + i, p2, s2)) {
return i;
}
}
return -1;
}
int
find_key(long pos, long * o_pos, void * buf, int len, void * key, int klen,
const char * str)
{
char * ptr = buf;
int offs = 0;
while (offs >= 0) {
offs = memmatch(ptr, len, key, klen);
if (offs >= 0) {
if (*o_pos != 0 && (*o_pos != (pos + offs))) {
fprintf(stderr, "Duplicate match for %s at %08lx and %08lx\n",
str, *o_pos, pos + offs);
return -1;
}
*o_pos = pos + offs;
}
ptr += offs + klen;
len -= offs + klen;
}
return 0;
}
int
bl_patch(FILE * ifp, FILE * ofp, struct dsa_key * dkey)
{
long pos, p_pos, q_pos, g_pos, y_pos;
struct dsa_key * key;
size_t len;
int i;
p_pos = q_pos = g_pos = y_pos = 0;
printv(V_ALL, "Scanning the bootloader for existing DSA keys\n");
for (i = 0, key = &dsa_keytable[0]; i < NUM_DSA_KEYS; i++, key++) {
printv(V_LOW, "Searching for '%s' DSA keys ... ", key->name);
pos = 0;
do {
fseek(ifp, pos, SEEK_SET);
len = fread(inbuf, 1, BUFSIZE, ifp);
if (find_key(pos, &p_pos, inbuf, len, key->p, sizeof(key->p), "p")) {
break;
}
if (find_key(pos, &q_pos, inbuf, len, key->q, sizeof(key->q), "q")) {
break;
}
if (find_key(pos, &g_pos, inbuf, len, key->g, sizeof(key->g), "g")) {
break;
}
if (find_key(pos, &y_pos, inbuf, len, key->y, sizeof(key->y), "y")) {
break;
}
pos += BUFSIZE - 128;
} while (len == BUFSIZE);
if (p_pos && q_pos && g_pos && y_pos) {
printv(V_LOW, "found!\n");
printv(V_ALL, "Found DSA key '%s', ", key->name);
printv(V_ALL, "p at %lx, q at %lx, g at %lx, y at %lx\n",
p_pos, q_pos, g_pos, y_pos);
printv(V_ALL,
"*******************************************************\n"
"** Do NOT try to use the patched bootloader if **\n"
"** you think the values above are not correct! **\n"
"** **\n"
"** I TAKE ABSOLUTELY NO RESPONSIBILITY IF YOU **\n"
"** BREAK YOUR PLAYER BEYOND REPAIR WITH THIS **\n"
"** TOOL! IF YOU FEEL UNSURE, JUST DON'T DO IT! **\n"
"*******************************************************\n");
fseek(ifp, 0, SEEK_SET);
file_copy(ifp, ofp, -1, NULL);
fseek(ofp, p_pos, SEEK_SET);
fwrite(dkey->p, 1, sizeof(dkey->p), ofp);
fseek(ofp, q_pos, SEEK_SET);
fwrite(dkey->q, 1, sizeof(dkey->q), ofp);
fseek(ofp, g_pos, SEEK_SET);
fwrite(dkey->g, 1, sizeof(dkey->g), ofp);
fseek(ofp, y_pos, SEEK_SET);
fwrite(dkey->y, 1, sizeof(dkey->y), ofp);
printv(V_ALL, "Bootloader patched with key '%s'!\n", dkey->name);
return 0;
} else {
printv(V_LOW, "not found\n");
}
}
fprintf(stderr,
"No suitable DSA keys found! Unable to patch the bootloader!\n");
return 1;
}
int
myopt(int argc, char * argv[], const char * optstr, const char ** optarg)
{
static char * opt;
static int optind;
const char * c;
if (optind >= argc) {
return -optind;
}
if (!opt) {
opt = argv[optind];
if (!strcmp(opt, "--")) {
optind++;
return -optind;
}
if (opt[0] != '-') {
return -optind;
}
opt++;
if (*opt == 0) {
return -optind;
}
}
c = strchr(optstr, *opt);
if (!c) {
fprintf(stderr, "Unknown option '%c'!\n", *opt);
opt++;
if (*opt == 0) {
optind++;
opt = NULL;
}
return '?';
}
if (c[1] == ':') {
optind++;
if (c[2] == ':') {
*optarg = opt[1] ? opt + 1 : NULL;
opt = NULL;
} else {
if (opt[1] != 0) {
*optarg = opt + 1;
} else if (optind < argc) {
*optarg = argv[optind++];
} else {
fprintf(stderr, "Option '%c' requires an argument!\n", *c);
exit(1);
}
opt = NULL;
}
} else {
opt++;
if (*opt == 0) {
optind++;
opt = NULL;
}
}
return *c;
}
int
parse_tea_key(int argc, char * argv[], uint32_t * key)
{
char * p;
int i;
if (argc == 1) {
for (i = 0; i < NUM_TEA_KEYS; i++) {
if (!strcmp(tea_keytable[i].name, argv[0])) {
memcpy(key, tea_keytable[i].key, 4 * sizeof(uint32_t));
return 1;
}
}
fprintf(stderr, "Unknown key '%s'!\n", argv[0]);
return 0;
} else if (argc == 4) {
for (i = 0; i < 4; i++) {
key[i] = strtoul(argv[i], &p, 16);
if (*p != 0) {
fprintf(stderr, "Invalid key '%s' (must be a hexadecimal number)!\n",
argv[i]);
return 0;
}
}
return 1;
}
fprintf(stderr, "Invalid number of arguments!\n");
return 0;
}
void
print_tea_keys()
{
int i;
printf("\nKnown keys: %s", tea_keytable[0].name);
for (i = 1; i < NUM_TEA_KEYS; i++) {
printf(", %s", tea_keytable[i].name);
}
printf("\n\n");
}
void
help_decrypt()
{
printf("\n"
"Usage:\tmi4code decrypt [options] <infile> <outfile> [keyid]\n"
"\n"
"\tmi4code decrypt [options] <infile> <outfile> [k1] [k2] [k3] [k4]\n"
"\n"
"options:\n"
"\t-l\tlist known keys\n"
"\t-s\tstrip mi4 header\n"
"\t-v\tincrease verbosity\n"
"\t-q\tdecrease verbosity\n"
"\t-h\tthis help\n"
"\n");
exit(1);
}
int
cmd_decrypt(int argc, char * argv[])
{
FILE * ifp, * ofp;
struct tea_key * kp;
uint32_t key[4];
long ipos, opos;
int strip_header = 0;
int i;
int c;
while ((c = myopt(argc, argv, "lsvqh", NULL)) > 0) {
switch (c) {
case 'l':
print_tea_keys();
return 0;
case 's':
strip_header = 1;
break;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_decrypt();
break;
}
}
argc += c;
argv -= c;
if (argc < 2) {
fprintf(stderr, "Invalid number of arguments!\n");
help_decrypt();
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
ofp = fopen(argv[1], "wb+");
if (!ofp) {
perror(argv[1]);
return 1;
}
argc -= 2;
argv += 2;
if (!mi4hdr_read(ifp)) {
return 1;
}
if (!strip_header) {
printv(V_LOW, "Copying the mi4 header\n");
mi4hdr_write(ofp);
} else {
printv(V_LOW, "Skipping the mi4 header\n");
}
if (mi4hdr.plainlen) {
printv(V_LOW, "Copying the plaintext part (%d bytes)\n", mi4hdr.plainlen);
file_copy(ifp, ofp, mi4hdr.plainlen, NULL);
} else {
printv(V_LOW, "File has no plaintext part\n");
}
if (argc > 0) {
if (!parse_tea_key(argc, argv, key)) {
return 1;
}
printv(V_ALL, "Decrypting with key %08x %08x %08x %08x\n",
key[0], key[1], key[2], key[3]);
file_decrypt(ifp, ofp, key, NULL);
if (decode_ok(ofp, !strip_header, mi4hdr.datalen)) {
printv(V_ALL, "Verify ok!\n");
return 0;
} else {
printv(V_ALL, "Verification failed (maybe wrong key?)!\n");
return 1;
}
}
ipos = ftell(ifp);
opos = ftell(ofp);
for (i = 0; i < NUM_TEA_KEYS; i++) {
fseek(ifp, ipos, SEEK_SET);
fseek(ofp, opos, SEEK_SET);
kp = &tea_keytable[i];
printv(V_LOW, "Trying key '%s'\t(%08x %08x %08x %08x) ... ",
kp->name, kp->key[0], kp->key[1], kp->key[2], kp->key[3]);
file_decrypt(ifp, ofp, kp->key, NULL);
if (decode_ok(ofp, !strip_header, mi4hdr.datalen)) {
printv(V_LOW, "ok!\n");
printv(V_ALL, "Decrypted ok with key '%s' (%08x %08x %08x %08x)\n",
kp->name, kp->key[0], kp->key[1], kp->key[2], kp->key[3]);
return 0;
} else {
printv(V_LOW, "fail\n");
}
}
printv(V_ALL, "Unable to decrypt the file (maybe the key is not known)!\n");
return 1;
}
int
parse_uint32(const char * s, uint32_t * v)
{
char * c;
*v = strtoul(s, &c, 0);
if (*c != 0) {
fprintf(stderr, "Invalid value '%s'\n", s);
return 0;
}
return 1;
}
int
parse_plen(const char * s, uint32_t * v)
{
if (!strcmp(s, "all")) {
*v = ~7;
return 1;
}
if (!parse_uint32(s, v)) {
return 0;
}
if (*v & 7) {
fprintf(stderr, "Lenght must be a multiple of 8!\n");
return 0;
}
return 1;
}
void
help_encrypt()
{
printf("\n"
"Usage:\tmi4code encrypt [options] <infile> <outfile> <keyid>\n"
"\n"
"\tmi4code encrypt [options] <infile> <outfile> <k1> <k2> <k3> <k4>\n"
"\n"
"options:\n"
"\t-l\t\tlist known keys\n"
"\t-n\t\tdon't correct the checksum\n"
"\t-p <num|all>\tplaintext length\n"
"\t-v\t\tincrease verbosity\n"
"\t-q\t\tdecrease verbosity\n"
"\t-h\t\tthis help\n"
"\n");
exit(1);
}
int
cmd_encrypt(int argc, char * argv[])
{
FILE * ifp, * ofp;
const char * opt;
uint32_t key[4];
uint32_t crc = 0;
uint32_t plen;
int fix_crc = 1;
int set_plen = 0;
int c;
while ((c = myopt(argc, argv, "lnp:vqh", &opt)) > 0) {
switch (c) {
case 'l':
print_tea_keys();
return 0;
case 'n':
fix_crc = 0;
break;
case 'p':
if (!parse_plen(opt, &plen)) {
return 1;
}
set_plen = 1;
break;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_encrypt();
break;
}
}
argc += c;
argv -= c;
if (argc < 2) {
fprintf(stderr, "Invalid number of arguments!\n");
help_encrypt();
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
ofp = fopen(argv[1], "wb");
if (!ofp) {
perror(argv[1]);
return 1;
}
argc -= 2;
argv += 2;
if (!parse_tea_key(argc, argv, key)) {
return 1;
}
if (!mi4hdr_read(ifp)) {
return 1;
}
if (set_plen) {
mi4hdr.plainlen = MIN(plen, mi4hdr.totallen - sizeof(struct mi4hdr));
}
mi4hdr_write(ofp);
if (mi4hdr.plainlen) {
printv(V_LOW, "Copying the plaintext part (%d bytes)\n", mi4hdr.plainlen);
file_copy(ifp, ofp, mi4hdr.plainlen, &crc);
} else {
printv(V_LOW, "File has no plaintext part\n");
}
printv(V_ALL, "Encrypting with key %08x %08x %08x %08x\n",
key[0], key[1], key[2], key[3]);
file_encrypt(ifp, ofp, key, &crc);
if (crc != mi4hdr.crc32) {
if (fix_crc) {
printv(V_ALL, "CRC32 corrected (%08x -> %08x)\n", mi4hdr.crc32, crc);
mi4hdr.crc32 = crc;
mi4hdr_write(ofp);
} else {
printv(V_ALL, "CRC32 mismatch detected (%08x <-> %08x)\n",
mi4hdr.crc32, crc);
}
}
return 0;
}
int
parse_leo(const char * s, uint32_t * v)
{
int i;
for (i = 0; i < NUM_LE_OFFS; i++) {
if (!strcmp(le_offs_table[i].name, s)) {
*v = le_offs_table[i].offs;
printv(V_LOW, "Using label end offset '%s' (0x%x)\n", s, *v);
return 1;
}
}
if (!parse_uint32(s, v)) {
return 0;
}
if (*v < LABEL_END_MIN) {
fprintf(stderr, "Label end offset too small, must be at least 0x%x!\n",
LABEL_END_MIN);
return 0;
}
printv(V_LOW, "Using label end offset 0x%x\n", *v);
return 1;
}
void
print_leos()
{
int i;
printf("\nKnown offs_ids: %s (0x%x)",
le_offs_table[0].name, le_offs_table[0].offs);
for (i = 1; i < NUM_LE_OFFS; i++) {
printf(", %s (0x%x)", le_offs_table[i].name, le_offs_table[i].offs);
}
printf("\n\n");
}
void
help_build()
{
printf("\n"
"Usage:\tmi4code build [options] <infile> <outfile> [offs]\n"
"\n"
"\tmi4code build [options] <infile> <outfile> [offs_id]\n"
"\n"
"options:\n"
"\t-l\t\tlist known offs_ids\n"
"\t-2\t\tmake 010201 header\n"
"\t-3\t\tmake 010301 header (default)\n"
"\t-p <num|all>\tplaintext length (default 0x200)\n"
"\t-v\t\tincrease verbosity\n"
"\t-q\t\tdecrease verbosity\n"
"\t-h\t\tthis help\n"
"\n");
exit(1);
}
int
roundup(int val, int to)
{
val += to - 1;
val &= ~(to - 1);
return val;
}
int
cmd_build(int argc, char * argv[])
{
FILE * ifp, * ofp;
const char * opt;
uint32_t ver = 0x10301;
uint32_t plen = 0x200;
uint32_t x, leo;
int todo;
int c;
while ((c = myopt(argc, argv, "l23p:vqh", &opt)) > 0) {
switch (c) {
case 'l':
print_leos();
return 0;
case '2':
ver = 0x10201;
break;
case '3':
ver = 0x10301;
break;
case 'p':
if (!parse_plen(opt, &plen)) {
return 1;
}
break;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_build();
break;
}
}
argc += c;
argv -= c;
if (argc < 2 || argc > 3) {
fprintf(stderr, "Invalid number of arguments!\n");
help_build();
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
ofp = fopen(argv[1], "wb");
if (!ofp) {
perror(argv[1]);
return 1;
}
argc -= 2;
argv += 2;
if (argc > 0) {
if (!parse_leo(argv[0], &leo)) {
return 1;
}
argc -= 1;
argv += 1;
} else {
parse_leo("default", &leo);
}
memset(&mi4hdr, 0, sizeof(struct mi4hdr));
mi4hdr_write(ofp);
file_copy(ifp, ofp, -1, NULL);
if (ftell(ofp) < (leo + sizeof(struct mi4hdr))) {
x = MAX(leo, 0xec);
fprintf(stderr,
"File too small, at least %u (0x%x) bytes needed!\n", x, x);
return 1;
}
put_le32(&x, VERIFY_MAGIC);
fwrite(&x, 1, sizeof(x), ofp);
todo = roundup(ftell(ofp), 1024) - ftell(ofp);
mi4hdr.magic = MI4MAGIC;
mi4hdr.version = ver;
mi4hdr.datalen = ftell(ofp) - sizeof(struct mi4hdr);
mi4hdr.crypto = 2;
mi4hdr.totallen = roundup(ftell(ofp), 1024);
mi4hdr.plainlen = MIN(plen, mi4hdr.totallen - sizeof(struct mi4hdr));
while (todo--) {
fputc(0, ofp);
}
mi4hdr_write(ofp);
if (leo == 0) {
printv(V_LOW, "Secondary label not created!\n");
goto done;
}
printv(V_ALL,
"*************************************************************\n"
"** The data in input file offsets 0x%02x-0x%-8.0x **\n"
"** will be overwritten. You should not have **\n"
"** your own code/data there! **\n"
"*************************************************************\n",
LABEL_OFFSET, leo - 1);
fseek(ofp, sizeof(struct mi4hdr) + LABEL_OFFSET, SEEK_SET);
put_le32(&x, LABEL_MAGIC);
fwrite(&x, 1, sizeof(x), ofp);
put_le32(&x, leo);
fwrite(&x, 1, sizeof(x), ofp);
put_le32(&x, mi4hdr.datalen);
fwrite(&x, 1, sizeof(x), ofp);
leo -= LABEL_END_MIN;
while (leo--) {
fputc(0, ofp);
}
done:
printv(V_ALL, "Image created ok!\n");
return 0;
}
void
print_dsa_keys()
{
int i;
printf("\nKnown DSA keys: dummy*");
for (i = 0; i < NUM_DSA_KEYS; i++) {
printf(", %s%s", dsa_keytable[i].name, dsa_keytable[i].known ? "*" : "");
}
printf("\n"
"\n"
"'dummy' is not an actual key but a special signature\n"
"which tries to exploit a quirk in the verification code.\n"
"\n"
"A star after the name means the private key is known and\n"
"can be used for signing.\n"
"\n");
}
struct dsa_key *
parse_dsa_key(int argc, char * argv[])
{
int i;
if (argc < 1) {
return NULL;
}
for (i = 0; i < NUM_DSA_KEYS; i++) {
if (!strcmp(argv[0], dsa_keytable[i].name)) {
return &dsa_keytable[i];
}
}
fprintf(stderr, "Unknown key '%s'!\n", argv[0]);
return NULL;
}
void
help_sign()
{
printf("\n"
"Usage:\tmi4code sign [options] <infile> <outfile> [keyid]\n"
"\n"
"\tSign the file with DSA private key. If key not\n"
"\tgiven the dummy signature will be used.\n"
"\n"
"options:\n"
"\t-l\tlist available keys\n"
"\t-v\tincrease verbosity\n"
"\t-q\tdecrease verbosity\n"
"\t-h\tthis help\n"
"\n");
exit(1);
}
const char dummy_r[20] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
const char dummy_s[20] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int
cmd_sign(int argc, char * argv[])
{
FILE * ifp, * ofp;
struct dsa_key * dkey;
int c;
while ((c = myopt(argc, argv, "lvqh", NULL)) > 0) {
switch (c) {
case 'l':
print_dsa_keys();
return 0;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_sign();
break;
}
}
argc += c;
argv -= c;
if (argc < 2) {
fprintf(stderr, "Invalid number of arguments!\n");
help_sign();
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
ofp = fopen(argv[1], "wb");
if (!ofp) {
perror(argv[1]);
return 1;
}
argc -= 2;
argv += 2;
if (!mi4hdr_read(ifp)) {
return 1;
}
if (!mi4hdr_dsa_check()) {
return 1;
}
if (argc < 1 || !strcmp(argv[0], "dummy")) {
memcpy(mi4hdr.dsa_r, dummy_r, sizeof(mi4hdr.dsa_r));
memcpy(mi4hdr.dsa_s, dummy_s, sizeof(mi4hdr.dsa_s));
printv(V_ALL,
"*************************************************************\n"
"** Image signed with 'dummy' DSA signature. **\n"
"** This works with certain versions of the bootloader **\n"
"** and completely bypasses the DSA check! It works **\n"
"** only because the DSA verification code in the **\n"
"** bootloader has a certain quirk and accepts this **\n"
"** signature regardless of the contents of the file. **\n"
"** This trick may not work on all (future) versions **\n"
"** of the bootloader. **\n"
"*************************************************************\n");
} else {
init_dsa();
dkey = parse_dsa_key(argc, argv);
if (!dkey) {
return 1;
}
if (!dkey->known) {
fprintf(stderr,
"The private key for '%s' is not known! Cannot sign with it!\n",
dkey->name);
}
sign_image(ifp, dkey->p, dkey->q, dkey->g, dkey->y,
dkey->x, mi4hdr.dsa_r, mi4hdr.dsa_s);
printv(V_ALL,
"*************************************************************\n"
"** Image signed with DSA key. **\n"
"** A bootloader must have the same key **\n"
"** to boot the signed image! **\n"
"*************************************************************\n");
}
mi4hdr_write(ofp);
file_copy(ifp, ofp, -1, NULL);
return 0;
}
void
help_verify()
{
printf("\n"
"Usage:\tmi4code verify [options] <file> [keyid]\n"
"\n"
"options:\n"
"\t-l\tlist available keys\n"
"\t-v\tincrease verbosity\n"
"\t-q\tdecrease verbosity\n"
"\t-h\tthis help\n"
"\n");
exit(1);
}
int
cmd_verify(int argc, char * argv[])
{
struct dsa_key * dkey;
FILE * ifp, * bfp;
int i;
int c;
bfp = NULL; /* !!! */
while ((c = myopt(argc, argv, "lvqh", NULL)) > 0) {
switch (c) {
case 'l':
print_dsa_keys();
return 0;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_verify();
break;
}
}
argc += c;
argv -= c;
if (argc < 1) {
fprintf(stderr, "Invalid number of arguments!\n");
help_verify();
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
argc -= 1;
argv += 1;
if (!mi4hdr_read(ifp)) {
return 1;
}
if (!mi4hdr_dsa_check()) {
return 1;
}
if (!memcmp(mi4hdr.dsa_r, dummy_r, sizeof(mi4hdr.dsa_r)) &&
!memcmp(mi4hdr.dsa_s, dummy_s, sizeof(mi4hdr.dsa_s))) {
fprintf(stderr,
"The mi4 is signed with 'dummy' signature. "
"It is not possible to verify it.\n");
return 0;
}
init_dsa();
if (argc > 0) {
dkey = parse_dsa_key(argc, argv);
if (!dkey) {
return 1;
}
if (verify_image(ifp, dkey->p, dkey->q, dkey->g, dkey->y,
mi4hdr.dsa_r, mi4hdr.dsa_s)) {
printv(V_ALL, "Image verified ok with DSA key '%s'\n", dkey->name);
return 0;
}
printv(V_ALL, "Verificaion failed with DSA key '%s'!\n", dkey->name);
return 1;
}
for (i = 0; i < NUM_DSA_KEYS; i++) {
dkey = &dsa_keytable[i];
printv(V_LOW, "Trying DSA key '%s'\n", dkey->name);
if (verify_image(ifp, dkey->p, dkey->q, dkey->g, dkey->y,
mi4hdr.dsa_r, mi4hdr.dsa_s)) {
printv(V_ALL, "Image verified ok with DSA key '%s'\n", dkey->name);
return 0;
}
}
printv(V_ALL, "No suitable DSA key found (or signature is incorrect)!\n");
return 1;
}
void
help_keyscan()
{
printf("\n"
"Usage:\tmi4code keyscan [options] <infile> <keyfile>\n"
"\n"
"\tScan for potential keys for <infile> in <keyfile>\n"
"\n"
"options:\n"
"\t-v\tincrease verbosity\n"
"\t-q\tdecrease verbosity\n"
"\t-h\tthis help\n"
"\n");
exit(1);
}
int
cmd_keyscan(int argc, char * argv[])
{
FILE * ifp, * kfp;
int complete = 0;
int c;
while ((c = myopt(argc, argv, "vqh", NULL)) > 0) {
switch (c) {
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_keyscan();
break;
}
}
argc += c;
argv -= c;
if (argc != 2) {
fprintf(stderr, "Invalid number of arguments!\n");
help_keyscan();
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
if (!strcmp(argv[1], "-")) {
kfp = stdin;
complete = 1;
} else {
kfp = fopen(argv[1], "rb");
if (!kfp) {
perror(argv[1]);
return 1;
}
}
argc -= 2;
argv += 2;
if (!mi4hdr_read(ifp)) {
return 1;
}
key_scan(ifp, kfp, complete);
return 0;
}
void
help_blpatch()
{
printf("\n"
"Usage:\tmi4code blpatch [options] <infile> <outfile> [keyid]\n"
"\n"
"\tPatch the bootloader file with DSA public key. If key not\n"
"\tgiven the mi4code key will be used.\n"
"\n"
"options:\n"
"\t-l\tlist available keys\n"
"\t-v\tincrease verbosity\n"
"\t-q\tdecrease verbosity\n"
"\t-h\tthis help\n"
"\n");
exit(1);
}
int
cmd_blpatch(int argc, char * argv[])
{
FILE * ifp, * ofp;
struct dsa_key * dkey;
int c;
while ((c = myopt(argc, argv, "lvqh", NULL)) > 0) {
switch (c) {
case 'l':
print_dsa_keys();
return 0;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_blpatch();
break;
}
}
argc += c;
argv -= c;
if (argc < 2) {
fprintf(stderr, "Invalid number of arguments!\n");
return 1;
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
ofp = fopen(argv[1], "wb");
if (!ofp) {
perror(argv[1]);
return 1;
}
argc -= 2;
argv += 2;
if (argc < 1) {
dkey = &dsa_keytable[0];
} else {
dkey = parse_dsa_key(argc, argv);
}
if (!dkey) {
return 1;
}
return bl_patch(ifp, ofp, dkey);
}
void
print_hex_keys()
{
int i;
printf("\nKnown HEX keys: %s", hex_keytable[0].name);
for (i = 1; i < NUM_HEX_KEYS; i++) {
printf(", %s", hex_keytable[i].name);
}
printf("\n\n");
}
struct hex_key *
parse_hex_key(int argc, char * argv[])
{
int i;
if (argc < 1) {
fprintf(stderr, "Invalid number of arguments!\n");
return NULL;
}
for (i = 0; i < NUM_HEX_KEYS; i++) {
if (!strcmp(argv[0], hex_keytable[i].name)) {
return &hex_keytable[i];
}
}
fprintf(stderr, "Unknown key '%s'!\n", argv[0]);
return NULL;
}
void
help_hexdec()
{
printf("\n"
"Usage:\tmi4code hexdec [options] <infile> <outfile> <keyid>\n"
"\n"
"options:\n"
"\t-l\tlist available keys\n"
"\t-s\tstrip hex header\n"
"\t-v\tincrease verbosity\n"
"\t-q\tdecrease verbosity\n"
"\t-h\tthis help\n"
"\n");
exit(1);
}
int
cmd_hexdec(int argc, char * argv[])
{
struct hex_key * hkey;
FILE * ifp, * ofp;
int strip_header = 0;
int c;
while ((c = myopt(argc, argv, "lsvqh", NULL)) > 0) {
switch (c) {
case 'l':
print_hex_keys();
return 0;
case 's':
strip_header = 1;
break;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_hexdec();
break;
}
}
argc += c;
argv -= c;
if (argc < 3) {
fprintf(stderr, "Invalid number of arguments!\n");
help_hexdec();
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
ofp = fopen(argv[1], "wb");
if (!ofp) {
perror(argv[1]);
return 1;
}
argc -= 2;
argv += 2;
hkey = parse_hex_key(argc, argv);
if (!hkey) {
return 1;
}
if (!hexhdr_read(ifp)) {
return 1;
}
if (!strip_header) {
printv(V_LOW, "Copying the hex header\n");
hexhdr_write(ofp);
} else {
printv(V_LOW, "Skipping the hex header\n");
}
printv(V_ALL, "Decoding with key '%s'\n", hkey->name);
file_hexdecode(ifp, ofp, hkey, NULL);
printv(V_ALL,
"*************************************************************\n"
"** This tool currently has no way of knowing if **\n"
"** the correct key was used. It's up to the user **\n"
"** to verify the results somehow. **\n"
"*************************************************************\n");
return 0;
}
void
help_hexenc()
{
printf("\n"
"Usage:\tmi4code hexenc [options] <infile> <outfile> <keyid>\n"
"\n"
"options:\n"
"\t-l\tlist available keys\n"
"\t-n\tdon't correct the checksum\n"
"\t-v\tincrease verbosity\n"
"\t-q\tdecrease verbosity\n"
"\t-h\tthis help\n"
"\n");
exit(1);
}
int
cmd_hexenc(int argc, char * argv[])
{
struct hex_key * hkey;
FILE * ifp, * ofp;
uint32_t sum;
int fix_csum = 1;
int c;
while ((c = myopt(argc, argv, "lnvqh", NULL)) > 0) {
switch (c) {
case 'l':
print_hex_keys();
return 0;
case 'n':
fix_csum = 0;
break;
case 'v':
verbose++;
break;
case 'q':
verbose--;
break;
case 'h':
help_hexenc();
break;
}
}
argc += c;
argv -= c;
if (argc < 3) {
fprintf(stderr, "Invalid number of arguments!\n");
help_hexenc();
}
ifp = fopen(argv[0], "rb");
if (!ifp) {
perror(argv[0]);
return 1;
}
ofp = fopen(argv[1], "wb");
if (!ofp) {
perror(argv[1]);
return 1;
}
argc -= 2;
argv += 2;
hkey = parse_hex_key(argc, argv);
if (!hkey) {
return 1;
}
if (!hexhdr_read(ifp)) {
return 1;
}
hexhdr_write(ofp);
sum = hexhdr.sum1;
printv(V_ALL, "Encoding with key '%s'\n", hkey->name);
file_hexencode(ifp, ofp, hkey, &sum);
if (sum != hexhdr.sum2) {
if (fix_csum) {
printv(V_ALL, "Checksum corrected (%08x -> %08x)\n", hexhdr.sum2, sum);
hexhdr.sum2 = sum;
hexhdr_write(ofp);
} else {
printv(V_ALL, "Checksum mismatch detected (%08x <-> %08x)\n",
hexhdr.sum2, sum);
}
}
printv(V_ALL,
"*************************************************************\n"
"** This tool currently has no way of knowing if **\n"
"** the correct key was used or if the bootloader **\n"
"** was broken in some other way. It is even possible **\n"
"** that this tool does not encode the file in a right **\n"
"** way (it has not been tested on actual hardware). **\n"
"** Trying to flash a broken bootloader may break your **\n"
"** player beyond repair. IF YOU FEEL UNSURE, ABORT **\n"
"** WHATEVER YOU ARE TRYING TO DO NOW! **\n"
"*************************************************************\n");
return 0;
}
cmd_func
get_cmd(const char * s)
{
int i, len, cmd;
cmd = -1;
len = strlen(s);
for (i = 0; i < NUM_CMDS; i++) {
if (!memcmp(cmd_table[i].name, s, len) && cmd_table[i].func) {
if (cmd < 0) {
cmd = i;
} else {
fprintf(stderr, "Ambiguous command, could be '%s' or '%s'!\n",
cmd_table[cmd].name, cmd_table[i].name);
return NULL;
}
}
}
return cmd >= 0 ? cmd_table[cmd].func : NULL;
}
#ifdef SUPPORT_DSA
#define VERSION_EXT "-DSA"
#else
#define VERSION_EXT ""
#endif
int
main(int argc, char * argv[])
{
cmd_func func;
printf("mi4code " VERSION VERSION_EXT " (c) by MrH 2008\n");
if (argc < 2) {
help();
}
func = get_cmd(argv[1]);
if (!func) {
fprintf(stderr, "Unknown command '%s'!\n", argv[1]);
help();
}
return func(argc - 2, argv + 2);
}
Generated by GNU enscript 1.6.4.