How good an encryption algorithm is this?

J

Jon Skeet [C# MVP]

Bonj said:
Right, OK. I see what you're saying.
See also inline.


Not plenty of good ones, though. Check how many home-grown "XOR" ones there
are on planetsourcecode compared to good, robust, CryptoAPI examples...more
the former than the latter definitely.

But surely there are enough CryptoAPI examples to help you out, aren't
there?
But that's just it - *as far as you know*.

True, but I suspect most people who *were* trained in encryption would
have understood the reasons given for not trying to come up with your
own algorithm to start with.
You don't know. How did anyone get good at encryption, how did the
people that do the "training" get good at it? They have ideas, and
put them into practice.

I suspect the first thing is to have a very strong mathematical
background, actually - a PhD in discreet maths would be a good starting
point, for instance.

They'd then no doubt read several books on cryptology and cryptography,
and study the standard algorithms, including old ones which have been
broken, in order to see where weaknesses have previously been
discovered.

Using "I think I'll design my own crypto algorithm" is a bad starting
point, IMO.
What's more, how do the crackers get good at their skill? Probably by
looking up to other crackers, and analysing how they do their stuff... and
those higher up crackers are probably more into breaking standard algorithms
than mine...I'm merely citing the old adage that the small child who plays
chess against a grandmaster, might just win - due to the fact that he plays
SO badly, none of the grandmaster's standard theories and gameplans work,
because they're all designed to work against other gameplans (which the young
child has no concept of), but still.....

That's really not a good argument in favour of creating your own
algorithm. Just because someone hasn't already studied yours in an
attempt to crack it doesn't mean it's more secure than one which many
highly skilled people *have* studied and failed to find significant
problems with. It just means they haven't looked at yours yet.
Again, weak as it is, the point comes back - if they're not likely to look
at it, how do they crack it?

They crack it when it's worth cracking, rather than now. Do you really
want to only find out whether your algorithm is strong enough when it's
already deployed in the field, and is protecting real-world data?
The reason for originally posting was that I had tried to get the standard
algorithm working, *and failed*. I did try several times on that first. I
knew my design choice wasn't a good one, but I persisted with it because at
the time it seemed like my *only* choice, and I had thought that I had
explained the fact that I couldn't get the CryptoAPI working sufficient.

But why did you wait until you'd made what you could see was a bad
choice before posting, rather than just asking for help with the
CryptoAPI in the first place? It's like starting to design your own
string class because you can't get Substring working - you're far more
likely to get help on standard stuff than you are to get genuinely
expert opinions on your own custom algorithms.
Igor has very kindly addressed that, and at the end of the day that's
probably what I'll go with, but since I started out on this tack and
spent all of a whole hour writing the damn thing, I'll finish.

No-one can stop you, of course - but I'd urge you not to make the
mistake of deciding to actually *use* it at any point, just because
you'll then have it.
Well, no - in light of the above paragraph, it possibly just seemed
like that - but you have explained yourself sufficiently now and I
thank you for that.

Goodo - I'm glad we understood each other in the end.
 
A

Alexander Grigoriev

If you just need to save a secret, why not simply use
CryptProtectData/CryptUnprotectData?
 
B

Bonj

I completely agree with your statement that "the process used to transform
key + encrypted data into plaintext cannot be considered to be secret". But,
well, that leads me to the question - how does using a standard algorithm
make it any easier to "secure" the key than using my own algorithm? There
always has to be a key, whatever algorithm I use...
I can't see any way round using the same key every time - and that means it
has to be stored as data within the executable file or a DLL, either in
global namespace memory or a binary resource. Which means someone could
easily find it out. Doesn't it?
 
I

Igor Tandetnik

Bonj said:
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].

Note two facts. First, XOR is associative and commutative, that is, a
sequence of XOR's can be executed in any order without changing the
result. Second, x XOR x == 0 for any x, and x XOR 0 == x for any x.

