473,385 Members | 1,347 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

How good an encryption algorithm is this?

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.
Nov 16 '05
113 12161
Roy Fine <rl****@twt.obfuscate.net> wrote:
Hendrik

assume that you have a password file that contains all of the hash values
for all of the passwords of users in the system.

asssume that i know your hash algorithm - so i just hash a 5 or 6 million
common passwords, and store the password and hashed value in a database
structure - that becomes my dictionary of hashed passwords. the generation
of the dictionary took quite a while to generate (maybe a couple of months),
but now that i have it, and access is quick.
Oh, now I understand. I didn't get
that you would have precalculated
a dictionary.

Thanks for being so patience with
me! :)
[...]

Schobi

--
Sp******@gmx.de is never read
I'm Schobi at suespammers dot org

"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
Nov 16 '05 #101

"Hendrik Schober" <Sp******@gmx.de> wrote in message
news:co**********@news1.transmedia.de...
Roy Fine <rl****@twt.obfuscate.net> wrote:
Hendrik

assume that you have a password file that contains all of the hash values for all of the passwords of users in the system.

asssume that i know your hash algorithm - so i just hash a 5 or 6 million common passwords, and store the password and hashed value in a database
structure - that becomes my dictionary of hashed passwords. the generation of the dictionary took quite a while to generate (maybe a couple of months), but now that i have it, and access is quick.
Oh, now I understand. I didn't get
that you would have precalculated
a dictionary.

Thanks for being so patience with
me! :)

as always, it's my pleasure... rlf
[...]

Schobi

--
Sp******@gmx.de is never read
I'm Schobi at suespammers dot org

"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett

Nov 16 '05 #102
Bonj,

if you want to go back to using the Crypto API - I reworked your code - and
now it encrypts and decrypts with no loss of data. here is the code:
/* ************************************************ */

#pragma comment(lib,"Advapi32.lib")

char *szPassword = "eieio";
/* ------------------------------------------------ */
BOOL GetData(_TCHAR* datain, long lendatain)
{
HCRYPTPROV hCryptProv;
HCRYPTHASH hCryptHash;
HCRYPTKEY hCryptKey;

DWORD sts;
BOOL bSuccess = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
0);
bSuccess = CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hCryptHash);
bSuccess = CryptHashData(hCryptHash, (BYTE*)szPassword,
_tcslen(szPassword), 0);
bSuccess = CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0, &hCryptKey);

DWORD cryptBlockSize = lendatain;
bSuccess = CryptEncrypt(hCryptKey, NULL, TRUE, 0,(BYTE *)datain,
&cryptBlockSize, 0);
sts = GetLastError();
BYTE* bData = new BYTE[cryptBlockSize];
memcpy(bData, datain, lendatain);

DWORD bytesback = lendatain;
bSuccess = CryptEncrypt(hCryptKey, NULL, TRUE, 0, bData, &bytesback,
cryptBlockSize);
sts = GetLastError();

CryptDestroyKey(hCryptKey);
CryptDestroyHash(hCryptHash);
CryptReleaseContext(hCryptProv, 0);

bSuccess = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0);
bSuccess &= CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hCryptHash);
bSuccess &= CryptHashData(hCryptHash, (BYTE*)szPassword,
_tcslen(szPassword), 0);
bSuccess &= CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0,
&hCryptKey);

bSuccess &= CryptDecrypt(hCryptKey, NULL, TRUE, 0, (BYTE *)bData,
&bytesback);
bData[bytesback] = 0;

CryptDestroyKey(hCryptKey);
CryptDestroyHash(hCryptHash);
CryptReleaseContext(hCryptProv, 0);

delete[] bData;
return bSuccess;
}

/* ------------------------------------------------ */
void test(_TCHAR* string)
{
GetData(string, _tcslen(string));
}

/* ------------------------------------------------ */
int _tmain(int argc, _TCHAR* argv[])
{
test(_T("TheMagicBonj"));
return 0;
}
Nov 16 '05 #103
Oh right, thanks very much.
I'd still like to get CryptProtectData and CryptUnprotectData to work, which
I can't at the moment, I have made a separate post.

Cheers

"Roy Fine" <rl****@twt.obfuscate.net> wrote in message
news:O4**************@TK2MSFTNGP14.phx.gbl...
Bonj,

if you want to go back to using the Crypto API - I reworked your code -
and
now it encrypts and decrypts with no loss of data. here is the code:
/* ************************************************ */

#pragma comment(lib,"Advapi32.lib")

