- fixed warnings in mix_decode.h git-svn-id: svn://svn.ijw.co.nz/svn/OpenRa@1075 993157c7-ee19-0410-b2c4-bb4e9862e678
428 lines
10 KiB
C
428 lines
10 KiB
C
#include <memory>
|
|
|
|
const static char* pubkey_str = "AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V";
|
|
|
|
const static char char2num[] = {
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
|
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
|
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
|
|
|
typedef unsigned int dword;
|
|
typedef unsigned short word;
|
|
typedef unsigned char byte;
|
|
|
|
typedef dword bignum4[4];
|
|
typedef dword bignum[64];
|
|
typedef dword bignum130[130];
|
|
|
|
static struct
|
|
{
|
|
bignum key1;
|
|
bignum key2;
|
|
dword len;
|
|
} pubkey;
|
|
static bignum glob1;
|
|
static dword glob1_bitlen, glob1_len_x2;
|
|
static bignum130 glob2;
|
|
static bignum4 glob1_hi, glob1_hi_inv;
|
|
static dword glob1_hi_bitlen;
|
|
static dword glob1_hi_inv_lo, glob1_hi_inv_hi;
|
|
|
|
static void init_bignum(bignum n, dword val, dword len)
|
|
{
|
|
memset((void *)n, 0, len * 4);
|
|
n[0] = val;
|
|
}
|
|
|
|
static void move_key_to_big(bignum n, char *key, dword klen, dword blen)
|
|
{
|
|
dword sign;
|
|
unsigned i;
|
|
|
|
if (key[0] & 0x80) sign = 0xff;
|
|
else sign = 0;
|
|
|
|
for (i = blen*4; i > klen; i--)
|
|
((char *)n)[i-1] = sign;
|
|
for (; i > 0; i--)
|
|
((char *)n)[i-1] = key[klen-i];
|
|
}
|
|
|
|
static void key_to_bignum(bignum n, char *key, dword len)
|
|
{
|
|
dword keylen;
|
|
int i;
|
|
|
|
if (key[0] != 2) return;
|
|
key++;
|
|
|
|
if (key[0] & 0x80)
|
|
{
|
|
keylen = 0;
|
|
for (i = 0; i < (key[0] & 0x7f); i++) keylen = (keylen << 8) | key[i+1];
|
|
key += (key[0] & 0x7f) + 1;
|
|
}
|
|
else
|
|
{
|
|
keylen = key[0];
|
|
key++;
|
|
}
|
|
if (keylen <= len*4)
|
|
move_key_to_big(n, key, keylen, len);
|
|
}
|
|
|
|
static dword len_bignum(bignum n, dword len)
|
|
{
|
|
int i;
|
|
i = len-1;
|
|
while ((i >= 0) && (n[i] == 0)) i--;
|
|
return i+1;
|
|
}
|
|
|
|
static dword bitlen_bignum(bignum n, dword len)
|
|
{
|
|
dword ddlen, bitlen, mask;
|
|
ddlen = len_bignum(n, len);
|
|
if (ddlen == 0) return 0;
|
|
bitlen = ddlen * 32;
|
|
mask = 0x80000000;
|
|
while ((mask & n[ddlen-1]) == 0) {
|
|
mask >>= 1;
|
|
bitlen--;
|
|
}
|
|
return bitlen;
|
|
}
|
|
|
|
static void init_pubkey()
|
|
{
|
|
dword i, i2, tmp;
|
|
char keytmp[256];
|
|
|
|
init_bignum(pubkey.key2, 0x10001, 64);
|
|
|
|
i = 0;
|
|
i2 = 0;
|
|
while (i < strlen(pubkey_str))
|
|
{
|
|
tmp = char2num[pubkey_str[i++]];
|
|
tmp <<= 6; tmp |= char2num[pubkey_str[i++]];
|
|
tmp <<= 6; tmp |= char2num[pubkey_str[i++]];
|
|
tmp <<= 6; tmp |= char2num[pubkey_str[i++]];
|
|
keytmp[i2++] = (tmp >> 16) & 0xff;
|
|
keytmp[i2++] = (tmp >> 8) & 0xff;
|
|
keytmp[i2++] = tmp & 0xff;
|
|
}
|
|
key_to_bignum(pubkey.key1, keytmp, 64);
|
|
pubkey.len = bitlen_bignum(pubkey.key1, 64) - 1;
|
|
}
|
|
|
|
static dword len_predata()
|
|
{
|
|
dword a = (pubkey.len - 1) / 8;
|
|
return (55 / a + 1) * (a + 1);
|
|
}
|
|
|
|
static long int cmp_bignum(bignum n1, bignum n2, dword len)
|
|
{
|
|
n1 += len-1;
|
|
n2 += len-1;
|
|
while (len > 0) {
|
|
if (*n1 < *n2) return -1;
|
|
if (*n1 > *n2) return 1;
|
|
n1--;
|
|
n2--;
|
|
len--;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void mov_bignum(bignum dest, bignum src, dword len)
|
|
{
|
|
memmove(dest, src, len*4);
|
|
}
|
|
|
|
static void shr_bignum(bignum n, dword bits, unsigned long int len)
|
|
{
|
|
dword i, i2;
|
|
|
|
i2 = bits / 32;
|
|
if (i2 > 0) {
|
|
for (i = 0; i < len - i2; i++) n[i] = n[i + i2];
|
|
for (; i < len; i++) n[i] = 0;
|
|
bits = bits % 32;
|
|
}
|
|
if (bits == 0) return;
|
|
for (i = 0; i < len - 1; i++) n[i] = (n[i] >> bits) | (n[i + 1] << (32 -
|
|
bits));
|
|
n[i] = n[i] >> bits;
|
|
}
|
|
|
|
static void shl_bignum(bignum n, dword bits, dword len)
|
|
{
|
|
dword i, i2;
|
|
|
|
i2 = bits / 32;
|
|
if (i2 > 0) {
|
|
for (i = len - 1; i > i2; i--) n[i] = n[i - i2];
|
|
for (; i > 0; i--) n[i] = 0;
|
|
bits = bits % 32;
|
|
}
|
|
if (bits == 0) return;
|
|
for (i = len - 1; i > 0; i--) n[i] = (n[i] << bits) | (n[i - 1] >> (32 -
|
|
bits));
|
|
n[0] <<= bits;
|
|
}
|
|
|
|
static dword sub_bignum(bignum dest, bignum src1, bignum src2, dword carry, dword len)
|
|
{
|
|
dword i1, i2;
|
|
|
|
len += len;
|
|
while (--len != -1) {
|
|
i1 = *(word *)src1;
|
|
i2 = *(word *)src2;
|
|
*(word *)dest = i1 - i2 - carry;
|
|
src1 = (dword *)(((word *)src1) + 1);
|
|
src2 = (dword *)(((word *)src2) + 1);
|
|
dest = (dword *)(((word *)dest) + 1);
|
|
if ((i1 - i2 - carry) & 0x10000) carry = 1; else carry = 0;
|
|
}
|
|
return carry;
|
|
}
|
|
|
|
static void inv_bignum(bignum n1, bignum n2, dword len)
|
|
{
|
|
bignum n_tmp;
|
|
dword n2_bytelen, bit;
|
|
long int n2_bitlen;
|
|
|
|
init_bignum(n_tmp, 0, len);
|
|
init_bignum(n1, 0, len);
|
|
n2_bitlen = bitlen_bignum(n2, len);
|
|
bit = ((dword)1) << (n2_bitlen % 32);
|
|
n1 += ((n2_bitlen + 32) / 32) - 1;
|
|
n2_bytelen = ((n2_bitlen - 1) / 32) * 4;
|
|
n_tmp[n2_bytelen / 4] |= ((dword)1) << ((n2_bitlen - 1) & 0x1f);
|
|
|
|
while (n2_bitlen > 0) {
|
|
n2_bitlen--;
|
|
shl_bignum(n_tmp, 1, len);
|
|
if (cmp_bignum(n_tmp, n2, len) != -1) {
|
|
sub_bignum(n_tmp, n_tmp, n2, 0, len);
|
|
*n1 |= bit;
|
|
}
|
|
bit >>= 1;
|
|
if (bit == 0) {
|
|
n1--;
|
|
bit = 0x80000000;
|
|
}
|
|
}
|
|
init_bignum(n_tmp, 0, len);
|
|
}
|
|
|
|
static void inc_bignum(bignum n, dword len)
|
|
{
|
|
while ((++*n == 0) && (--len > 0)) n++;
|
|
}
|
|
|
|
static void init_two_dw(bignum n, dword len)
|
|
{
|
|
mov_bignum(glob1, n, len);
|
|
glob1_bitlen = bitlen_bignum(glob1, len);
|
|
glob1_len_x2 = (glob1_bitlen + 15) / 16;
|
|
mov_bignum(glob1_hi, glob1 + len_bignum(glob1, len) - 2, 2);
|
|
glob1_hi_bitlen = bitlen_bignum(glob1_hi, 2) - 32;
|
|
shr_bignum(glob1_hi, glob1_hi_bitlen, 2);
|
|
inv_bignum(glob1_hi_inv, glob1_hi, 2);
|
|
shr_bignum(glob1_hi_inv, 1, 2);
|
|
glob1_hi_bitlen = (glob1_hi_bitlen + 15) % 16 + 1;
|
|
inc_bignum(glob1_hi_inv, 2);
|
|
if (bitlen_bignum(glob1_hi_inv, 2) > 32)
|
|
{
|
|
shr_bignum(glob1_hi_inv, 1, 2);
|
|
glob1_hi_bitlen--;
|
|
}
|
|
glob1_hi_inv_lo = *(word *)glob1_hi_inv;
|
|
glob1_hi_inv_hi = *(((word *)glob1_hi_inv) + 1);
|
|
}
|
|
|
|
static void mul_bignum_word(bignum n1, bignum n2, dword mul, dword len)
|
|
{
|
|
dword i, tmp;
|
|
|
|
tmp = 0;
|
|
for (i = 0; i < len; i++) {
|
|
tmp = mul * (*(word *)n2) + *(word *)n1 + tmp;
|
|
*(word *)n1 = tmp;
|
|
n1 = (dword *)(((word *)n1) + 1);
|
|
n2 = (dword *)(((word *)n2) + 1);
|
|
tmp >>= 16;
|
|
}
|
|
*(word *)n1 += tmp;
|
|
}
|
|
|
|
static void mul_bignum(bignum dest, bignum src1, bignum src2, dword len)
|
|
{
|
|
dword i;
|
|
|
|
init_bignum(dest, 0, len*2);
|
|
for (i = 0; i < len*2; i++) {
|
|
mul_bignum_word(dest, src1, *(word *)src2, len*2);
|
|
src2 = (dword *)(((word *)src2) + 1);
|
|
dest = (dword *)(((word *)dest) + 1);
|
|
}
|
|
}
|
|
|
|
static void not_bignum(bignum n, dword len)
|
|
{
|
|
dword i;
|
|
for (i = 0; i < len; i++) *(n++) = ~*n;
|
|
}
|
|
|
|
static void neg_bignum(bignum n, dword len)
|
|
{
|
|
not_bignum(n, len);
|
|
inc_bignum(n, len);
|
|
}
|
|
|
|
static dword get_mulword(bignum n)
|
|
{
|
|
dword i;
|
|
word *wn;
|
|
|
|
wn = (word *)n;
|
|
i = (((((((((*(wn-1) ^ 0xffff) & 0xffff) * glob1_hi_inv_lo + 0x10000) >> 1)
|
|
+ (((*(wn-2) ^ 0xffff) * glob1_hi_inv_hi + glob1_hi_inv_hi) >> 1) + 1)
|
|
>> 16) + ((((*(wn-1) ^ 0xffff) & 0xffff) * glob1_hi_inv_hi) >> 1) +
|
|
(((*wn ^ 0xffff) * glob1_hi_inv_lo) >> 1) + 1) >> 14) + glob1_hi_inv_hi
|
|
* (*wn ^ 0xffff) * 2) >> glob1_hi_bitlen;
|
|
if (i > 0xffff) i = 0xffff;
|
|
return i & 0xffff;
|
|
}
|
|
|
|
static void dec_bignum(bignum n, dword len)
|
|
{
|
|
while ((--*n == 0xffffffff) && (--len > 0))
|
|
n++;
|
|
}
|
|
|
|
static void calc_a_bignum(bignum n1, bignum n2, bignum n3, dword len)
|
|
{
|
|
dword g2_len_x2, len_diff;
|
|
word *esi, *edi;
|
|
word tmp;
|
|
|
|
mul_bignum(glob2, n2, n3, len);
|
|
glob2[len*2] = 0;
|
|
g2_len_x2 = len_bignum(glob2, len*2+1)*2;
|
|
if (g2_len_x2 >= glob1_len_x2) {
|
|
inc_bignum(glob2, len*2+1);
|
|
neg_bignum(glob2, len*2+1);
|
|
len_diff = g2_len_x2 + 1 - glob1_len_x2;
|
|
esi = ((word *)glob2) + (1 + g2_len_x2 - glob1_len_x2);
|
|
edi = ((word *)glob2) + (g2_len_x2 + 1);
|
|
for (; len_diff != 0; len_diff--) {
|
|
edi--;
|
|
tmp = get_mulword((dword *)edi);
|
|
esi--;
|
|
if (tmp > 0) {
|
|
mul_bignum_word((dword *)esi, glob1, tmp, 2*len);
|
|
if ((*edi & 0x8000) == 0) {
|
|
if (sub_bignum((dword *)esi, (dword *)esi, glob1, 0, len)) (*edi)--;
|
|
}
|
|
}
|
|
}
|
|
neg_bignum(glob2, len);
|
|
dec_bignum(glob2, len);
|
|
}
|
|
mov_bignum(n1, glob2, len);
|
|
}
|
|
|
|
static void clear_tmp_vars(dword len)
|
|
{
|
|
init_bignum(glob1, 0, len);
|
|
init_bignum(glob2, 0, len);
|
|
init_bignum(glob1_hi_inv, 0, 4);
|
|
init_bignum(glob1_hi, 0, 4);
|
|
glob1_bitlen = 0;
|
|
glob1_hi_bitlen = 0;
|
|
glob1_len_x2 = 0;
|
|
glob1_hi_inv_lo = 0;
|
|
glob1_hi_inv_hi = 0;
|
|
}
|
|
|
|
static void calc_a_key(bignum n1, bignum n2, bignum n3, bignum n4, dword len)
|
|
{
|
|
bignum n_tmp;
|
|
dword n3_len, n4_len, n3_bitlen, bit_mask;
|
|
|
|
init_bignum(n1, 1, len);
|
|
n4_len = len_bignum(n4, len);
|
|
init_two_dw(n4, n4_len);
|
|
n3_bitlen = bitlen_bignum(n3, n4_len);
|
|
n3_len = (n3_bitlen + 31) / 32;
|
|
bit_mask = (((dword)1) << ((n3_bitlen - 1) % 32)) >> 1;
|
|
n3 += n3_len - 1;
|
|
n3_bitlen--;
|
|
mov_bignum(n1, n2, n4_len);
|
|
while (--n3_bitlen != -1)
|
|
{
|
|
if (bit_mask == 0)
|
|
{
|
|
bit_mask = 0x80000000;
|
|
n3--;
|
|
}
|
|
calc_a_bignum(n_tmp, n1, n1, n4_len);
|
|
if (*n3 & bit_mask)
|
|
calc_a_bignum(n1, n_tmp, n2, n4_len);
|
|
else
|
|
mov_bignum(n1, n_tmp, n4_len);
|
|
bit_mask >>= 1;
|
|
}
|
|
init_bignum(n_tmp, 0, n4_len);
|
|
clear_tmp_vars(len);
|
|
}
|
|
|
|
static void process_predata(const byte* pre, dword pre_len, byte *buf)
|
|
{
|
|
bignum n2, n3;
|
|
const dword a = (pubkey.len - 1) / 8;
|
|
while (a + 1 <= pre_len)
|
|
{
|
|
init_bignum(n2, 0, 64);
|
|
memmove(n2, pre, a + 1);
|
|
calc_a_key(n3, n2, pubkey.key2, pubkey.key1, 64);
|
|
|
|
memmove(buf, n3, a);
|
|
|
|
pre_len -= a + 1;
|
|
pre += a + 1;
|
|
buf += a;
|
|
}
|
|
}
|
|
|
|
static void get_blowfish_key(const byte* s, byte* d)
|
|
{
|
|
static bool public_key_initialized = false;
|
|
if (!public_key_initialized)
|
|
{
|
|
init_pubkey();
|
|
public_key_initialized = true;
|
|
}
|
|
byte key[256];
|
|
process_predata(s, len_predata(), key);
|
|
memcpy(d, key, 56);
|
|
} |