Suppose key2[n] happens to be even. Let the data byte at position n be
x. Then your inner loop, the one that loops 'levels' times, XOR's x with
itself an even number of times (the result is 0), then XORs some key
material on top of that. The result _does not_ depend on x _at all_.
Which means, there's no way to recover plain text from ciphertext - the
data is irretrievably lost in encryption.

Let's assume you fix it by simply XOR'ing x (the data byte) once. Now,
the operations of the inner loop don't depend on x at all. You can
represent an operation on byte x at position n as (x XOR K(n) ), where
K(n) depends only on n and key material (the bytes of key1 and key2).
You can as well precalculate K(n) and do a simple XOR without any loop,
and it won't change the result.

Thus, this modification of your algorithm is equivalent to a naive XOR
cipher - XORing the input data with a fixed key. If I happen to know
both a plaintext and a ciphertext for some message (known-plaintext
attack), I'll just XOR them together and get the key (note that the
attacker often has access to at least some bytes of plaintext, since
many messages contain known signatures in fixed places, like protocol
headers and such). Even if I don't, a simple XOR cipher is a particular
case of polyalphabetic aka Vigenere cipher - all the rage in 16-17th
centuries until broken in 1863.

http://www.trincoll.edu/depts/cpsc/cryptography/vigenere.html

--
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
 
I

Igor Tandetnik

Bonj said:
Hey, we're getting somewhere, thanks Igor...
(inline)


Do you reckon that, albeit not the be all and end all, but that if I
achieve that, then it's a big step forward in the right direction?

No offence intended, but perhaps reading a cryptology textbook should be
your first step in the right direction? After all, you don't start
designing car engines without first studying to be a mechanical
engineer. Why do you think you can design an encryption algorithm
without studying the field first? At least you should first become a
proficient cryptanalyst (cryptanalysis is a science of breaking
encryption), just so you know what an encryption algorithm should look
out for and protect against.
Note that this wouldn't occur in my algorithm, because each byte
undergoes a number of XOR operations given by f(n), where n is the
byte number.

Yours is equivalent to a simple XOR with a fixed key - see my other
message. Do you seriously believe this to be strong encryption?
Eh? Hard to miss? wouldn't it be easy to miss, as you could just say
from what point the meaningless jumble started, and that's where the
tampering occurred...

It is obvious that the message has been tampered with, and not to be
trusted. It does not matter what the original data was, or what the
modification attempt was. The message is discared, alarms are sounded,
and the investigation starts. It's like those tamper-proof medicine
bottles - if the packaging is broken, you don't much care (at least, not
immediately) what exactly happened to the medicine, who did it or for
what reason. It's often enough to know that the medicine is no good
anymore.
And... you're saying that an important principle of a good algorithm
is that each byte affects all the others after it, not just itself?

It's generally a very good idea, yes. Usually every byte affects all the
subsequent bytes, as most encryption algorithms work in one pass so it
is hard to retroactively affect preceding bytes. The algorithms need to
be fast, and also they often need to be implemented in a hardware device
with a limited amount of memory that encrypts a large data stream as it
moves past it, so going back to previous bytes is not feasible.
--
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
 
J