char *szPassword = "eieio";
/* ------------------------------------------------ */
BOOL GetData(_TCHAR* datain, long lendatain)
{
HCRYPTPROV hCryptProv;
HCRYPTHASH hCryptHash;
HCRYPTKEY hCryptKey;

DWORD sts;
BOOL bSuccess = CryptAcquireContext(&hCryptProv, NULL, NULL,
PROV_RSA_FULL,
0);
bSuccess = CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hCryptHash);
bSuccess = CryptHashData(hCryptHash, (BYTE*)szPassword,
_tcslen(szPassword), 0);
bSuccess = CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0,
&hCryptKey);

DWORD cryptBlockSize = lendatain;
bSuccess = CryptEncrypt(hCryptKey, NULL, TRUE, 0,(BYTE *)datain,
&cryptBlockSize, 0);
sts = GetLastError();
BYTE* bData = new BYTE[cryptBlockSize];
memcpy(bData, datain, lendatain);

DWORD bytesback = lendatain;
bSuccess = CryptEncrypt(hCryptKey, NULL, TRUE, 0, bData, &bytesback,
cryptBlockSize);
sts = GetLastError();

CryptDestroyKey(hCryptKey);
CryptDestroyHash(hCryptHash);
CryptReleaseContext(hCryptProv, 0);

bSuccess = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0);
bSuccess &= CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hCryptHash);
bSuccess &= CryptHashData(hCryptHash, (BYTE*)szPassword,
_tcslen(szPassword), 0);
bSuccess &= CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0,
&hCryptKey);

bSuccess &= CryptDecrypt(hCryptKey, NULL, TRUE, 0, (BYTE *)bData,
&bytesback);
bData[bytesback] = 0;

CryptDestroyKey(hCryptKey);
CryptDestroyHash(hCryptHash);
CryptReleaseContext(hCryptProv, 0);

delete[] bData;
return bSuccess;
}

/* ------------------------------------------------ */
void test(_TCHAR* string)
{
GetData(string, _tcslen(string));
}

/* ------------------------------------------------ */
int _tmain(int argc, _TCHAR* argv[])
{
test(_T("TheMagicBonj"));
return 0;
}

Nov 16 '05 #104
"Carl Daniel [VC++ MVP]" <cp*****************************@mvps.org.nospam >
wrote in message news:O2**************@TK2MSFTNGP12.phx.gbl...
You should never (or almost never) store passwords with reversible
encryption. Instead, store the username in plaintext and store the password as a one-way hash. Typically MD5 or SHA(1) are used for this purpose.


I'd disagree with that. It's a nice theory, but in the real world,
where 80% of applications have no real need for strong security (*), and 99%
of user eventually forget their password, most users would prefer an "email
me my personally chosen and usually easy-to-remember password" option,
rather than an "email me a new string of random characters which I'm going
to lose before the next time I log in"

(*) e.g., a website forum needs a userid & password, but a security breach
would cause little harm.

--
Truth,
James Curran
[erstwhile VC++ MVP]
Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
Nov 16 '05 #105
James Curran <Ja*********@mvps.org> wrote:
"Carl Daniel [VC++ MVP]" <cp*****************************@mvps.org.nospam >
wrote in message news:O2**************@TK2MSFTNGP12.phx.gbl...
You should never (or almost never) store passwords with reversible
encryption. Instead, store the username in plaintext and store the

password
as a one-way hash. Typically MD5 or SHA(1) are used for this purpose.


I'd disagree with that. It's a nice theory, but in the real world,
where 80% of applications have no real need for strong security (*), and 99%
of user eventually forget their password, most users would prefer an "email
me my personally chosen and usually easy-to-remember password" option,
rather than an "email me a new string of random characters which I'm going
to lose before the next time I log in"

(*) e.g., a website forum needs a userid & password, but a security breach
would cause little harm.


A security breach might cause little harm in terms of the forum itself,
but knowing *one* password that someone uses could often easily lead to
knowing the *only* password that that person uses. I'm not as good at
using different passwords all over the place as I should be, although I
do do it to some extent - but I suspect many users just use the same
password everywhere. In that case, a security breach is potentially
*very* damaging.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #106
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
A security breach might cause little harm in terms of the forum itself,
but knowing *one* password that someone uses could often easily lead to
knowing the *only* password that that person uses. I'm not as good at
using different passwords all over the place as I should be, although I
do do it to some extent - but I suspect many users just use the same
password everywhere. In that case, a security breach is potentially
*very* damaging.


Oh yes. Just after 9/11/2001, a major broadband support site set up a forum
for 9/11 discussions (to keep them all in one place), and after two weeks
they closed it down. Somebody else opened the "9/11 overflow forums", and
people flocked over there to continue the discussions. Of course, people
used the same username and password, and when that other site got hacked,
the major broadband site got a bit of unwanted attention. A few *moderators*
had their accounts expropriated this way, and it was a big hairy mess.

