// CRYPTO LIBRARY FOR EXCHANGING KEYS // USING THE DIFFIE-HELLMAN KEY EXCHANGE PROTOCOL // The diffie-hellman can be used to securely exchange keys // between parties, where a third party eavesdropper given // the values being transmitted cannot determine the key. // Implemented by Lee Griffiths, Jan 2004. // This software is freeware, you may use it to your discretion, // however by doing so you take full responsibility for any damage // it may cause. // Hope you find it useful, even if you just use some of the functions // out of it like the prime number generator and the XtoYmodN function. // It would be great if you could send me emails to: lee.griffiths@first4internet.co.uk // with any suggestions, comments, or questions! // Enjoy. // Adopted to ms-logon for ultravnc by marscha, 2006. #include "dh.h" #include class Except { private: char *info; public: Except(const char *info_ = NULL); virtual ~Except(){ if (info) delete [] info; }; }; Except::Except(const char *info_) { if (info_ != NULL) { info = new char[strlen(info_)+1]; strcpy(info, info_); } } DH::DH() : maxNum(((unsigned __int64) 1) << DH_MAX_BITS) { srand((unsigned) time(NULL)); } DH::DH(unsigned __int64 generator, unsigned __int64 modulus) : gen(generator), mod(modulus), maxNum(((unsigned __int64) 1) << DH_MAX_BITS) { if (gen > maxNum || mod > maxNum) throw Except("Input exceeds maxNum"); if (gen > mod) throw Except("Generator is larger than modulus"); srand((unsigned) time(NULL)); } DH::~DH() { cleanMem(); } unsigned __int64 rng(unsigned __int64 limit) { return ((((unsigned __int64) rand()) * rand() * rand ()) % limit); } //Performs the miller-rabin primality test on a guessed prime n. //trials is the number of attempts to verify this, because the function //is not 100% accurate it may be a composite. However setting the trial //value to around 5 should guarantee success even with very large primes bool DH::millerRabin (unsigned __int64 n, unsigned int trials) { unsigned __int64 a = 0; for (unsigned int i = 0; i < trials; i++) { a = rng(n - 3) + 2;// gets random value in [2..n-1] if (XpowYmodN(a, n - 1, n) != 1) return false; //n composite, return false } return true; // n probably prime } //Generates a large prime number by //choosing a randomly large integer, and ensuring the value is odd //then uses the miller-rabin primality test on it to see if it is prime //if not the value gets increased until it is prime unsigned __int64 DH::generatePrime() { unsigned __int64 prime = 0; do { unsigned __int64 start = rng(maxNum); prime = tryToGeneratePrime(start); } while (!prime); return prime; } unsigned __int64 DH::tryToGeneratePrime(unsigned __int64 prime) { //ensure it is an odd number if ((prime & 1) == 0) prime += 1; unsigned __int64 cnt = 0; while (!millerRabin(prime, 25) && (cnt++ < DH_RANGE) && prime < maxNum) { prime += 2; if ((prime % 3) == 0) prime += 2; } return (cnt >= DH_RANGE || prime >= maxNum) ? 0 : prime; } //Raises X to the power Y in modulus N //the values of X, Y, and N can be massive, and this can be //achieved by first calculating X to the power of 2 then //using power chaining over modulus N unsigned __int64 DH::XpowYmodN(unsigned __int64 x, unsigned __int64 y, unsigned __int64 N) { unsigned __int64 result = 1; const unsigned __int64 oneShift63 = ((unsigned __int64) 1) << 63; for (int i = 0; i < 64; y <<= 1, i++){ result = result * result % N; if (y & oneShift63) result = result * x % N; } return result; } void DH::createKeys() { gen = generatePrime(); mod = generatePrime(); if (gen > mod) { unsigned __int64 swap = gen; gen = mod; mod = swap; } } unsigned __int64 DH::createInterKey() { priv = rng(maxNum); return pub = XpowYmodN(gen,priv,mod); } unsigned __int64 DH::createEncryptionKey(unsigned __int64 interKey) { if (interKey >= maxNum) throw Except("interKey larger than maxNum"); return key = XpowYmodN(interKey,priv,mod); } void DH::cleanMem(DWORD flags) { // marscha (TODO): SecureZeroMemory? gen = 0; mod = 0; priv = 0; pub = 0; if (flags != DH_CLEAN_ALL_MEMORY_EXCEPT_KEY) key = 0; } unsigned __int64 DH::getValue(DWORD flags) { switch (flags) { case DH_MOD: return mod; case DH_GEN: return gen; case DH_PRIV: return priv; case DH_PUB: return pub; case DH_KEY: return key; default: return (unsigned __int64) 0; } } int bits(__int64 number){ for (unsigned int i = 0; i < 64; i++){ number /= 2; if (number < 2) return i; } return 0; } bool int64ToBytes(const unsigned __int64 integer, char* const bytes) { for (int i = 0; i < 8; i++) { bytes[i] = (unsigned char) (integer >> (8 * (7 - i))); } return true; } unsigned __int64 bytesToInt64(const char* const bytes) { unsigned __int64 result = 0; for (int i = 0; i < 8; i++) { result <<= 8; result += (unsigned char) bytes[i]; } return result; } bool vncWc2Mb(char* multibyte, WCHAR* widechar, int length) { multibyte[0] = '\0'; int origlen = wcslen(widechar); if (origlen > length) return false; int newlen = WideCharToMultiByte( CP_ACP, // code page 0, // performance and mapping flags widechar, // address of wide-character string origlen, // number of characters in string multibyte, // address of buffer for new string length, // size of buffer NULL, NULL ); if (newlen >= length) return false; multibyte[newlen]= '\0'; return newlen ? true : false; }