Re: How good an encryption algorithm is this?
From: Bonj (benjtaylor)
Date: 11/23/04
- Next message: Craig: "filter by file properties"
- Previous message: BobT: "Marshalling WIN32_FIND_DATA"
- In reply to: Bonj: "How good an encryption algorithm is this?"
- Next in thread: Roy Fine: "Re: How good an encryption algorithm is this?"
- Messages sorted by: [ date ] [ thread ]
Date: Tue, 23 Nov 2004 22:39:23 -0000
Just out of interest folks, this is an almost exact description of the
precise issue I'm having:
http://groups.google.com/groups?hl=en&lr=&threadm=uPqaHHhQCHA.2780%40tkmsftngp09&rnum=3&prev=/groups%3Fq%3Dpassword%2Bregistry%2B%2522hide%2Bthe%2Bkey%2522%26hl%3Den%26lr%3D%26sa%3DN%26tab%3Dwg
"Bonj" <benjtaylor at hotpop d0t com> wrote in message
news:OuHf3lM0EHA.2716@TK2MSFTNGP14.phx.gbl...
>I was in need of an encryption algorithm to the following requirements:
> 1) Must be capable of encrypting strings to a byte array, and decyrpting
> back again to the same string
> 2) Must have the same algorithm work with strings that may or may not be
> unicode
> 3) Number of bytes back must either be <= number of _TCHARs in *
> sizeof(_TCHAR), or the relation between output size and input size can be
> calculated simply. Has to take into account the null terminator on the end
> of the string.
> 4) Encryption algorithm must also return the exact number of bytes of the
> encrypted data
> I was struggling to get the CryptoAPI to work, with CALG_RC4 it didn't
> encrypt at all, and with CALG_RC2 it didn't decrypt at all (both claimed
> to have succeeded, but with the former, the encrypted string was exactly
> the same as the input, and with the latter, the decrypted string was
> exactly the same as the encrypted string) - and I thought I'd done
> everything right (at the bottom if you reckon you can spot where I
> havent...)
>
> So I decided to invent my own algorithm, and I just wanted anybody's
> opinion on how secure this could be compared to the Win32 API version.
> First, a C# program generates an array of 256 bytes, as such:
> using System;
> using System.Security.Cryptography;
> class Class1
> {
> [STAThread]
> static void Main()
> {
> byte[] b_raw = new byte[256];
> RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
> rng.GetBytes(b_raw);
> Console.Write("const BYTE b[] = {");
> for(int i = 0; i < 256; i += 8)
> {
> Console.WriteLine("0x{0:x}, 0x{1:x}, 0x{2:x}, 0x{3:x}, 0x{4:x}, 0x{5:x},
> 0x{6:x}, 0x{7:x},",
> b_raw[i], b_raw[i+1], b_raw[i+2], b_raw[i+3], b_raw[i+4], b_raw[i+5],
> b_raw[i+6], b_raw[i+7]);
> }
> }
> }
> This is run twice, so I have two arrays of 256 bytes, say key1 and key2.
> These are then hardcoded into the C++ encryption algorithm.
> Then, the C++ encryption algorithm goes as such:
> It memcpys the _TCHAR array to a byte array, then loops round each byte of
> this array.
> For each byte, it gets the value of key1[n] (where n is the byte number),
> and calls this 'b_current_indir' (the starting 'indirection level').
> Then, it gets the value of key2[n] and calls this 'levels' - the number of
> indirection levels.
> Then, an inner loop runs 'levels' times - and on each loop the following
> happens: the current byte of the data to be encrypted (dictated by the
> outer loop) is XORed with key2[b_current_indir], and THEN, b_current_indir
> is reassigned to take on the value of key2[b_current_indir].
>
> The whole C++ algorithm is defined as such:
> void Decrypt(BYTE* orig, long bytelen, _TCHAR* dataout)
> {
> BYTE* b_temp = new BYTE[bytelen];
> #ifdef _DEBUG
> ZeroMemory(b_temp, bytelen);
> #endif
> for(long bytenum = 0; bytenum < bytelen; bytenum++)
> {
> BYTE levels = b[bytenum % 256],
> b_current_indir = b2[bytenum % 256]; //always starts the same
> b_temp[(long)bytenum] = orig[(long)bytenum];
> for(long level = 0; level < levels; level++)
> {
> b_temp[(long)bytenum] ^= b_current_indir;
> b_current_indir = b2[(long)b_current_indir];
> }
> }
> memcpy(dataout, b_temp, bytelen);
> delete[] b_temp;
> }
>
> void Encrypt(_TCHAR* orig, long textlen, BYTE* dataout)
> {
> long bytelen = textlen * sizeof(_TCHAR);
> BYTE* b_temp = new BYTE[bytelen];
> #ifdef _DEBUG
> ZeroMemory(b_temp, bytelen);
> #endif
> memcpy(b_temp, orig, bytelen);
> for(long bytenum = 0; bytenum < bytelen; bytenum++)
> {
> BYTE levels = b[(long)(bytenum % 256)],
> b_current_indir = b2[(long)(bytenum % 256)];
> for(long level = 0; level < levels; level++)
> {
> b_temp[(long)bytenum] ^= b_current_indir;
> b_current_indir = b2[(long)b_current_indir];
> }
> }
> memcpy(dataout, b_temp, bytelen);
> delete[] b_temp;
> }
>
> int main()
> {
> LPTSTR testtext = _T("TheMagicBonj");
> long textlen = _tcslen(testtext) + 1;
> BYTE* b_enc = new BYTE[textlen * sizeof(_TCHAR)];
> #ifdef _DEBUG
> ZeroMemory(b_enc, textlen * sizeof(_TCHAR));
> #endif
> Encrypt(testtext, textlen, b_enc);
> _TCHAR* t_enc = new _TCHAR[textlen];
> ZeroMemory(t_enc, textlen * sizeof(_TCHAR));
> memcpy(t_enc, b_enc, textlen * sizeof(_TCHAR));
> _tprintf(_T("The encrypted text is \"%s\"\n"), t_enc);
> delete[] t_enc;
>
> _TCHAR* t_dec = new _TCHAR[textlen];
> Decrypt(b_enc, textlen * sizeof(_TCHAR), t_dec);
> _tprintf(_T("The decrypted text is \"%s\"\n"), t_dec);
> delete[] t_dec;
>
> }
>
> It seems to work to my eyes, but is it a pile of rubbish?
>
> My initial thoughts were that somebody could crack it by disassembling the
> machine code into assembly language, discovering where the global
> namespace section of the DLL file was and deriving key1 and key2 from
> that, and then just plugging them back through the algorithm, without
> necessarily understanding the algorithm from the assembly language. But
> even simpler than that, if they discovered that "it was probably *this*
> DLL that created *that* encrypted data, so if I find out how to call the
> DLL, I can decrypt it". To counter that, I could put the key in the
> application very easily. But does this help? Could someone with a
> knowledge of assembly language guess with a reasonable degree of accuracy
> which bit of data in a PE file was likely to be a key to an encryption
> algorithm?
> Wouldn't it be just as easy for someone wanting to crack it to still do
> that if I had written a DLL that used the Win32 API Crypto functions? If
> not, why not? Is the effectiveness of private key cryptography only as
> good as how well you can hide the key?
>
> Please give as many thoughts as possible...
>
> My (unsuccessful) attempt to use the Win32 API is as follows:
> BOOL GetData(_TCHAR* datain, long lendatain)
> {
> HCRYPTPROV hCryptProv;
> HCRYPTHASH hCryptHash;
> HCRYPTKEY hCryptKey;
> DWORD bytelen = (lendatain + 10) * sizeof(_TCHAR), databack = 0, bytesback
> = 0;
> BYTE* bData = new BYTE[bytelen];
> _TCHAR* cryptdata = new _TCHAR[lendatain],
> * decryptdata = new _TCHAR[lendatain];
>
> BOOL bSuccess = CryptAcquireContext(&hCryptProv, keysetname, NULL,
> PROV_RSA_FULL, CRYPT_NEWKEYSET);
> if(!bSuccess) bSuccess |= CryptAcquireContext(&hCryptProv, keysetname,
> NULL, PROV_RSA_FULL, 0);
> memcpy(bData, datain, bytelen);
> bSuccess &= CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hCryptHash);
> bSuccess &= CryptHashData(hCryptHash, (BYTE*)textkey, _tcslen(textkey),
> 0);
> bSuccess &= CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0,
> &hCryptKey);
> bSuccess &= CryptEncrypt(hCryptKey, hCryptHash, TRUE, 0, bData,
> &bytesback, bytelen);
> CryptDestroyKey(hCryptKey);
> CryptDestroyHash(hCryptHash);
> CryptReleaseContext(hCryptProv, 0);
> memcpy(cryptdata, bData, bytesback);
> _tprintf(_T("The encrypted data is \"%s\"\n"), cryptdata);
>
>
> bSuccess = CryptAcquireContext(&hCryptProv, keysetname, NULL,
> PROV_RSA_FULL, CRYPT_NEWKEYSET);
> if(!bSuccess) bSuccess |= CryptAcquireContext(&hCryptProv, keysetname,
> NULL, PROV_RSA_FULL, 0);
> bSuccess &= CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hCryptHash);
> bSuccess &= CryptHashData(hCryptHash, (BYTE*)textkey, _tcslen(textkey),
> 0);
> bSuccess &= CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0,
> &hCryptKey);
> bSuccess &= CryptDecrypt(hCryptKey, hCryptHash, TRUE, 0, bData,
> &bytesback);
> memcpy(decryptdata, bData, bytesback);
> databack = (DWORD)(bytelen / sizeof(_TCHAR));
> _tprintf(_T("The decrypted data is \"%s\"\n"), decryptdata);
>
> CryptDestroyKey(hCryptKey);
> CryptDestroyHash(hCryptHash);
> CryptReleaseContext(hCryptProv, 0);
>
> delete[] bData;
> delete[] cryptdata;
> delete[] decryptdata;
> CryptDestroyKey(hCryptKey);
> CryptDestroyHash(hCryptHash);
> CryptReleaseContext(hCryptProv, 0);
>
> return bSuccess;
> }
>
> void test(_TCHAR* string)
> {
> GetData(string, _tcslen(string));
> }
>
> int _tmain()
> {
> test(_T("TheMagicBonj"));
> return 0;
> }
> The output is:
>
> The encrypted data is "^ðnÍ&lÕeMagicBo"
> The decrypted data is "@2"
>
> which is disappointing.
>
- Next message: Craig: "filter by file properties"
- Previous message: BobT: "Marshalling WIN32_FIND_DATA"
- In reply to: Bonj: "How good an encryption algorithm is this?"
- Next in thread: Roy Fine: "Re: How good an encryption algorithm is this?"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|