Generally I tell people that if they used their "main site" password on
another site, even for a few minutes, they have to change their *main* site
password immediately. The other site very well may keep logs, and changing
the other-site password immediately doesn't have the effect they imagine.

I don't use the same password for any two accounts *anywhere*.

Steve
--
Steve Friedl -- Tustin, California USA -- www.unixwiz.net
Unix Wizard -- Microsoft MVP/Security -- I speak for me only
Nov 16 '05 #107
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om
I'm
not as good at using different passwords all over the place as I
should be, although I do do it to some extent


You might find Password Minder by Keith Brown useful:

http://www.pluralsight.com/tools.aspx

--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
Nov 16 '05 #108

"Igor Tandetnik" <it********@mvps.org> wrote in message
news:uY**************@TK2MSFTNGP12.phx.gbl...
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om
I'm
not as good at using different passwords all over the place as I
should be, although I do do it to some extent


You might find Password Minder by Keith Brown useful:

http://www.pluralsight.com/tools.aspx


Or the [free] Password Safe from Bruce Schneier:

http://www.schneier.com/passsafe.html

Been using it for years, it stores *hundreds* of passwords.

Steve
--
Steve Friedl -- Tustin, California USA -- www.unixwiz.net
Unix Wizard -- Microsoft MVP/Security -- I speak for me only
Nov 16 '05 #109
Steve Friedl [MVP/Security] wrote:
"Igor Tandetnik" <it********@mvps.org> wrote in message
news:uY**************@TK2MSFTNGP12.phx.gbl...
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om
I'm
not as good at using different passwords all over the place as I
should be, although I do do it to some extent


You might find Password Minder by Keith Brown useful:

http://www.pluralsight.com/tools.aspx


Or the [free] Password Safe from Bruce Schneier:

http://www.schneier.com/passsafe.html

Been using it for years, it stores *hundreds* of passwords.


This one looks interesting:

http://keepass.sourceforge.net/

--
Doug Harrison
Microsoft MVP - Visual C++
Nov 16 '05 #110
>> You might find Password Minder by Keith Brown useful:

http://www.pluralsight.com/tools.aspx
Or the [free] Password Safe from Bruce Schneier:

http://www.schneier.com/passsafe.html


I just thought I'd point out that Keith's password minder is also free.

The way you worded your reply suggested that it wasn't...

Been using it for years, it stores *hundreds* of passwords.


And also, Keith's can store hundreds of passwords - again, you seem to be
suggesting that it can't.

--
Ian Griffiths - http://www.interact-sw.co.uk/iangblog/
DevelopMentor - http://www.develop.com/
Nov 16 '05 #111
I also use PasswordSafe, but I'd recommend the latest version (v2.07)
https://sourceforge.net/projects/passwordsafe/

(they've just, finally, added the ability to merge two password files, so
you can keep the copy at home & the one at the office in sync)

--
Truth,
James Curran
[erstwhile VC++ MVP]
Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
"Steve Friedl [MVP/Security]" <st***@unixwiz.net> wrote in message
news:eA**************@TK2MSFTNGP15.phx.gbl...
Or the [free] Password Safe from Bruce Schneier:

http://www.schneier.com/passsafe.html

Been using it for years, it stores *hundreds* of passwords.

Nov 16 '05 #112
In article <Ou**************@TK2MSFTNGP14.phx.gbl>, "Bonj"
<benjtaylor at hotpop d0t com> says...

[ ... ]
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:
[ ... ]
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].
[ ... ]
It seems to work to my eyes, but is it a pile of rubbish?


Yes, pretty much.

First you need to realize that repeated XORs have little real effect.
For the moment, let's assume that you XOR one particular input byte
with two other key bytes, calling the input A and the key bytes B and
C, giving: encrypted_byte = (A ^ B) ^ C. The associative property
says this is equivalent to encrypted_byte = A ^ (B ^ C).

If we chose to, we could do:
D = (B ^ C);
encrypted_byte = A ^ D;

Changing the number of times the inner loop executes only changes the
number of items on the right side of the first line that computes D,
meaning that whole inner loop is equivalent to XORing each input byte
with exactly ONE effective key byte (which is the result XORing
together all the key bytes you currently use).

Therefore, what you really have is just a slow and complex way of
producing the same output as XORing each input byte with one key
byte.

