SVN-Revision: 14672master
parent
38821210b0
commit
4a518ddf1c
@ -0,0 +1,307 @@ |
|||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*********************************************************************** |
||||||
|
** md5.c -- the source code for MD5 routines ** |
||||||
|
** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** |
||||||
|
** Created: 2/17/90 RLR ** |
||||||
|
** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** |
||||||
|
*********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
*********************************************************************** |
||||||
|
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** |
||||||
|
** ** |
||||||
|
** License to copy and use this software is granted provided that ** |
||||||
|
** it is identified as the "RSA Data Security, Inc. MD5 Message- ** |
||||||
|
** Digest Algorithm" in all material mentioning or referencing this ** |
||||||
|
** software or this function. ** |
||||||
|
** ** |
||||||
|
** License is also granted to make and use derivative works ** |
||||||
|
** provided that such works are identified as "derived from the RSA ** |
||||||
|
** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** |
||||||
|
** material mentioning or referencing the derived work. ** |
||||||
|
** ** |
||||||
|
** RSA Data Security, Inc. makes no representations concerning ** |
||||||
|
** either the merchantability of this software or the suitability ** |
||||||
|
** of this software for any particular purpose. It is provided "as ** |
||||||
|
** is" without express or implied warranty of any kind. ** |
||||||
|
** ** |
||||||
|
** These notices must be retained in any copies of any part of this ** |
||||||
|
** documentation and/or software. ** |
||||||
|
*********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <string.h> |
||||||
|
#include "md5.h" |
||||||
|
|
||||||
|
/*
|
||||||
|
*********************************************************************** |
||||||
|
** Message-digest routines: ** |
||||||
|
** To form the message digest for a message M ** |
||||||
|
** (1) Initialize a context buffer mdContext using MD5_Init ** |
||||||
|
** (2) Call MD5_Update on mdContext and M ** |
||||||
|
** (3) Call MD5_Final on mdContext ** |
||||||
|
** The message digest is now in mdContext->digest[0...15] ** |
||||||
|
*********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/* forward declaration */ |
||||||
|
static void Transform (); |
||||||
|
|
||||||
|
static unsigned char PADDING[64] = { |
||||||
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
||||||
|
}; |
||||||
|
|
||||||
|
/* F, G, H and I are basic MD5 functions */ |
||||||
|
#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) |
||||||
|
#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) |
||||||
|
#define H(x, y, z) ((x) ^ (y) ^ (z)) |
||||||
|
#define I(x, y, z) ((y) ^ ((x) | (~z))) |
||||||
|
|
||||||
|
/* ROTATE_LEFT rotates x left n bits */ |
||||||
|
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) |
||||||
|
|
||||||
|
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ |
||||||
|
/* Rotation is separate from addition to prevent recomputation */ |
||||||
|
#define FF(a, b, c, d, x, s, ac) \ |
||||||
|
{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
} |
||||||
|
#define GG(a, b, c, d, x, s, ac) \ |
||||||
|
{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
} |
||||||
|
#define HH(a, b, c, d, x, s, ac) \ |
||||||
|
{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
} |
||||||
|
#define II(a, b, c, d, x, s, ac) \ |
||||||
|
{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
} |
||||||
|
|
||||||
|
#ifdef __STDC__ |
||||||
|
#define UL(x) x##U |
||||||
|
#else |
||||||
|
#define UL(x) x |
||||||
|
#endif |
||||||
|
|
||||||
|
/* The routine MD5_Init initializes the message-digest context
|
||||||
|
mdContext. All fields are set to zero. |
||||||
|
*/ |
||||||
|
void MD5_Init (mdContext) |
||||||
|
MD5_CTX *mdContext; |
||||||
|
{ |
||||||
|
mdContext->i[0] = mdContext->i[1] = (UINT4)0; |
||||||
|
|
||||||
|
/* Load magic initialization constants.
|
||||||
|
*/ |
||||||
|
mdContext->buf[0] = (UINT4)0x67452301; |
||||||
|
mdContext->buf[1] = (UINT4)0xefcdab89; |
||||||
|
mdContext->buf[2] = (UINT4)0x98badcfe; |
||||||
|
mdContext->buf[3] = (UINT4)0x10325476; |
||||||
|
} |
||||||
|
|
||||||
|
/* The routine MD5Update updates the message-digest context to
|
||||||
|
account for the presence of each of the characters inBuf[0..inLen-1] |
||||||
|
in the message whose digest is being computed. |
||||||
|
*/ |
||||||
|
void MD5_Update (mdContext, inBuf, inLen) |
||||||
|
MD5_CTX *mdContext; |
||||||
|
unsigned char *inBuf; |
||||||
|
unsigned int inLen; |
||||||
|
{ |
||||||
|
UINT4 in[16]; |
||||||
|
int mdi; |
||||||
|
unsigned int i, ii; |
||||||
|
|
||||||
|
/* compute number of bytes mod 64 */ |
||||||
|
mdi = (int)((mdContext->i[0] >> 3) & 0x3F); |
||||||
|
|
||||||
|
/* update number of bits */ |
||||||
|
if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) |
||||||
|
mdContext->i[1]++; |
||||||
|
mdContext->i[0] += ((UINT4)inLen << 3); |
||||||
|
mdContext->i[1] += ((UINT4)inLen >> 29); |
||||||
|
|
||||||
|
while (inLen--) { |
||||||
|
/* add new character to buffer, increment mdi */ |
||||||
|
mdContext->in[mdi++] = *inBuf++; |
||||||
|
|
||||||
|
/* transform if necessary */ |
||||||
|
if (mdi == 0x40) { |
||||||
|
for (i = 0, ii = 0; i < 16; i++, ii += 4) |
||||||
|
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | |
||||||
|
(((UINT4)mdContext->in[ii+2]) << 16) | |
||||||
|
(((UINT4)mdContext->in[ii+1]) << 8) | |
||||||
|
((UINT4)mdContext->in[ii]); |
||||||
|
Transform (mdContext->buf, in); |
||||||
|
mdi = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* The routine MD5Final terminates the message-digest computation and
|
||||||
|
ends with the desired message digest in mdContext->digest[0...15]. |
||||||
|
*/ |
||||||
|
void MD5_Final (hash, mdContext) |
||||||
|
unsigned char hash[]; |
||||||
|
MD5_CTX *mdContext; |
||||||
|
{ |
||||||
|
UINT4 in[16]; |
||||||
|
int mdi; |
||||||
|
unsigned int i, ii; |
||||||
|
unsigned int padLen; |
||||||
|
|
||||||
|
/* save number of bits */ |
||||||
|
in[14] = mdContext->i[0]; |
||||||
|
in[15] = mdContext->i[1]; |
||||||
|
|
||||||
|
/* compute number of bytes mod 64 */ |
||||||
|
mdi = (int)((mdContext->i[0] >> 3) & 0x3F); |
||||||
|
|
||||||
|
/* pad out to 56 mod 64 */ |
||||||
|
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); |
||||||
|
MD5_Update (mdContext, PADDING, padLen); |
||||||
|
|
||||||
|
/* append length in bits and transform */ |
||||||
|
for (i = 0, ii = 0; i < 14; i++, ii += 4) |
||||||
|
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | |
||||||
|
(((UINT4)mdContext->in[ii+2]) << 16) | |
||||||
|
(((UINT4)mdContext->in[ii+1]) << 8) | |
||||||
|
((UINT4)mdContext->in[ii]); |
||||||
|
Transform (mdContext->buf, in); |
||||||
|
|
||||||
|
/* store buffer in digest */ |
||||||
|
for (i = 0, ii = 0; i < 4; i++, ii += 4) { |
||||||
|
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); |
||||||
|
mdContext->digest[ii+1] = |
||||||
|
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF); |
||||||
|
mdContext->digest[ii+2] = |
||||||
|
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF); |
||||||
|
mdContext->digest[ii+3] = |
||||||
|
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF); |
||||||
|
} |
||||||
|
memcpy(hash, mdContext->digest, 16); |
||||||
|
} |
||||||
|
|
||||||
|
/* Basic MD5 step. Transforms buf based on in.
|
||||||
|
*/ |
||||||
|
static void Transform (buf, in) |
||||||
|
UINT4 *buf; |
||||||
|
UINT4 *in; |
||||||
|
{ |
||||||
|
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; |
||||||
|
|
||||||
|
/* Round 1 */ |
||||||
|
#define S11 7 |
||||||
|
#define S12 12 |
||||||
|
#define S13 17 |
||||||
|
#define S14 22 |
||||||
|
FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ |
||||||
|
FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ |
||||||
|
FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ |
||||||
|
FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ |
||||||
|
FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ |
||||||
|
FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ |
||||||
|
FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ |
||||||
|
FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ |
||||||
|
FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ |
||||||
|
FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ |
||||||
|
FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ |
||||||
|
FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ |
||||||
|
FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ |
||||||
|
FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ |
||||||
|
FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ |
||||||
|
FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ |
||||||
|
|
||||||
|
/* Round 2 */ |
||||||
|
#define S21 5 |
||||||
|
#define S22 9 |
||||||
|
#define S23 14 |
||||||
|
#define S24 20 |
||||||
|
GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ |
||||||
|
GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ |
||||||
|
GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ |
||||||
|
GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ |
||||||
|
GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ |
||||||
|
GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ |
||||||
|
GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ |
||||||
|
GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ |
||||||
|
GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ |
||||||
|
GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ |
||||||
|
GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ |
||||||
|
GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ |
||||||
|
GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ |
||||||
|
GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ |
||||||
|
GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ |
||||||
|
GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ |
||||||
|
|
||||||
|
/* Round 3 */ |
||||||
|
#define S31 4 |
||||||
|
#define S32 11 |
||||||
|
#define S33 16 |
||||||
|
#define S34 23 |
||||||
|
HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ |
||||||
|
HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ |
||||||
|
HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ |
||||||
|
HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ |
||||||
|
HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ |
||||||
|
HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ |
||||||
|
HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ |
||||||
|
HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ |
||||||
|
HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ |
||||||
|
HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ |
||||||
|
HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ |
||||||
|
HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ |
||||||
|
HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ |
||||||
|
HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ |
||||||
|
HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ |
||||||
|
HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ |
||||||
|
|
||||||
|
/* Round 4 */ |
||||||
|
#define S41 6 |
||||||
|
#define S42 10 |
||||||
|
#define S43 15 |
||||||
|
#define S44 21 |
||||||
|
II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ |
||||||
|
II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ |
||||||
|
II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ |
||||||
|
II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ |
||||||
|
II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ |
||||||
|
II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ |
||||||
|
II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ |
||||||
|
II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ |
||||||
|
II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ |
||||||
|
II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ |
||||||
|
II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ |
||||||
|
II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ |
||||||
|
II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ |
||||||
|
II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ |
||||||
|
II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ |
||||||
|
II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ |
||||||
|
|
||||||
|
buf[0] += a; |
||||||
|
buf[1] += b; |
||||||
|
buf[2] += c; |
||||||
|
buf[3] += d; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
*********************************************************************** |
||||||
|
** End of md5.c ** |
||||||
|
******************************** (cut) ******************************** |
||||||
|
*/ |
@ -0,0 +1,65 @@ |
|||||||
|
/*
|
||||||
|
*********************************************************************** |
||||||
|
** md5.h -- header file for implementation of MD5 ** |
||||||
|
** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** |
||||||
|
** Created: 2/17/90 RLR ** |
||||||
|
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** |
||||||
|
** Revised (for MD5): RLR 4/27/91 ** |
||||||
|
** -- G modified to have y&~z instead of y&z ** |
||||||
|
** -- FF, GG, HH modified to add in last register done ** |
||||||
|
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** |
||||||
|
** -- distinct additive constant for each step ** |
||||||
|
** -- round 4 added, working mod 7 ** |
||||||
|
*********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
*********************************************************************** |
||||||
|
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** |
||||||
|
** ** |
||||||
|
** License to copy and use this software is granted provided that ** |
||||||
|
** it is identified as the "RSA Data Security, Inc. MD5 Message- ** |
||||||
|
** Digest Algorithm" in all material mentioning or referencing this ** |
||||||
|
** software or this function. ** |
||||||
|
** ** |
||||||
|
** License is also granted to make and use derivative works ** |
||||||
|
** provided that such works are identified as "derived from the RSA ** |
||||||
|
** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** |
||||||
|
** material mentioning or referencing the derived work. ** |
||||||
|
** ** |
||||||
|
** RSA Data Security, Inc. makes no representations concerning ** |
||||||
|
** either the merchantability of this software or the suitability ** |
||||||
|
** of this software for any particular purpose. It is provided "as ** |
||||||
|
** is" without express or implied warranty of any kind. ** |
||||||
|
** ** |
||||||
|
** These notices must be retained in any copies of any part of this ** |
||||||
|
** documentation and/or software. ** |
||||||
|
*********************************************************************** |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef __MD5_INCLUDE__ |
||||||
|
|
||||||
|
/* typedef a 32-bit type */ |
||||||
|
#ifdef _LP64 |
||||||
|
typedef unsigned int UINT4; |
||||||
|
typedef int INT4; |
||||||
|
#else |
||||||
|
typedef unsigned long UINT4; |
||||||
|
typedef long INT4; |
||||||
|
#endif |
||||||
|
#define _UINT4_T |
||||||
|
|
||||||
|
/* Data structure for MD5 (Message-Digest) computation */ |
||||||
|
typedef struct { |
||||||
|
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ |
||||||
|
UINT4 buf[4]; /* scratch buffer */ |
||||||
|
unsigned char in[64]; /* input buffer */ |
||||||
|
unsigned char digest[16]; /* actual digest after MD5Final call */ |
||||||
|
} MD5_CTX; |
||||||
|
|
||||||
|
void MD5_Init (); |
||||||
|
void MD5_Update (); |
||||||
|
void MD5_Final (); |
||||||
|
|
||||||
|
#define __MD5_INCLUDE__ |
||||||
|
#endif /* __MD5_INCLUDE__ */ |
@ -0,0 +1,432 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> |
||||||
|
* |
||||||
|
* This tool was based on: |
||||||
|
* TP-Link WR941 V2 firmware checksum fixing tool. |
||||||
|
* Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify it |
||||||
|
* under the terms of the GNU General Public License version 2 as published |
||||||
|
* by the Free Software Foundation. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <string.h> |
||||||
|
#include <unistd.h> /* for unlink() */ |
||||||
|
#include <libgen.h> |
||||||
|
#include <getopt.h> /* for getopt() */ |
||||||
|
#include <stdarg.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <sys/stat.h> |
||||||
|
|
||||||
|
#include "md5.h" |
||||||
|
|
||||||
|
#if (__BYTE_ORDER == __BIG_ENDIAN) |
||||||
|
# define HOST_TO_BE32(x) (x) |
||||||
|
# define BE32_TO_HOST(x) (x) |
||||||
|
#else |
||||||
|
# define HOST_TO_BE32(x) bswap_32(x) |
||||||
|
# define BE32_TO_HOST(x) bswap_32(x) |
||||||
|
#endif |
||||||
|
|
||||||
|
#define HEADER_VERSION_V1 0x01000000 |
||||||
|
#define HWID_TL_WR941ND_V2 0x09410002 |
||||||
|
|
||||||
|
#define MD5SUM_LEN 16 |
||||||
|
|
||||||
|
struct file_info { |
||||||
|
char *file_name; /* name of the file */ |
||||||
|
uint32_t file_size; /* length of the file */ |
||||||
|
}; |
||||||
|
|
||||||
|
struct fw_header { |
||||||
|
uint32_t version; /* header version */ |
||||||
|
char vendor_name[24]; |
||||||
|
char fw_version[36]; |
||||||
|
uint32_t hw_id; /* hardware id */ |
||||||
|
uint32_t hw_rev; /* hardware revision */ |
||||||
|
uint32_t unk1; |
||||||
|
uint8_t md5sum1[MD5SUM_LEN]; |
||||||
|
uint32_t unk2; |
||||||
|
uint8_t md5sum2[MD5SUM_LEN]; |
||||||
|
uint32_t unk3; |
||||||
|
uint32_t kernel_la; /* kernel load address */ |
||||||
|
uint32_t kernel_ep; /* kernel entry point */ |
||||||
|
uint32_t fw_length; /* total length of the firmware */ |
||||||
|
uint32_t kernel_ofs; /* kernel data offset */ |
||||||
|
uint32_t kernel_len; /* kernel data length */ |
||||||
|
uint32_t rootfs_ofs; /* rootfs data offset */ |
||||||
|
uint32_t rootfs_len; /* rootfs data length */ |
||||||
|
uint32_t boot_ofs; /* bootloader data offset */ |
||||||
|
uint32_t boot_len; /* bootloader data length */ |
||||||
|
uint8_t pad[360]; |
||||||
|
} __attribute__ ((packed)); |
||||||
|
|
||||||
|
struct board_info { |
||||||
|
char *id; |
||||||
|
uint32_t hw_id; |
||||||
|
uint32_t hw_rev; |
||||||
|
uint32_t fw_max_len; |
||||||
|
uint32_t kernel_la; |
||||||
|
uint32_t kernel_ep; |
||||||
|
uint32_t rootfs_ofs; |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Globals |
||||||
|
*/ |
||||||
|
static char *ofname; |
||||||
|
static char *progname; |
||||||
|
static char *vendor = "TP-LINK Technologies"; |
||||||
|
static char *version = "ver. 1.0"; |
||||||
|
|
||||||
|
static char *board_id; |
||||||
|
static struct board_info *board; |
||||||
|
static struct file_info kernel_info; |
||||||
|
static struct file_info rootfs_info; |
||||||
|
static struct file_info boot_info; |
||||||
|
|
||||||
|
char md5salt_normal[MD5SUM_LEN] = { |
||||||
|
0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb, |
||||||
|
0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38, |
||||||
|
}; |
||||||
|
|
||||||
|
char md5salt_boot[MD5SUM_LEN] = { |
||||||
|
0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa, |
||||||
|
0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct board_info boards[] = { |
||||||
|
{ |
||||||
|
.id = "TL-WR941NDv2", |
||||||
|
.hw_id = HWID_TL_WR941ND_V2, |
||||||
|
.hw_rev = 2, |
||||||
|
.fw_max_len = 0x3c0000, |
||||||
|
.kernel_la = 0x80060000, |
||||||
|
.kernel_ep = 0x80060000, |
||||||
|
.rootfs_ofs = 0x120000, |
||||||
|
}, { |
||||||
|
/* terminating entry */ |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Message macros |
||||||
|
*/ |
||||||
|
#define ERR(fmt, ...) do { \ |
||||||
|
fflush(0); \
|
||||||
|
fprintf(stderr, "[%s] *** error: " fmt "\n", \
|
||||||
|
progname, ## __VA_ARGS__ ); \
|
||||||
|
} while (0) |
||||||
|
|
||||||
|
#define ERRS(fmt, ...) do { \ |
||||||
|
int save = errno; \
|
||||||
|
fflush(0); \
|
||||||
|
fprintf(stderr, "[%s] *** error: " fmt "\n", \
|
||||||
|
progname, ## __VA_ARGS__, strerror(save)); \
|
||||||
|
} while (0) |
||||||
|
|
||||||
|
#define DBG(fmt, ...) do { \ |
||||||
|
fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
|
||||||
|
} while (0) |
||||||
|
|
||||||
|
static struct board_info *find_board(char *id) |
||||||
|
{ |
||||||
|
struct board_info *ret; |
||||||
|
struct board_info *board; |
||||||
|
|
||||||
|
ret = NULL; |
||||||
|
for (board = boards; board->id != NULL; board++){ |
||||||
|
if (strcasecmp(id, board->id) == 0) { |
||||||
|
ret = board; |
||||||
|
break; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
static void usage(int status) |
||||||
|
{ |
||||||
|
FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; |
||||||
|
struct board_info *board; |
||||||
|
|
||||||
|
fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); |
||||||
|
fprintf(stream, |
||||||
|
"\n" |
||||||
|
"Options:\n" |
||||||
|
" -B <board> create image for the board specified with <board>\n" |
||||||
|
" -k <file> read kernel image from the file <file>\n" |
||||||
|
" -r <file> read rootfs image from the file <file>\n" |
||||||
|
" -o <file> write output to the file <file>\n" |
||||||
|
" -v <version> set image version to <version>\n" |
||||||
|
" -h show this screen\n" |
||||||
|
); |
||||||
|
|
||||||
|
exit(status); |
||||||
|
} |
||||||
|
|
||||||
|
static int get_md5(char *data, int size, char *md5) |
||||||
|
{ |
||||||
|
MD5_CTX ctx; |
||||||
|
|
||||||
|
MD5_Init(&ctx); |
||||||
|
MD5_Update(&ctx, data, size); |
||||||
|
MD5_Final(md5, &ctx); |
||||||
|
} |
||||||
|
|
||||||
|
static int get_file_stat(struct file_info *fdata) |
||||||
|
{ |
||||||
|
struct stat st; |
||||||
|
int res; |
||||||
|
|
||||||
|
if (fdata->file_name == NULL) |
||||||
|
return 0; |
||||||
|
|
||||||
|
res = stat(fdata->file_name, &st); |
||||||
|
if (res){ |
||||||
|
ERRS("stat failed on %s", fdata->file_name); |
||||||
|
return res; |
||||||
|
} |
||||||
|
|
||||||
|
fdata->file_size = st.st_size; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int read_to_buf(struct file_info *fdata, char *buf) |
||||||
|
{ |
||||||
|
FILE *f; |
||||||
|
int ret = EXIT_FAILURE; |
||||||
|
|
||||||
|
f = fopen(fdata->file_name, "r"); |
||||||
|
if (f == NULL) { |
||||||
|
ERRS("could not open \"%s\" for reading", fdata->file_name); |
||||||
|
goto out; |
||||||
|
} |
||||||
|
|
||||||
|
errno = 0; |
||||||
|
fread(buf, fdata->file_size, 1, f); |
||||||
|
if (errno != 0) { |
||||||
|
ERRS("unable to read from file \"%s\"", fdata->file_name); |
||||||
|
goto out_close; |
||||||
|
} |
||||||
|
|
||||||
|
ret = EXIT_SUCCESS; |
||||||
|
|
||||||
|
out_close: |
||||||
|
fclose(f); |
||||||
|
out: |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
static int check_options(void) |
||||||
|
{ |
||||||
|
int ret; |
||||||
|
|
||||||
|
if (board_id == NULL) { |
||||||
|
ERR("no board specified"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
board = find_board(board_id); |
||||||
|
if (board == NULL) { |
||||||
|
ERR("unknown/unsupported board id \"%s\"", board_id); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
if (kernel_info.file_name == NULL) { |
||||||
|
ERR("no kernel image specified"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
ret = get_file_stat(&kernel_info); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
|
||||||
|
if (kernel_info.file_size > board->rootfs_ofs - sizeof(struct fw_header)) { |
||||||
|
ERR("kernel image is too big"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
if (rootfs_info.file_name == NULL) { |
||||||
|
ERR("no rootfs image specified"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
ret = get_file_stat(&rootfs_info); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
|
||||||
|
if (rootfs_info.file_size > (board->fw_max_len - board->rootfs_ofs)) { |
||||||
|
ERR("rootfs image is too big"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
if (ofname == NULL) { |
||||||
|
ERR("no output file specified"); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static void fill_header(char *buf, int len) |
||||||
|
{ |
||||||
|
struct fw_header *hdr = (struct fw_header *)buf; |
||||||
|
|
||||||
|
memset(hdr, 0, sizeof(struct fw_header)); |
||||||
|
|
||||||
|
hdr->version = HOST_TO_BE32(HEADER_VERSION_V1); |
||||||
|
strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name)); |
||||||
|
strncpy(hdr->fw_version, version, sizeof(hdr->fw_version)); |
||||||
|
hdr->hw_id = HOST_TO_BE32(board->hw_id); |
||||||
|
hdr->hw_rev = HOST_TO_BE32(board->hw_rev); |
||||||
|
|
||||||
|
if (boot_info.file_size == 0) |
||||||
|
memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1)); |
||||||
|
else |
||||||
|
memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1)); |
||||||
|
|
||||||
|
hdr->kernel_la = HOST_TO_BE32(board->kernel_la); |
||||||
|
hdr->kernel_ep = HOST_TO_BE32(board->kernel_ep); |
||||||
|
hdr->fw_length = HOST_TO_BE32(board->fw_max_len); |
||||||
|
hdr->kernel_ofs = HOST_TO_BE32(sizeof(struct fw_header)); |
||||||
|
hdr->kernel_len = HOST_TO_BE32(kernel_info.file_size); |
||||||
|
hdr->rootfs_ofs = HOST_TO_BE32(board->rootfs_ofs); |
||||||
|
hdr->rootfs_len = HOST_TO_BE32(rootfs_info.file_size); |
||||||
|
|
||||||
|
get_md5(buf, len, hdr->md5sum1); |
||||||
|
} |
||||||
|
|
||||||
|
static int write_fw(char *data, int len) |
||||||
|
{ |
||||||
|
FILE *f; |
||||||
|
int ret = EXIT_FAILURE; |
||||||
|
|
||||||
|
f = fopen(ofname, "w"); |
||||||
|
if (f == NULL) { |
||||||
|
ERRS("could not open \"%s\" for writing", ofname); |
||||||
|
goto out; |
||||||
|
} |
||||||
|
|
||||||
|
errno = 0; |
||||||
|
fwrite(data, len, 1, f); |
||||||
|
if (errno) { |
||||||
|
ERRS("unable to write output file"); |
||||||
|
goto out_flush; |
||||||
|
} |
||||||
|
|
||||||
|
DBG("firmware file \"%s\" completed", ofname); |
||||||
|
|
||||||
|
ret = EXIT_SUCCESS; |
||||||
|
|
||||||
|
out_flush: |
||||||
|
fflush(f); |
||||||
|
fclose(f); |
||||||
|
if (ret != EXIT_SUCCESS) { |
||||||
|
unlink(ofname); |
||||||
|
} |
||||||
|
out: |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
static int build_fw(void) |
||||||
|
{ |
||||||
|
int buflen; |
||||||
|
char *buf; |
||||||
|
char *p; |
||||||
|
int ret = EXIT_FAILURE; |
||||||
|
|
||||||
|
buflen = board->fw_max_len; |
||||||
|
|
||||||
|
buf = malloc(buflen); |
||||||
|
if (!buf) { |
||||||
|
ERR("no memory for buffer\n"); |
||||||
|
goto out; |
||||||
|
} |
||||||
|
|
||||||
|
memset(buf, 0xff, buflen); |
||||||
|
p = buf + sizeof(struct fw_header); |
||||||
|
ret = read_to_buf(&kernel_info, p); |
||||||
|
if (ret) |
||||||
|
goto out_free_buf; |
||||||
|
|
||||||
|
p = buf + board->rootfs_ofs; |
||||||
|
ret = read_to_buf(&rootfs_info, p); |
||||||
|
if (ret) |
||||||
|
goto out_free_buf; |
||||||
|
|
||||||
|
fill_header(buf, buflen); |
||||||
|
|
||||||
|
ret = write_fw(buf, buflen); |
||||||
|
if (ret) |
||||||
|
goto out_free_buf; |
||||||
|
|
||||||
|
ret = EXIT_SUCCESS; |
||||||
|
|
||||||
|
out_free_buf: |
||||||
|
free(buf); |
||||||
|
out: |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
int ret = EXIT_FAILURE; |
||||||
|
int err; |
||||||
|
|
||||||
|
FILE *outfile; |
||||||
|
|
||||||
|
progname = basename(argv[0]); |
||||||
|
|
||||||
|
while ( 1 ) { |
||||||
|
int c; |
||||||
|
|
||||||
|
c = getopt(argc, argv, "B:V:N:k:r:o:v:h:"); |
||||||
|
if (c == -1) |
||||||
|
break; |
||||||
|
|
||||||
|
switch (c) { |
||||||
|
case 'B': |
||||||
|
board_id = optarg; |
||||||
|
break; |
||||||
|
case 'V': |
||||||
|
version = optarg; |
||||||
|
break; |
||||||
|
case 'N': |
||||||
|
vendor = optarg; |
||||||
|
break; |
||||||
|
case 'k': |
||||||
|
kernel_info.file_name = optarg; |
||||||
|
break; |
||||||
|
case 'r': |
||||||
|
rootfs_info.file_name = optarg; |
||||||
|
break; |
||||||
|
case 'o': |
||||||
|
ofname = optarg; |
||||||
|
break; |
||||||
|
case 'v': |
||||||
|
version = optarg; |
||||||
|
break; |
||||||
|
case 'h': |
||||||
|
usage(EXIT_SUCCESS); |
||||||
|
break; |
||||||
|
default: |
||||||
|
usage(EXIT_FAILURE); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ret = check_options(); |
||||||
|
if (ret) |
||||||
|
goto out; |
||||||
|
|
||||||
|
ret = build_fw(); |
||||||
|
|
||||||
|
out: |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
Loading…
Reference in new issue