mirror of
https://github.com/Obfuscator-Collections/VMProtect.git
synced 2024-12-26 08:20:19 +03:00
5ec92ee05e
Version 3.x.x
1086 lines
25 KiB
C++
1086 lines
25 KiB
C++
#include "common.h"
|
|
#include "crypto.h"
|
|
|
|
uint32_t rand32()
|
|
{
|
|
uint32_t v1 = rand();
|
|
uint32_t v2 = rand();
|
|
return (v1 << 16) | v2;
|
|
}
|
|
|
|
uint64_t rand64()
|
|
{
|
|
uint64_t v1 = rand32();
|
|
uint64_t v2 = rand32();
|
|
return (v1 << 32) | v2;
|
|
}
|
|
|
|
/**
|
|
* CipherRC5
|
|
*/
|
|
|
|
CipherRC5::CipherRC5(const RC5Key &key)
|
|
{
|
|
#ifndef RUNTIME
|
|
P = key.P;
|
|
Q = key.Q;
|
|
#endif
|
|
|
|
uint32_t i, j, k, u = w / 8, A, B, L[c];
|
|
|
|
for (i = b - 1, L[c - 1] = 0; i != (uint32_t)-1; i--) //-V621
|
|
L[i / u] = (L[i / u] << 8) + key.Value[i];
|
|
|
|
for (S[0] = P, i = 1; i < t; i++)
|
|
S[i] = S[i - 1] + Q;
|
|
for (A = B = i = j = k = 0; k < 3 * t; k++, i = (i + 1) % t, j = (j + 1) % c) /* 3*t > 3*c */
|
|
{
|
|
A = S[i] = _rotl32(S[i] + (A + B), 3);
|
|
B = L[j] = _rotl32(L[j] + (A + B), (A + B));
|
|
}
|
|
}
|
|
|
|
void CipherRC5::Encrypt(const uint32_t *in, uint32_t *out) const
|
|
{
|
|
uint32_t i, A = in[0] + S[0], B = in[1] + S[1];
|
|
for (i = 1; i <= r; i++)
|
|
{
|
|
A = _rotl32(A ^ B, B) + S[2 * i];
|
|
B = _rotl32(B ^ A, A) + S[2 * i + 1];
|
|
}
|
|
out[0] = A;
|
|
out[1] = B;
|
|
}
|
|
|
|
void CipherRC5::Decrypt(const uint32_t *in, uint32_t *out) const
|
|
{
|
|
uint32_t i, B = in[1], A = in[0];
|
|
for (i = r; i > 0; i--) {
|
|
B = _rotr32(B - S[2 * i + 1], A) ^ A;
|
|
A = _rotr32(A - S[2 * i], B) ^ B;
|
|
}
|
|
out[1] = B - S[1];
|
|
out[0] = A - S[0];
|
|
}
|
|
|
|
void CipherRC5::Encrypt(uint8_t *buff, size_t count) const
|
|
{
|
|
for (size_t i = 0; i < count; i += 8) {
|
|
Encrypt(reinterpret_cast<uint32_t *>(buff + i), reinterpret_cast<uint32_t *>(buff + i));
|
|
}
|
|
}
|
|
|
|
void CipherRC5::Decrypt(const uint8_t *in, uint8_t *out, size_t count) const
|
|
{
|
|
for (size_t i = 0; i < count; i += 8) {
|
|
Decrypt(reinterpret_cast<const uint32_t *>(in + i), reinterpret_cast<uint32_t *>(out + i));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* RC5Key
|
|
*/
|
|
|
|
void RC5Key::Create()
|
|
{
|
|
#ifdef RUNTIME
|
|
uint64_t key = __rdtsc();
|
|
key ^= ~key << 32;
|
|
uint8_t *p = reinterpret_cast<uint8_t *>(&key);
|
|
for (size_t i = 0; i < _countof(Value); i++) {
|
|
Value[i] = p[i];
|
|
}
|
|
#else
|
|
for (size_t i = 0; i < _countof(Value); i++) {
|
|
Value[i] = rand();
|
|
}
|
|
P = rand32();
|
|
Q = rand32();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* BigNumber
|
|
*/
|
|
|
|
BigNumber::BigNumber()
|
|
{
|
|
init(0);
|
|
}
|
|
|
|
BigNumber::BigNumber(const uint8_t *data, size_t size, bool inverse_order)
|
|
{
|
|
size_t w, i;
|
|
|
|
w = (size + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES; /* bytes->words */
|
|
init(w);
|
|
|
|
if (inverse_order) {
|
|
if (size)
|
|
memcpy(&data_[1], data, size);
|
|
} else {
|
|
for (i = size; i--;) {
|
|
uint8_t byte = *data++;
|
|
bignum_set_word(data_ + 1 + i / BIGNUM_INT_BYTES, bignum_get_word(data_ + 1 + i / BIGNUM_INT_BYTES) | byte << (8*i % BIGNUM_INT_BITS));
|
|
}
|
|
}
|
|
|
|
while (bignum_get_word(data_ + 0) > 1 && bignum_get_word(data_ + bignum_get_word(data_ + 0)) == 0)
|
|
bignum_set_word(data_ + 0, bignum_get_word(data_ + 0) - 1);
|
|
}
|
|
|
|
BigNumber::BigNumber(const BigNumber &src)
|
|
{
|
|
size_t size = src.data(0);
|
|
init(size);
|
|
for (size_t i = 1; i <= size; i++) {
|
|
bignum_set_word(data_ + i, src.data(i));
|
|
}
|
|
}
|
|
|
|
BigNumber::BigNumber(Bignum data, const BignumInt *salt)
|
|
{
|
|
data_ = data;
|
|
#ifdef RUNTIME
|
|
for (size_t i = 0; i < _countof(salt_); i++) {
|
|
salt_[i] = salt[i];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
BigNumber::~BigNumber()
|
|
{
|
|
delete [] data_;
|
|
}
|
|
|
|
bool BigNumber::operator < (const BigNumber &b) const
|
|
{
|
|
return (bignum_cmp(b) < 0);
|
|
}
|
|
|
|
size_t BigNumber::size() const
|
|
{
|
|
return data(0) * BIGNUM_INT_BYTES;
|
|
}
|
|
|
|
uint8_t BigNumber::operator [] (size_t index) const
|
|
{
|
|
return bignum_byte(data_, index);
|
|
}
|
|
|
|
#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
|
|
#define DIVMOD_WORD(q, r, hi, lo, w) { \
|
|
BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
|
|
q = n / w; \
|
|
r = n % w; \
|
|
}
|
|
|
|
BignumInt BigNumber::bignum_get_word(Bignum b) const
|
|
{
|
|
#ifdef RUNTIME
|
|
size_t addr = reinterpret_cast<size_t>(b);
|
|
size_t offset = (addr + (addr >> 7)) % _countof(salt_);
|
|
size_t salt = salt_[offset] + 0x73 + (addr >> 4);
|
|
return static_cast<BignumInt>((*b ^ salt) + addr);
|
|
#else
|
|
return *b;
|
|
#endif
|
|
}
|
|
|
|
void BigNumber::bignum_set_word(Bignum b, BignumInt value) const
|
|
{
|
|
#ifdef RUNTIME
|
|
size_t addr = reinterpret_cast<size_t>(b);
|
|
size_t offset = (addr + (addr >> 7)) % _countof(salt_);
|
|
size_t salt = salt_[offset] + 0x73 + (addr >> 4);
|
|
*b = static_cast<BignumInt>((value - addr) ^ salt);
|
|
#else
|
|
*b = value;
|
|
#endif
|
|
}
|
|
|
|
void BigNumber::init(size_t length)
|
|
{
|
|
data_ = new BignumInt[length + 1];
|
|
|
|
#ifdef RUNTIME
|
|
{
|
|
uint64_t rand = __rdtsc();
|
|
SHA1 hash;
|
|
hash.Input(reinterpret_cast<const uint8_t *>(&rand), sizeof(rand));
|
|
hash.Input(reinterpret_cast<const uint8_t *>(&data_), sizeof(data_));
|
|
|
|
const BignumInt *p = reinterpret_cast<const BignumInt *>(hash.Result());
|
|
for (size_t i = 0; i < _countof(salt_); i++) {
|
|
salt_[i] = p[i];
|
|
}
|
|
}
|
|
#endif
|
|
|
|
bignum_set_word(data_, (BignumInt)length);
|
|
for (size_t i = 1; i <= length; i++)
|
|
bignum_set_word(data_ + i, 0);
|
|
}
|
|
|
|
void BigNumber::internal_mul(BignumInt *a, BignumInt *b, BignumInt *c, int len) const
|
|
{
|
|
int i, j;
|
|
BignumDblInt t;
|
|
|
|
for (j = 0; j < 2 * len; j++)
|
|
bignum_set_word(c + j, 0);
|
|
|
|
for (i = len - 1; i >= 0; i--) {
|
|
t = 0;
|
|
for (j = len - 1; j >= 0; j--) {
|
|
t += MUL_WORD(bignum_get_word(a + i), (BignumDblInt) bignum_get_word(b + j));
|
|
t += (BignumDblInt) bignum_get_word(c + i + j + 1);
|
|
bignum_set_word(c + i + j + 1, (BignumInt) t);
|
|
t = t >> BIGNUM_INT_BITS;
|
|
}
|
|
bignum_set_word(c + i, (BignumInt) t);
|
|
}
|
|
}
|
|
|
|
void BigNumber::internal_add_shifted(BignumInt *number, unsigned n, int shift) const
|
|
{
|
|
int word = 1 + (shift / BIGNUM_INT_BITS);
|
|
int bshift = shift % BIGNUM_INT_BITS;
|
|
BignumDblInt addend;
|
|
|
|
addend = (BignumDblInt)n << bshift;
|
|
|
|
while (addend) {
|
|
addend += bignum_get_word(number + word);
|
|
bignum_set_word(number + word, (BignumInt) addend & BIGNUM_INT_MASK);
|
|
addend >>= BIGNUM_INT_BITS;
|
|
word++;
|
|
}
|
|
}
|
|
|
|
void BigNumber::internal_mod(BignumInt *a, int alen,
|
|
BignumInt *m, int mlen,
|
|
BignumInt *quot, int qshift) const
|
|
{
|
|
BignumInt m0, m1;
|
|
unsigned int h;
|
|
int i, k;
|
|
|
|
m0 = bignum_get_word(m + 0);
|
|
m1 = (mlen > 1) ? bignum_get_word(m + 1) : 0;
|
|
|
|
for (i = 0; i <= alen - mlen; i++) {
|
|
BignumDblInt t;
|
|
unsigned int q, r, c, ai1;
|
|
|
|
if (i == 0) {
|
|
h = 0;
|
|
} else {
|
|
h = bignum_get_word(a + i - 1);
|
|
bignum_set_word(a + i - 1, 0);
|
|
}
|
|
|
|
if (i == alen - 1)
|
|
ai1 = 0;
|
|
else
|
|
ai1 = bignum_get_word(a + i + 1);
|
|
|
|
/* Find q = h:a[i] / m0 */
|
|
DIVMOD_WORD(q, r, h, bignum_get_word(a + i), m0);
|
|
|
|
/* Refine our estimate of q by looking at h:a[i]:a[i+1] / m0:m1 */
|
|
t = MUL_WORD(m1, q);
|
|
if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
|
|
q--;
|
|
t -= m1;
|
|
r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
|
|
if (r >= (BignumDblInt) m0 &&
|
|
t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
|
|
}
|
|
|
|
/* Subtract q * m from a[i...] */
|
|
c = 0;
|
|
for (k = mlen - 1; k >= 0; k--) {
|
|
t = MUL_WORD(q, bignum_get_word(m + k));
|
|
t += c;
|
|
c = t >> BIGNUM_INT_BITS;
|
|
if ((BignumInt) t > bignum_get_word(a + i + k))
|
|
c++;
|
|
bignum_set_word(a + i + k, bignum_get_word(a + i + k) - (BignumInt) t);
|
|
}
|
|
|
|
/* Add back m in case of borrow */
|
|
if (c != h) {
|
|
t = 0;
|
|
for (k = mlen - 1; k >= 0; k--) {
|
|
t += bignum_get_word(m + k);
|
|
t += bignum_get_word(a + i + k);
|
|
bignum_set_word(a + i + k, (BignumInt) t);
|
|
t = t >> BIGNUM_INT_BITS;
|
|
}
|
|
q--;
|
|
}
|
|
if (quot)
|
|
internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
|
|
}
|
|
}
|
|
|
|
BigNumber BigNumber::modpow(const BigNumber &exp, const BigNumber &mod) const
|
|
{
|
|
BignumInt *a, *b, *n, *m;
|
|
int mshift;
|
|
int i,j,mlen;
|
|
Bignum result;
|
|
|
|
/* Allocate m of size mlen, copy mod to m */
|
|
/* We use big endian internally */
|
|
mlen = mod.data(0);
|
|
#ifdef WIN_DRIVER
|
|
NT_ASSERT(mlen > 0);
|
|
#else
|
|
assert(mlen > 0);
|
|
#endif
|
|
if(mlen <= 0) return BigNumber();
|
|
|
|
m = new BignumInt[mlen];
|
|
for (j = 0; j < mlen; j++)
|
|
bignum_set_word(m + j, mod.data(mlen - j));
|
|
|
|
/* Shift m left to make msb bit set */
|
|
for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
|
|
if ((bignum_get_word(m + 0) << mshift) & BIGNUM_TOP_BIT)
|
|
break;
|
|
if (mshift) {
|
|
for (i = 0; i < mlen - 1; i++)
|
|
m[i] = (bignum_get_word(m + i) << mshift) | (bignum_get_word(m + i + 1) >> (BIGNUM_INT_BITS - mshift));
|
|
bignum_set_word(m + mlen - 1, bignum_get_word(m + mlen - 1) << mshift);
|
|
}
|
|
|
|
/* Allocate n of size mlen, copy base to n */
|
|
int blen = data(0);
|
|
n = new BignumInt[mlen];
|
|
i = mlen - blen;
|
|
for (j = 0; j < i; j++)
|
|
bignum_set_word(n + j, 0);
|
|
for (j = 0; j < blen; j++)
|
|
bignum_set_word(n + i + j, data(blen - j));
|
|
|
|
/* Allocate a and b of size 2*mlen. Set a = 1 */
|
|
a = new BignumInt[2 * mlen];
|
|
b = new BignumInt[2 * mlen];
|
|
for (i = 0; i < 2 * mlen; i++)
|
|
bignum_set_word(a + i, 0);
|
|
bignum_set_word(a + 2 * mlen - 1, 1);
|
|
|
|
/* Skip leading zero bits of exp. */
|
|
i = 0;
|
|
j = BIGNUM_INT_BITS-1;
|
|
int elen = exp.data(0);
|
|
while (i < elen && (exp.data(elen - i) & (1 << j)) == 0) {
|
|
j--;
|
|
if (j < 0) {
|
|
i++;
|
|
j = BIGNUM_INT_BITS-1;
|
|
}
|
|
}
|
|
|
|
/* Main computation */
|
|
while (i < elen) {
|
|
while (j >= 0) {
|
|
internal_mul(a + mlen, a + mlen, b, mlen);
|
|
internal_mod(b, mlen * 2, m, mlen, NULL, 0);
|
|
if ((exp.data(elen - i) & (1 << j)) != 0) {
|
|
internal_mul(b + mlen, n, a, mlen);
|
|
internal_mod(a, mlen * 2, m, mlen, NULL, 0);
|
|
} else {
|
|
BignumInt *t;
|
|
t = a;
|
|
a = b;
|
|
b = t;
|
|
}
|
|
j--;
|
|
}
|
|
i++;
|
|
j = BIGNUM_INT_BITS-1;
|
|
}
|
|
|
|
/* Fixup result in case the modulus was shifted */
|
|
if (mshift) {
|
|
for (i = mlen - 1; i < 2 * mlen - 1; i++)
|
|
a[i] = (bignum_get_word(a + i) << mshift) | (bignum_get_word(a + i + 1) >> (BIGNUM_INT_BITS - mshift));
|
|
bignum_set_word(a + 2 * mlen - 1, bignum_get_word(a + 2 * mlen - 1) << mshift);
|
|
internal_mod(a, mlen * 2, m, mlen, NULL, 0);
|
|
for (i = 2 * mlen - 1; i >= mlen; i--)
|
|
bignum_set_word(a + i, (bignum_get_word(a + i) >> mshift) | (bignum_get_word(a + i - 1) << (BIGNUM_INT_BITS - mshift)));
|
|
}
|
|
|
|
/* Copy result to buffer */
|
|
result = new BignumInt[mlen + 1];
|
|
bignum_set_word(result, (BignumInt)mlen);
|
|
for (i = 0; i < mlen; i++)
|
|
bignum_set_word(result + mlen - i, bignum_get_word(a + i + mlen));
|
|
while (bignum_get_word(result + 0) > 1 && bignum_get_word(result + bignum_get_word(result + 0)) == 0)
|
|
bignum_set_word(result + 0, bignum_get_word(result + 0) - 1);
|
|
|
|
/* Free temporary arrays */
|
|
delete [] a;
|
|
delete [] b;
|
|
delete [] m;
|
|
delete [] n;
|
|
|
|
return BigNumber(result,
|
|
#ifdef RUNTIME
|
|
salt_
|
|
#else
|
|
NULL
|
|
#endif
|
|
);
|
|
}
|
|
|
|
CryptoContainer *BigNumber::modpow(const CryptoContainer &source, size_t exp_offset, size_t exp_size, size_t mod_offset, size_t mod_size) const
|
|
{
|
|
BignumInt *a, *b, *n, *m, *e, *mem, *next;
|
|
int mshift;
|
|
int i, j, mlen, elen, blen;
|
|
Bignum result;
|
|
size_t k;
|
|
size_t arrays[5];
|
|
|
|
mlen = (int)(mod_size + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES;
|
|
elen = (int)(exp_size + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES;
|
|
|
|
#ifdef WIN_DRIVER
|
|
NT_ASSERT(mlen > 0);
|
|
#else
|
|
assert(mlen > 0);
|
|
#endif
|
|
if (mlen <= 0 || data(0) > mlen) return NULL;
|
|
|
|
for (k = 0; k < _countof(arrays); k++) {
|
|
arrays[k] = k;
|
|
}
|
|
for (k = 0; k < _countof(arrays); k++) {
|
|
uint64_t rand = __rdtsc();
|
|
size_t r = static_cast<size_t>(rand ^ (rand >> 32)) % _countof(arrays);
|
|
size_t t = arrays[k];
|
|
arrays[k] = arrays[r];
|
|
arrays[r] = t;
|
|
}
|
|
|
|
// Allocate memory for temporary arrays
|
|
mem = new BignumInt[mlen + mlen + mlen * 2 + mlen * 2 + elen];
|
|
next = mem;
|
|
for (k = 0; k < _countof(arrays); k++) {
|
|
switch (arrays[k]) {
|
|
case 0:
|
|
/* Allocate m of size mlen, copy mod to m */
|
|
m = next;
|
|
next = m + mlen;
|
|
|
|
for (j = 0; j < mlen; j++) {
|
|
BignumInt value = 0;
|
|
for (i = 0; i < BIGNUM_INT_BYTES; i++) {
|
|
value = (value << 8) | source.GetByte(mod_offset++);
|
|
}
|
|
bignum_set_word(m + j, value);
|
|
}
|
|
|
|
/* Shift m left to make msb bit set */
|
|
for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
|
|
if ((bignum_get_word(m + 0) << mshift) & BIGNUM_TOP_BIT)
|
|
break;
|
|
if (mshift) {
|
|
for (i = 0; i < mlen - 1; i++)
|
|
m[i] = (bignum_get_word(m + i) << mshift) | (bignum_get_word(m + i + 1) >> (BIGNUM_INT_BITS - mshift));
|
|
bignum_set_word(m + mlen - 1, bignum_get_word(m + mlen - 1) << mshift);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
/* Allocate e of size elen, copy exp to e */
|
|
e = next;
|
|
next = next + elen;
|
|
|
|
for (j = 0; j < elen; j++) {
|
|
BignumInt value = 0;
|
|
for (i = 0; i < BIGNUM_INT_BYTES; i++) {
|
|
value = (value << 8) | source.GetByte(exp_offset++);
|
|
}
|
|
bignum_set_word(e + j, value);
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
/* Allocate n of size mlen, copy base to n */
|
|
n = next;
|
|
next = next + mlen;
|
|
|
|
blen = data(0);
|
|
i = mlen - blen;
|
|
for (j = 0; j < i; j++)
|
|
bignum_set_word(n + j, 0);
|
|
for (j = 0; j < blen; j++)
|
|
bignum_set_word(n + i + j, data(blen - j));
|
|
break;
|
|
|
|
case 3:
|
|
/* Allocate a of size 2*mlen. Set a = 1 */
|
|
a = next;
|
|
next = next + 2 * mlen;
|
|
|
|
for (i = 0; i < 2 * mlen; i++)
|
|
bignum_set_word(a + i, 0);
|
|
bignum_set_word(a + 2 * mlen - 1, 1);
|
|
break;
|
|
|
|
case 4:
|
|
/* Allocate b of size 2*mlen */
|
|
b = next;
|
|
next = next + 2 * mlen;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Skip leading zero bits of exp. */
|
|
i = 0;
|
|
j = BIGNUM_INT_BITS - 1;
|
|
while (i < elen && (bignum_get_word(e + i) & (1 << j)) == 0) {
|
|
j--;
|
|
if (j < 0) {
|
|
i++;
|
|
j = BIGNUM_INT_BITS - 1;
|
|
}
|
|
}
|
|
|
|
/* Main computation */
|
|
while (i < elen) {
|
|
while (j >= 0) {
|
|
internal_mul(a + mlen, a + mlen, b, mlen);
|
|
internal_mod(b, mlen * 2, m, mlen, NULL, 0);
|
|
if ((bignum_get_word(e + i) & (1 << j)) != 0) {
|
|
internal_mul(b + mlen, n, a, mlen);
|
|
internal_mod(a, mlen * 2, m, mlen, NULL, 0);
|
|
}
|
|
else {
|
|
BignumInt *t;
|
|
t = a;
|
|
a = b;
|
|
b = t;
|
|
}
|
|
j--;
|
|
}
|
|
i++;
|
|
j = BIGNUM_INT_BITS - 1;
|
|
}
|
|
|
|
/* Fixup result in case the modulus was shifted */
|
|
if (mshift) {
|
|
for (i = mlen - 1; i < 2 * mlen - 1; i++)
|
|
a[i] = (bignum_get_word(a + i) << mshift) | (bignum_get_word(a + i + 1) >> (BIGNUM_INT_BITS - mshift));
|
|
bignum_set_word(a + 2 * mlen - 1, bignum_get_word(a + 2 * mlen - 1) << mshift);
|
|
internal_mod(a, mlen * 2, m, mlen, NULL, 0);
|
|
for (i = 2 * mlen - 1; i >= mlen; i--)
|
|
bignum_set_word(a + i, (bignum_get_word(a + i) >> mshift) | (bignum_get_word(a + i - 1) << (BIGNUM_INT_BITS - mshift)));
|
|
}
|
|
|
|
/* Copy result to buffer */
|
|
result = b;
|
|
for (i = 0; i < mlen; i++)
|
|
bignum_set_word(result + mlen - i, bignum_get_word(a + i + mlen));
|
|
while (mlen > 1 && bignum_get_word(result + mlen) == 0)
|
|
mlen--;
|
|
bignum_set_word(result, (BignumInt)mlen);
|
|
|
|
size_t size = bignum_get_word(result + 0) * BIGNUM_INT_BYTES;
|
|
RC5Key key;
|
|
key.Create();
|
|
CryptoContainer *res = new CryptoContainer(size, key);
|
|
for (k = 0; k < size; k++) {
|
|
// BigNumber has inverse order of bytes
|
|
res->SetByte(k, bignum_byte(result, size - 1 - k));
|
|
}
|
|
|
|
/* Free temporary arrays */
|
|
delete[] mem;
|
|
|
|
return res;
|
|
}
|
|
|
|
NOINLINE uint8_t BigNumber::bignum_byte(Bignum bn, size_t i) const
|
|
{
|
|
if (i >= BIGNUM_INT_BYTES * (size_t)bignum_get_word(bn + 0))
|
|
return 0; /* beyond the end */
|
|
else
|
|
return (bignum_get_word(bn + i / BIGNUM_INT_BYTES + 1) >>
|
|
((i % BIGNUM_INT_BYTES)*8)) & 0xFF;
|
|
}
|
|
|
|
int BigNumber::bignum_cmp(const BigNumber &b) const
|
|
{
|
|
int amax = data(0), bmax = b.data(0);
|
|
int i = (amax > bmax ? amax : bmax);
|
|
while (i) {
|
|
BignumInt aval = (i > amax ? 0 : data(i));
|
|
BignumInt bval = (i > bmax ? 0 : b.data(i));
|
|
if (aval < bval)
|
|
return -1;
|
|
if (aval > bval)
|
|
return +1;
|
|
i--;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* CryptoContainer
|
|
*/
|
|
|
|
CryptoContainer::CryptoContainer(size_t size, const RC5Key &key)
|
|
: is_own_data_(true), size_(size)
|
|
{
|
|
// align size
|
|
size = (size + RC5_BLOCK_SIZE - 1) / RC5_BLOCK_SIZE * RC5_BLOCK_SIZE;
|
|
data_ = new uint32_t[size / sizeof(uint32_t)];
|
|
cipher_ = new CipherRC5(key);
|
|
}
|
|
|
|
CryptoContainer::CryptoContainer(uint8_t *data, size_t size, const RC5Key &key)
|
|
: is_own_data_(false), data_(reinterpret_cast<uint32_t *>(data)), size_(size)
|
|
{
|
|
cipher_ = new CipherRC5(key);
|
|
}
|
|
|
|
CryptoContainer::CryptoContainer(const BigNumber &bn)
|
|
: is_own_data_(true)
|
|
{
|
|
RC5Key key;
|
|
key.Create();
|
|
cipher_ = new CipherRC5(key);
|
|
|
|
// align size
|
|
size_t len = bn.size();
|
|
size_ = (len + RC5_BLOCK_SIZE - 1) / RC5_BLOCK_SIZE * RC5_BLOCK_SIZE;
|
|
data_ = new uint32_t[size_ / sizeof(uint32_t)];
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
// BigNumber has inverse order of bytes
|
|
SetByte(i, bn[len - 1 - i]);
|
|
}
|
|
}
|
|
|
|
CryptoContainer::~CryptoContainer()
|
|
{
|
|
delete cipher_;
|
|
if (is_own_data_)
|
|
delete [] data_;
|
|
}
|
|
|
|
bool CryptoContainer::EncryptValue(size_t pos, uint8_t *value, size_t value_size) const
|
|
{
|
|
if (pos > size_ - value_size)
|
|
return false;
|
|
|
|
uint32_t buff[4];
|
|
size_t block_pos = pos / RC5_BLOCK_SIZE;
|
|
pos = pos % RC5_BLOCK_SIZE;
|
|
size_t block_count = (pos <= RC5_BLOCK_SIZE - value_size) ? 1 : 2;
|
|
for (size_t i = 0; i < block_count; i++) {
|
|
cipher_->Decrypt(&data_[block_pos * 2 + i * 2], &buff[i * 2]);
|
|
}
|
|
uint8_t *p = reinterpret_cast<uint8_t *>(buff);
|
|
for (size_t i = 0; i < value_size; i++) {
|
|
p[pos + i] = value[i];
|
|
}
|
|
for (size_t i = 0; i < block_count; i++) {
|
|
cipher_->Encrypt(&buff[i * 2], &data_[block_pos * 2 + i * 2]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CryptoContainer::DecryptValue(size_t pos, uint8_t *value, size_t value_size) const
|
|
{
|
|
if (pos > size_ - value_size)
|
|
return false;
|
|
|
|
uint32_t buff[4];
|
|
size_t block_pos = pos / RC5_BLOCK_SIZE;
|
|
pos = pos % RC5_BLOCK_SIZE;
|
|
size_t block_count = (pos <= RC5_BLOCK_SIZE - value_size) ? 1 : 2;
|
|
for (size_t i = 0; i < block_count; i++) {
|
|
cipher_->Decrypt(&data_[block_pos * 2 + i * 2], &buff[i * 2]);
|
|
}
|
|
uint8_t *p = reinterpret_cast<uint8_t *>(buff);
|
|
for (size_t i = 0; i < value_size; i++) {
|
|
value[i] = p[pos + i];
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uint32_t CryptoContainer::GetDWord(size_t pos) const
|
|
{
|
|
uint32_t res;
|
|
if (DecryptValue(pos, reinterpret_cast<uint8_t *>(&res), sizeof(res)))
|
|
return res;
|
|
return -1;
|
|
}
|
|
|
|
uint16_t CryptoContainer::GetWord(size_t pos) const
|
|
{
|
|
uint16_t res;
|
|
if (DecryptValue(pos, reinterpret_cast<uint8_t *>(&res), sizeof(res)))
|
|
return res;
|
|
return -1;
|
|
}
|
|
|
|
uint8_t CryptoContainer::GetByte(size_t pos) const
|
|
{
|
|
uint8_t res;
|
|
if (DecryptValue(pos, reinterpret_cast<uint8_t *>(&res), sizeof(res)))
|
|
return res;
|
|
return -1;
|
|
}
|
|
|
|
uint64_t CryptoContainer::GetQWord(size_t pos) const
|
|
{
|
|
uint64_t res;
|
|
if (DecryptValue(pos, reinterpret_cast<uint8_t *>(&res), sizeof(res)))
|
|
return res;
|
|
return -1;
|
|
}
|
|
|
|
bool CryptoContainer::SetDWord(size_t pos, uint32_t value) const
|
|
{
|
|
return EncryptValue(pos, reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
|
}
|
|
|
|
bool CryptoContainer::SetWord(size_t pos, uint16_t value) const
|
|
{
|
|
return EncryptValue(pos, reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
|
}
|
|
|
|
bool CryptoContainer::SetByte(size_t pos, uint8_t value) const
|
|
{
|
|
return EncryptValue(pos, reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
|
}
|
|
|
|
static const uint8_t utf8_limits[5] = {0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
|
|
|
|
void CryptoContainer::UTF8ToUnicode(size_t offset, size_t len, VMP_WCHAR *dest, size_t dest_size) const
|
|
{
|
|
if (!dest || dest_size == 0) return; // nothing to do
|
|
|
|
size_t pos = 0;
|
|
size_t dest_pos = 0;
|
|
while (pos < len && dest_pos < dest_size) {
|
|
uint8_t b = GetByte(offset + pos++);
|
|
|
|
if (b < 0x80) {
|
|
dest[dest_pos++] = b;
|
|
continue;
|
|
}
|
|
|
|
size_t val_len;
|
|
for (val_len = 0; val_len < _countof(utf8_limits); val_len++) {
|
|
if (b < utf8_limits[val_len])
|
|
break;
|
|
}
|
|
|
|
if (val_len == 0)
|
|
continue;
|
|
|
|
uint32_t value = b - utf8_limits[val_len - 1];
|
|
for (size_t i = 0; i < val_len; i++) {
|
|
if (pos == len)
|
|
break;
|
|
b = GetByte(offset + pos++);
|
|
if (b < 0x80 || b >= 0xC0)
|
|
break;
|
|
value <<= 6;
|
|
value |= (b - 0x80);
|
|
}
|
|
|
|
if (value < 0x10000) {
|
|
dest[dest_pos++] = static_cast<uint16_t>(value);
|
|
} else if (value <= 0x10FFFF) {
|
|
value -= 0x10000;
|
|
dest[dest_pos++] = static_cast<uint16_t>(0xD800 + (value >> 10));
|
|
dest[dest_pos++] = static_cast<uint16_t>(0xDC00 + (value & 0x3FF));
|
|
}
|
|
}
|
|
|
|
if (dest_pos < dest_size - 1)
|
|
dest[dest_pos] = 0;
|
|
else
|
|
dest[dest_pos - 1] = 0;
|
|
}
|
|
|
|
/**
|
|
* Base64
|
|
*/
|
|
|
|
bool Base64Encode(const uint8_t *src, size_t src_len, char *dst, size_t &dst_len)
|
|
{
|
|
if (!src || !dst)
|
|
return false;
|
|
|
|
const char alphabet[] = {
|
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
|
|
|
|
const char padchar = '=';
|
|
size_t padlen = 0;
|
|
|
|
char *out = dst;
|
|
char *dst_end = dst + dst_len;
|
|
size_t i = 0;
|
|
while (i < src_len) {
|
|
uint32_t chunk = 0;
|
|
chunk |= static_cast<uint32_t>(src[i++]) << 16;
|
|
if (i == src_len) {
|
|
padlen = 2;
|
|
} else {
|
|
chunk |= static_cast<uint32_t>(src[i++]) << 8;
|
|
if (i == src_len) {
|
|
padlen = 1;
|
|
} else {
|
|
chunk |= static_cast<uint32_t>(src[i++]);
|
|
}
|
|
}
|
|
|
|
size_t j = (chunk & 0x00fc0000) >> 18;
|
|
size_t k = (chunk & 0x0003f000) >> 12;
|
|
size_t l = (chunk & 0x00000fc0) >> 6;
|
|
size_t m = (chunk & 0x0000003f);
|
|
|
|
if (out + 4 > dst_end)
|
|
return false;
|
|
|
|
*out++ = alphabet[j];
|
|
*out++ = alphabet[k];
|
|
if (padlen > 1) *out++ = padchar;
|
|
else *out++ = alphabet[l];
|
|
if (padlen > 0) *out++ = padchar;
|
|
else *out++ = alphabet[m];
|
|
}
|
|
|
|
dst_len = out - dst;
|
|
return true;
|
|
}
|
|
|
|
size_t Base64EncodeGetRequiredLength(size_t src_len)
|
|
{
|
|
return src_len * 4 / 3 + 3;
|
|
}
|
|
|
|
bool Base64Decode(const char *src, size_t src_len, uint8_t *dst, size_t &dst_len)
|
|
{
|
|
if (!src || !dst)
|
|
return false;
|
|
|
|
size_t buf = 0;
|
|
size_t nbits = 0;
|
|
size_t offset = 0;
|
|
for (size_t i = 0; i < src_len; ++i) {
|
|
char c = src[i];
|
|
int d;
|
|
|
|
if (c >= 'A' && c <= 'Z') {
|
|
d = c - 'A';
|
|
} else if (c >= 'a' && c <= 'z') {
|
|
d = c - 'a' + 26;
|
|
} else if (c >= '0' && c <= '9') {
|
|
d = c - '0' + 52;
|
|
} else if (c == '+') {
|
|
d = 62;
|
|
} else if (c == '/') {
|
|
d = 63;
|
|
} else {
|
|
d = -1;
|
|
}
|
|
|
|
if (d != -1) {
|
|
buf = (buf << 6) | d;
|
|
nbits += 6;
|
|
if (nbits >= 8) {
|
|
nbits -= 8;
|
|
if (offset == dst_len)
|
|
return false;
|
|
dst[offset++] = static_cast<uint8_t>(buf >> nbits);
|
|
buf &= size_t((1 << nbits) - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
dst_len = offset;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* SHA1
|
|
*/
|
|
|
|
SHA1::SHA1()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void SHA1::Reset()
|
|
{
|
|
length_low_ = 0;
|
|
length_high_ = 0;
|
|
message_block_index_ = 0;
|
|
hash_[0] = 0x67452301;
|
|
hash_[1] = 0xEFCDAB89;
|
|
hash_[2] = 0x98BADCFE;
|
|
hash_[3] = 0x10325476;
|
|
hash_[4] = 0xC3D2E1F0;
|
|
computed_ = false;
|
|
}
|
|
|
|
void SHA1::Input(const uint8_t *data, size_t size)
|
|
{
|
|
if (computed_)
|
|
return;
|
|
|
|
for (size_t i = 0; i < size; i++) {
|
|
message_block_[message_block_index_++] = data[i];
|
|
length_low_ += 8;
|
|
if (!length_low_) {
|
|
// value out of DWORD
|
|
length_high_++;
|
|
}
|
|
if (message_block_index_ == 64)
|
|
ProcessMessageBlock();
|
|
}
|
|
}
|
|
|
|
void SHA1::Input(const CryptoContainer &data, size_t offset, size_t size)
|
|
{
|
|
if (computed_)
|
|
return;
|
|
|
|
for (size_t i = 0; i < size; i++) {
|
|
message_block_[message_block_index_++] = data.GetByte(offset + i);
|
|
length_low_ += 8;
|
|
if (!length_low_) {
|
|
// value out of DWORD
|
|
length_high_++;
|
|
}
|
|
if (message_block_index_ == 64)
|
|
ProcessMessageBlock();
|
|
}
|
|
}
|
|
|
|
void SHA1::ProcessMessageBlock()
|
|
{
|
|
size_t t;
|
|
uint32_t temp, W[80], A, B, C, D, E;
|
|
|
|
for (t = 0; t < 16; t++) {
|
|
W[t] = __builtin_bswap32(*reinterpret_cast<uint32_t *>(&message_block_[t * 4]));
|
|
}
|
|
|
|
for (t = 16; t < 80; t++) {
|
|
W[t] = _rotl32(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
|
|
}
|
|
|
|
A = hash_[0];
|
|
B = hash_[1];
|
|
C = hash_[2];
|
|
D = hash_[3];
|
|
E = hash_[4];
|
|
|
|
for (t = 0; t < 20; t++) {
|
|
temp = _rotl32(A, 5) + ((B & C) | ((~B) & D)) + E + W[t] + 0x5A827999;
|
|
E = D;
|
|
D = C;
|
|
C = _rotl32(B, 30);
|
|
B = A;
|
|
A = temp;
|
|
}
|
|
|
|
for(t = 20; t < 40; t++) {
|
|
temp = _rotl32(A, 5) + (B ^ C ^ D) + E + W[t] + 0x6ED9EBA1;
|
|
E = D;
|
|
D = C;
|
|
C = _rotl32(B, 30);
|
|
B = A;
|
|
A = temp;
|
|
}
|
|
|
|
for (t = 40; t < 60; t++) {
|
|
temp = _rotl32(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[t] + 0x8F1BBCDC;
|
|
E = D;
|
|
D = C;
|
|
C = _rotl32(B, 30);
|
|
B = A;
|
|
A = temp;
|
|
}
|
|
|
|
for(t = 60; t < 80; t++) {
|
|
temp = _rotl32(A, 5) + (B ^ C ^ D) + E + W[t] + 0xCA62C1D6;
|
|
E = D;
|
|
D = C;
|
|
C = _rotl32(B, 30);
|
|
B = A;
|
|
A = temp;
|
|
}
|
|
|
|
hash_[0] += A;
|
|
hash_[1] += B;
|
|
hash_[2] += C;
|
|
hash_[3] += D;
|
|
hash_[4] += E;
|
|
|
|
message_block_index_ = 0;
|
|
}
|
|
|
|
void SHA1::PadMessage()
|
|
{
|
|
message_block_[message_block_index_++] = 0x80;
|
|
if (message_block_index_ > 56) {
|
|
for (size_t i = message_block_index_; i < _countof(message_block_); i++) {
|
|
message_block_[i] = 0;
|
|
}
|
|
ProcessMessageBlock();
|
|
}
|
|
for (size_t i = message_block_index_; i < 56; i++) {
|
|
message_block_[i] = 0;
|
|
}
|
|
|
|
*reinterpret_cast<uint32_t *>(&message_block_[56]) = __builtin_bswap32(length_high_);
|
|
*reinterpret_cast<uint32_t *>(&message_block_[60]) = __builtin_bswap32(length_low_);
|
|
|
|
ProcessMessageBlock();
|
|
}
|
|
|
|
const uint8_t * SHA1::Result()
|
|
{
|
|
if (!computed_) {
|
|
PadMessage();
|
|
computed_ = true;
|
|
}
|
|
|
|
for (size_t i = 0; i < _countof(hash_); i++) {
|
|
digest_[i] = __builtin_bswap32(hash_[i]);
|
|
}
|
|
return reinterpret_cast<const uint8_t *>(&digest_[0]);
|
|
}
|
|
|
|
/**
|
|
* CRC32
|
|
*/
|
|
|
|
#ifdef RUNTIME
|
|
NOINLINE EXPORT_API uint32_t WINAPI CalcCRC(const void *key, size_t len)
|
|
#else
|
|
uint32_t CalcCRC(const void * key, size_t len)
|
|
#endif
|
|
{
|
|
uint32_t crc = 0;
|
|
const uint8_t *p = static_cast<const uint8_t *>(key);
|
|
while (len--) {
|
|
crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
|
|
}
|
|
return ~crc;
|
|
} |