#define LOG_MODULE "crypto" #include "util/crypto.h" #include "util/log.h" #include "util/mem.h" #include #include 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; }