There are a number of ways of breaking this. Using a chosen
plaintext, the attack is downright simple: the attacker just gets you
to encrypt a bunch of zero bytes. Since the result of 0 XOR D is D,
this transmits your effective key. The result is that your attacker
gets the _effective_ key that even YOU don't know -- what you
transmit will look (to you) pretty much like random garbage (as you'd
expect for encrypted data) but is really the effective key.

The result of that is that the attacker can decrypt by XORing each
input byte with the effective key for that byte -- IOW, he can
actually decrypt your messages slightly FASTER than you can.

Using a known-plaintext attack is almost as easy: he simply XORs each
byte of the encrypted text with the original text that was encrypted
to (again) get the effective encryption key. Once again, he can
decrypt your messages faster than you can.

A ciphertext-only attack is a _little_ more difficult, but not much.
There are a couple of different typical methods. One is to look only
at the statistics of the encrypted text. You start separating the
text into two bins -- odd-numbered bytes in the first bin and even-
numbered bytes in the second. You then do three bins, four bins,
etc., until you find a length at which (almost by magic) there is a
substantial difference in the number of characters in each bin. At
that point, the attacker has just found your effective key length
(something you probably don't know).

From there his attack becomes fairly simple, based on the frequency
of various characters -- if you're using normal English input, the
space will typically be the most common character. Letters follow a
fairly consistent pattern -- 'e' the most common, 't' the second
most, etc. This will probably solve the encryption pretty easily,
but if he has any difficulty with it, he might also use digraphs and
trigraphs -- sets of two and three letters that do/don't occur
together (e.g. 'th' is common, 'q' is normally followed by 'u', 'jj'
is almost certainly a mistake, and so on).

The other basic approach to an attack requires two encrypted
messages. The attacker realizes (even if you don't) that each byte of
each message is A xor D, where A was the input byte and D and some
(effective) key byte. If he XORs together the bytes of the two
messages, he gets:

(A XOR D) XOR (A' XOR D)

Using the distributive property, this is:

(A xor A') XOR (D XOR D)

Since anything XOR'd with itself is zero, this is:

(A xor A') xor 0

XORing with zero is an identity operation, so this is equivalent to:

A xor A'

Now the attacker uses what are know as cribs -- he takes some guesses
at things that are likely to be in one message or the other. Just for
example, "the' is probably going to occur at least once in one of the
messages. Since he's now factored out the key, and just has the two
original messages XORd against each other, he'll simply take 'the'
and xor it with the combined message. At a place that one message
contained 'the' to start with, he'll get the plaintext of the other
message at the same spot as well. If he tries 'the' and gets 'qjv' as
the matching plaintext from the other message, he can easily guess
that he hasn't found a match. OTOH, if he gets 'his' there's a pretty
fair chance that he's just found a place that one of the original
messages contained 'the' and the other contained 'his'.

In a real attack, he might combine both approaches -- the first
approach is easy to automate, so he'd just let the computer crank
through that. Once he knows your effective key length, each match
with the crib solves more than just the few letters that match -- it
solves all the other characters where the same key byte would be
used.

With as simple of a scheme as you've devised, the cribs probably
wouldn't even come into use at all. The first approach would break
your cipher automatically in almost no time at all. Just for
comparison consider that years ago, WordPerfect would "encrypt"
documents with essentially this same scheme. On the 20 MHz 386 I used
back then, I could normally recover people's passwords for them
entirely automatically in about 10 seconds or so. On a current
machine, that would be reduced to a matter of milliseconds...

--
Later,
Jerry.

The universe is a figment of its own imagination.
Nov 16 '05 #113
In article <OC**************@tk2msftngp13.phx.gbl>,
rl****@twt.obfuscate.net says...

[ ... ]
stream cipers are easier to beat than are block ciphers - byte 0 of stream
cipher can be decoded with NO other information from any other bytes in the
stream, byte 1 plaintext can be discovered using only byte 1 decoded and
byte 0 plaintext - consider block ciphers that have to be broken one block
at a time - typically 16 bytes at a time.


This really isn't true. It is true that stream ciphers have to be
used differently from block ciphers to provide secure results, but
with proper use a stream cipher provides security similar to a block
cipher.

In point of fact, block ciphers are often used to implement stream
ciphers -- just for example, output feedback and cipher feedback (OFB
and CFB) are two common ways of doing stream encryption with block
ciphers.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Nov 16 '05 #114

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Alan Silver | last post by:
Hello, I am writing a page where sensitive data is collected (over SSL) and stored in a database. I have been looking at the .NET encryption classes, but am a bit confused as to which is best...
11
by: John Williams | last post by:
I've written a simple program to do XOR encryption as my first foray into understanding how encryption works. The code compiles fine, however it segmentation faults on every run. using gdb to...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.