#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(buff + i), reinterpret_cast(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(in + i), reinterpret_cast(out + i)); } } /** * RC5Key */ void RC5Key::Create() { #ifdef RUNTIME uint64_t key = __rdtsc(); key ^= ~key << 32; uint8_t *p = reinterpret_cast(&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(b); size_t offset = (addr + (addr >> 7)) % _countof(salt_); size_t salt = salt_[offset] + 0x73 + (addr >> 4); return static_cast((*b ^ salt) + addr); #else return *b; #endif } void BigNumber::bignum_set_word(Bignum b, BignumInt value) const { #ifdef RUNTIME size_t addr = reinterpret_cast(b); size_t offset = (addr + (addr >> 7)) % _countof(salt_); size_t salt = salt_[offset] + 0x73 + (addr >> 4); *b = static_cast((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(&rand), sizeof(rand)); hash.Input(reinterpret_cast(&data_), sizeof(data_)); const BignumInt *p = reinterpret_cast(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(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(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(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(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(&res), sizeof(res))) return res; return -1; } uint16_t CryptoContainer::GetWord(size_t pos) const { uint16_t res; if (DecryptValue(pos, reinterpret_cast(&res), sizeof(res))) return res; return -1; } uint8_t CryptoContainer::GetByte(size_t pos) const { uint8_t res; if (DecryptValue(pos, reinterpret_cast(&res), sizeof(res))) return res; return -1; } uint64_t CryptoContainer::GetQWord(size_t pos) const { uint64_t res; if (DecryptValue(pos, reinterpret_cast(&res), sizeof(res))) return res; return -1; } bool CryptoContainer::SetDWord(size_t pos, uint32_t value) const { return EncryptValue(pos, reinterpret_cast(&value), sizeof(value)); } bool CryptoContainer::SetWord(size_t pos, uint16_t value) const { return EncryptValue(pos, reinterpret_cast(&value), sizeof(value)); } bool CryptoContainer::SetByte(size_t pos, uint8_t value) const { return EncryptValue(pos, reinterpret_cast(&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(value); } else if (value <= 0x10FFFF) { value -= 0x10000; dest[dest_pos++] = static_cast(0xD800 + (value >> 10)); dest[dest_pos++] = static_cast(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(src[i++]) << 16; if (i == src_len) { padlen = 2; } else { chunk |= static_cast(src[i++]) << 8; if (i == src_len) { padlen = 1; } else { chunk |= static_cast(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(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(&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(&message_block_[56]) = __builtin_bswap32(length_high_); *reinterpret_cast(&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(&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(key); while (len--) { crc = crc32_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8); } return ~crc; }