269 lines
5.5 KiB
C
269 lines
5.5 KiB
C
#define LOG_MODULE "crypto"
|
|
|
|
#include "util/crypto.h"
|
|
#include "util/log.h"
|
|
#include "util/mem.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static const char vista_prov[] =
|
|
"Microsoft Enhanced RSA and AES Cryptographic Provider";
|
|
static const char winxp_prov[] =
|
|
"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)";
|
|
|
|
static int init_count;
|
|
static HCRYPTPROV prov;
|
|
|
|
void crypto_init(void)
|
|
{
|
|
const char *prov_name;
|
|
OSVERSIONINFOEX osix;
|
|
|
|
if (init_count++ != 0) {
|
|
return;
|
|
}
|
|
|
|
log_misc("Initializing win32 crypto wrappers");
|
|
|
|
memset(&osix, 0, sizeof(osix));
|
|
osix.dwOSVersionInfoSize = sizeof(osix);
|
|
GetVersionEx((void *) &osix);
|
|
|
|
if (osix.dwMajorVersion < 6) {
|
|
prov_name = winxp_prov;
|
|
} else {
|
|
prov_name = vista_prov;
|
|
}
|
|
|
|
if (!CryptAcquireContext(
|
|
&prov, NULL, prov_name, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
|
|
log_fatal(
|
|
"CryptAcquireContext failed: %08x", (unsigned int) GetLastError());
|
|
}
|
|
}
|
|
|
|
void crypto_gen_random(void *bytes, size_t nbytes)
|
|
{
|
|
CryptGenRandom(prov, nbytes, bytes);
|
|
}
|
|
|
|
void crypto_fini(void)
|
|
{
|
|
if (--init_count != 0) {
|
|
return;
|
|
}
|
|
|
|
log_misc("Shutting down win32 crypto wrappers");
|
|
|
|
if (!CryptReleaseContext(prov, 0)) {
|
|
log_fatal(
|
|
"CryptReleaseContext failed: %08x", (unsigned int) GetLastError());
|
|
}
|
|
}
|
|
|
|
void md5_compute(
|
|
const void *in_bytes,
|
|
size_t in_nbytes,
|
|
uint8_t *out_bytes,
|
|
size_t out_nbytes)
|
|
{
|
|
struct md5 md5;
|
|
|
|
md5_init(&md5);
|
|
md5_append(&md5, in_bytes, in_nbytes);
|
|
md5_fini(&md5, out_bytes, out_nbytes);
|
|
}
|
|
|
|
void md5_init(struct md5 *md5)
|
|
{
|
|
if (!CryptCreateHash(prov, CALG_MD5, 0, 0, &md5->hash)) {
|
|
log_fatal(
|
|
"CryptCreateHash(CALG_MD5) failed: %08x",
|
|
(unsigned int) GetLastError());
|
|
}
|
|
}
|
|
|
|
void md5_append(struct md5 *md5, const void *bytes, size_t nbytes)
|
|
{
|
|
if (!CryptHashData(md5->hash, bytes, nbytes, 0)) {
|
|
log_fatal("CryptHashData failed: %08x", (unsigned int) GetLastError());
|
|
}
|
|
}
|
|
|
|
void md5_fini(struct md5 *md5, uint8_t *output, size_t nbytes)
|
|
{
|
|
DWORD tmp;
|
|
|
|
log_assert(output != NULL && nbytes == 16);
|
|
|
|
tmp = nbytes;
|
|
|
|
if (output != NULL) {
|
|
if (!CryptGetHashParam(md5->hash, HP_HASHVAL, output, &tmp, 0)) {
|
|
log_fatal(
|
|
"Error getting MD5 result: %08x",
|
|
(unsigned int) GetLastError());
|
|
}
|
|
}
|
|
|
|
if (!CryptDestroyHash(md5->hash)) {
|
|
log_fatal(
|
|
"CryptDestroyHash failed: %08x", (unsigned int) GetLastError());
|
|
}
|
|
}
|
|
|
|
#define SWAP(x, y, tmp) \
|
|
tmp = x; \
|
|
x = y; \
|
|
y = tmp
|
|
|
|
void arc4_init(struct arc4 *arc4, const uint8_t *key, size_t key_nbytes)
|
|
{
|
|
size_t i;
|
|
uint8_t j;
|
|
uint8_t tmp;
|
|
|
|
arc4->i = 0;
|
|
arc4->j = 0;
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
arc4->S[i] = (uint8_t) i;
|
|
}
|
|
|
|
j = 0;
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
j = j + arc4->S[i] + key[i % key_nbytes];
|
|
SWAP(arc4->S[i], arc4->S[j], tmp);
|
|
}
|
|
}
|
|
|
|
void arc4_apply(struct arc4 *arc4, uint8_t *bytes, size_t nbytes)
|
|
{
|
|
size_t i;
|
|
uint8_t tmp;
|
|
|
|
for (i = 0; i < nbytes; i++) {
|
|
arc4->i += 1;
|
|
arc4->j += arc4->S[arc4->i];
|
|
|
|
SWAP(arc4->S[arc4->i], arc4->S[arc4->j], tmp);
|
|
|
|
bytes[i] ^= arc4->S[(uint8_t)(arc4->S[arc4->i] + arc4->S[arc4->j])];
|
|
}
|
|
}
|
|
|
|
static uint32_t blowfish_F(struct blowfish *blowfish, uint32_t x)
|
|
{
|
|
unsigned short a, b, c, d;
|
|
uint32_t y;
|
|
|
|
d = x & 0x00FF;
|
|
x >>= 8;
|
|
c = x & 0x00FF;
|
|
x >>= 8;
|
|
b = x & 0x00FF;
|
|
x >>= 8;
|
|
a = x & 0x00FF;
|
|
|
|
y = blowfish->S[0][a] + blowfish->S[1][b];
|
|
y = y ^ blowfish->S[2][c];
|
|
y = y + blowfish->S[3][d];
|
|
return y;
|
|
}
|
|
|
|
void blowfish_init(
|
|
struct blowfish *blowfish, const uint8_t *key, size_t key_length)
|
|
{
|
|
int i, j, k;
|
|
uint32_t data, datal, datar;
|
|
|
|
j = 0;
|
|
for (i = 0; i < 16 + 2; ++i) {
|
|
data = 0x00000000;
|
|
|
|
for (k = 0; k < 4; ++k) {
|
|
data = (data << 8) | key[j];
|
|
j = j + 1;
|
|
if (j >= key_length)
|
|
j = 0;
|
|
}
|
|
|
|
blowfish->P[i] = blowfish->P[i] ^ data;
|
|
}
|
|
|
|
datal = 0x00000000;
|
|
datar = 0x00000000;
|
|
|
|
for (i = 0; i < 16 + 2; i += 2) {
|
|
blowfish_encrypt(blowfish, &datal, &datar);
|
|
blowfish->P[i] = datal;
|
|
blowfish->P[i + 1] = datar;
|
|
}
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
for (j = 0; j < 256; j += 2) {
|
|
blowfish_encrypt(blowfish, &datal, &datar);
|
|
blowfish->S[i][j] = datal;
|
|
blowfish->S[i][j + 1] = datar;
|
|
}
|
|
}
|
|
}
|
|
|
|
void blowfish_encrypt(struct blowfish *blowfish, uint32_t *xl, uint32_t *xr)
|
|
{
|
|
uint32_t Xl;
|
|
uint32_t Xr;
|
|
uint32_t temp;
|
|
short i;
|
|
|
|
Xl = *xl;
|
|
Xr = *xr;
|
|
|
|
for (i = 0; i < 16; ++i) {
|
|
Xl = Xl ^ blowfish->P[i];
|
|
Xr = blowfish_F(blowfish, Xl) ^ Xr;
|
|
temp = Xl;
|
|
Xl = Xr;
|
|
Xr = temp;
|
|
}
|
|
|
|
temp = Xl;
|
|
Xl = Xr;
|
|
Xr = temp;
|
|
Xr = Xr ^ blowfish->P[16];
|
|
Xl = Xl ^ blowfish->P[16 + 1];
|
|
*xl = Xl;
|
|
*xr = Xr;
|
|
}
|
|
|
|
void blowfish_decrypt(struct blowfish *blowfish, uint32_t *xl, uint32_t *xr)
|
|
{
|
|
uint32_t Xl;
|
|
uint32_t Xr;
|
|
uint32_t temp;
|
|
short i;
|
|
|
|
Xl = *xl;
|
|
Xr = *xr;
|
|
|
|
for (i = 16 + 1; i > 1; --i) {
|
|
Xl = Xl ^ blowfish->P[i];
|
|
Xr = blowfish_F(blowfish, Xl) ^ Xr;
|
|
/* Exchange Xl and Xr */
|
|
temp = Xl;
|
|
Xl = Xr;
|
|
Xr = temp;
|
|
}
|
|
|
|
/* Exchange Xl and Xr */
|
|
temp = Xl;
|
|
Xl = Xr;
|
|
Xr = temp;
|
|
Xr = Xr ^ blowfish->P[1];
|
|
Xl = Xl ^ blowfish->P[0];
|
|
*xl = Xl;
|
|
*xr = Xr;
|
|
}
|