Jon Skeet [C# MVP]

I completely agree with your statement that "the process used to transform
key + encrypted data into plaintext cannot be considered to be secret". But,
well, that leads me to the question - how does using a standard algorithm
make it any easier to "secure" the key than using my own algorithm? There
always has to be a key, whatever algorithm I use...
I can't see any way round using the same key every time - and that means it
has to be stored as data within the executable file or a DLL, either in
global namespace memory or a binary resource. Which means someone could
easily find it out. Doesn't it?

Securing the key is a difficult problem, and one which in some ways
can't be solved satisfactorily. Of course in a public/private key
system, there are different benefits, but I don't know exactly what
you're doing, so can't really comment on whether that would be better.

I believe there is a Windows API which lets you get/set data which only
the current user has access to, encrypting it with (presumably)
something to do with their Windows password - I don't know much about
it, but I expect others reading this thread will. You could use that to
secure the key in some respects - as long as the user's account isn't
broken into, the key is safe. (It does mean a single weak point,
however.)
 
A

Alex

Yes, I had considered this, BUT:
I do not control the part of the software that decides whether the
re-entered (or "decrypted") password is valid or not. That is SQL
Server! Hence, I *do* need to actually reverse the process.
If you're using ODBC to communicate with SQL Server, you probably
pass the password to SQLConnect, so whoever has access to the
computer and curious enough can just look what your application
passes.

And if you're concerned about somebody intercepting the packets in
the transit, your encryption won't matter. Hopefully, SQL server is
using a decent encryption for the transmitted packets.

Alex.
 
S

Scott Allen

I believe there is a Windows API which lets you get/set data which only
the current user has access to, encrypting it with (presumably)
something to do with their Windows password - I don't know much about
it, but I expect others reading this thread will. You could use that to
secure the key in some respects - as long as the user's account isn't
broken into, the key is safe. (It does mean a single weak point,
however.)


There is the Data Protection API. DAPI can access a user store or a
machine store (the latter if you are running in a service). If you
want to keep a secret on a machine, Bonj, this probably the best
you'll get unless you go with a hardware approach (smart cards /
dongles).

DPAPI is a layer over the CrytoAPI. There is some wrapper code on MSDN
to make it easier getting started from C#:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod21.asp
 
B

Bonj

If you're using ODBC to communicate with SQL Server, you probably
pass the password to SQLConnect, so whoever has access to the
computer and curious enough can just look what your application
passes.

But surely they'd need to understand how to disassemble machine language
into assembly and understand where the "pass" takes place in order to do
that?
Thus wouldn't be able to be done by a layman...
At the end of the day, if Bloke A's rival, Bloke B, were to sneak onto Bloke
A's computer at lunch time, he could technically run whatever SQL he liked
just by starting up my program (that the password encryption security is a
minor part of), and running it on the server through the application's
interface. But, the crux is, Bloke A would return from lunch, discover Bloke
B had done something, and immediately change his password, and make sure he
locked his terminal in future - the real question is could Bloke B download
a program from the internet, load it onto Bloke A's computer, point it at
the registry and my program's application directory, and hey presto, he
actually *discovers* the password, to use at his own leisure, from his own
computer. That's the only boundary that I'm trying to get the right side of,
if you see what I mean....
I generally tend to assume that the average layman won't understand how to
disassemble assembly language into machine code. However, I don't like to
assume that they don't understand XOR encryption or how to generally browse
around the internet for some cracking program someone else has written.
 
B

Bonj

Yours is equivalent to a simple XOR with a fixed key - see my other
message. Do you seriously believe this to be strong encryption?

No, I don't believe this at all. We've already established that the
algorithm itself shouldn't need to be secret, right?
So discovering the *key* that I use for the encryption and decryption is the
only thing that's going to need to be done to crack it, right?

*So, how does the CryptoAPI help me protect the secrecy of the key any
better than my own algorithm would?*

I'm talking about the DATA that is used for the key - the CODE that is used
to do the equation "key + encrypted => decrypted" is unimportant compared to
this, this is a principle I now accept...
 
B

Bonj

(please see my other post asking how to protect the actual key, given that
the algorithm shouldn't need to be secret - but inline also.)
Note two facts. First, XOR is associative and commutative, that is, a
sequence of XOR's can be executed in any order without changing the
result. Second, x XOR x == 0 for any x, and x XOR 0 == x for any x.

Interesting... I would say that only on average 1 byte of each key is going
to be zero...this is less than 0.5% of the values....., so would it matter?
Only 1 in 255 of the values wouldn't be changed, and that's only on this
step.
Suppose key2[n] happens to be even.
Let the data byte at position n be x. Then your inner loop, the one that
loops 'levels' times, XOR's x
yes...

with itself

no, not with itself! Where have I said it XORs it with *itself*? It would be
quite *obvious* to even me that that would produce zero...!
an even number of times (the result is 0), then XORs some key material on
top of that. The result _does not_ depend on x _at all_. Which means,
there's no way to recover plain text from ciphertext - the data is
irretrievably lost in encryption.

Well.... I don't think that to be the case. If you try the algorithm, you'll
see that it does indeed work. It's just unlikely to be very secure, such as
has apparently been drummed into me. But my current quandry is how would
*any* algorithm, as the key has to be hidden somewhere. Perhaps I need a
key-hiding algorithm..... but that's just another cryptographic algorithm
though... aaaargghh! Is it just a vast hall of mirrors that leads unto
infinity?
Thus, this modification of your algorithm is equivalent to a naive XOR
cipher - XORing the input data with a fixed key. If I happen to know both
a plaintext and a ciphertext for some message (known-plaintext attack),
I'll just XOR them together and get the key

Right, I see what you mean here - yes. So you're saying that however many
keys I invent, they will all 'boil down' to one master one, which even if
not defined, will exist, such that it will just convert all cipher back to
plaintext instantly?

(note that the
attacker often has access to at least some bytes of plaintext, since many
messages contain known signatures in fixed places, like protocol headers
and such). Even if I don't, a simple XOR cipher is a particular case of
polyalphabetic aka Vigenere cipher - all the rage in 16-17th centuries
until broken in 1863.

Surely XOR requires binary, which was only invented in the1940s or
something?
Why would people before the age of computers understand binary?
 
I

Igor Tandetnik

Bonj said:
*So, how does the CryptoAPI help me protect the secrecy of the key any
better than my own algorithm would?*

It does not. The cryptography is a science of trading off a large secret
for a small secret. You take a large secret (a message or file to be
encrypted) and replace it with a small secret (an encryption key). Now,
the problem of trasmitting or storing a large message is reduced to the
problem of transmitting or storing the key - so called key exchange
problem. Cryptography is of little help with this one. Still, strong
cryptography is important - once you manage to solve key exchange one
way or the other, you don't want a third party to be able to read your
message even without knowing the key after all.

Key exchange problem is unsolved in general case, mainly because it's an
administrative problem more than it is a mathematical problem. It
involves a question of trust. For example, there are algorithms for
generating good strong encryption keys from user-supplied passwords. But
then, you end up with the usual problems of people forgetting their
passwords, writing them on sticky notes and tacking them to their
monitors, being susceptible to social engineering attacks and so on. In
other words, the fact that a person knows correct password may not mean
that the system should trust her.

For now, key exchange needs to be solved on a case-by-case basis (that's
what security consultants derive most of their income from). So, maybe
if you describe the original problem you are trying to solve, rather
than your attempted solution, somebody might be able to help you.
--
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
 
C

Carl Daniel [VC++ MVP]

Bonj said:
Surely XOR requires binary, which was only invented in the1940s or
something?
Why would people before the age of computers understand binary?

They don't need to. The elementary school "secret decoder ring" style of
encryption that simply substitutes one set of characters for another set is
as secure as a repeated XOR cipher. That's the kind of cipher that Igor is
referring to.

-cd
 
I

Igor Tandetnik

Bonj said:
Right, I see what you mean here - yes. So you're saying that however
many keys I invent, they will all 'boil down' to one master one,
which even if not defined, will exist, such that it will just convert
all cipher back to plaintext instantly?

This is pretty much what happens with any encryption algorithm that uses
XOR alone. This has something to do with XOR being a linear operation on
bit vectors, but that's about as much as I know about this stuff.
Surely XOR requires binary, which was only invented in the1940s or
something?
Why would people before the age of computers understand binary?

They didn't. They drew (and presumably memorized) a 26x26 table showing
that if the plaintext letter is X and the key letter is Y, then the
ciphertext letter should be Z. A XOR on bytes may be thought of as a
256x256 table that explicitly spells the output given two inputs, and
thus is a particular case of Vigenere. The fact that you don't store
this table in memory but calculate the result on the fly does not change
the nature of the algorithm.
--
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
 
B

Bonj

Just out of interest folks, this is an almost exact description of the
precise issue I'm having:
http://groups.google.com/groups?hl=...stry+%22hide+the+key%22&hl=en&lr=&sa=N&tab=wg


Bonj said:
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, 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.
 
R

Roy Fine

Bonj,

You have essentially implemented a stream cipher - and they are much easier
to beat than are block ciphers. In the end, a positional output character
of your algorithm is a simple function of the same positional input
character and the password. That becomes trivial to beat with a dictionary
attack. Additionally, look at the encrypted output for every case where the
input has the character 'A', or 'B', or 'C' in position 1, or 2, or 3. If
you see a pattern, then so will the hackers, and your scheme is all for
naught. Encode "TheMajicBonj" and examine the encoded value. Then encode
"SheMajicBonj", "WeeMajicBonj", "FeeMajicBonj", and "KeeMajicBonj". We see
that the character 'e' in position 3 always encodes to the same value -
OOOOOPS now we are getting close to breaking the code. So all of your
mucking about - and you can get from the letter e in position x of plaintext
to the character '??' in same position x of decoded text.

Additionally, if I could convince you to add my account to your database,
and then if I could get access to the encrypted data, then I don't need to
know the algorithm. Consider how much easier it gets if you then allow me
to change my password a couple of times, all the while looking at the
resultant encoded/encrypted data - discovering the net mapping scheme
becomes straight forward. - out jumps Captain Midnight's Ovalteen Decoder
Ring.


regards
roy
 
I

Igor Tandetnik

Roy Fine said:
You have essentially implemented a stream cipher - and they are much
easier to beat than are block ciphers.

Not if they are implemented correctly - that is, with a key stream that
is an output of a cryptographically strong random number generator. What
Bonj has is a stream cipher with a repeated key, aka Vigenere cipher.
Those are known to be weak and easily broken.
--
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
 
J

Jeff Louie

Bonj.... In the end this may not be an encryption problem, but an
administration user rights problem. Choosing an appropriate user level
and
table level access control under SQL is the start. But at _some level_
the end
user is going to have to authenticate with a user name and password or
_room key_ if this system is going to have any security at all.
Embedding the
user name and password in the application provides no real protection
once I
have access to the running application (or even access just to the
code). The
end user needs to authenticate before running the application, don't you
agree? The advantage of forcing the user to memorize the SQL user name
and password is that you can periodically change the lowlevelaccess SQL
user
name and password without breaking the application. The alternative is
to
place the server/terminal in a locked room and protect the actual room
key!

The application does provides a level of password indirection so the
administrator can enter the SQL password at application start up and
restrict
user access to the application with user defined passwords, dongles,
fingerprint or retinal scanners :).

Regards,
Jeff
No, I don't believe this at all. We've already established that the
algorithm itself shouldn't need to be secret, right?
So discovering the *key* that I use for the encryption and decryption is
the
only thing that's going to need to be done to crack it, right?<
 
R

Roy Fine

Igor Tandetnik said:
Not if they are implemented correctly - that is, with a key stream that
is an output of a cryptographically strong random number generator. What
Bonj has is a stream cipher with a repeated key, aka Vigenere cipher.
Those are known to be weak and easily broken.
--

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.

In the absence of a salt value, these stream ciphers, even based on
"cryptographically strong random number generator" are trivial against a
dictionary attack.

You pointed out earlier, the XOR was a simple linear function - and that is
about as good as your will ever get on a stream cipher. You don't see
non-linear functions introduced (S-Box) until you get to block ciphers.

roy
 
S

Scott Allen

*So, how does the CryptoAPI help me protect the secrecy of the key any
better than my own algorithm would?*

It's not foolproof, but because it's built into the system it has some
advantages, like being about to encrypt a master key with the user's
password and hooking password change events in to re-encrypt. The
system can also expire master keys and tries to keep them out of
memory that can swap to disk and expose the key.

Lots of info here:
http://msdn.microsoft.com/library/d...-us/dnsecure/html/windataprotection-dpapi.asp
 
Top