How good an encryption algorithm is this?

G

Guest

Let's take yet another step back: _why_ do you need the key constantly
persisted in software on the client?

Because it's a "password remember" feature for a windows app, to enable the
application to logon to SQL servers that don't use windows authentication, so
that the user of the PC doesn't have to constantly type in the password every
time he uses it.
It's nothing to do with sending an encrypted message down a wire and
decrypting it again at the other end, and I don't control the part of the
software that decides whether or not the password is valid, it must be
enclosed in the connection string.
What do you need this key for

To log on to SQL server
, what
data are you trying to protect

The connection string
, who needs access to this data

Only the person that stored it (the application stores it when they type it
in for the first time)
, how do
you plan to know she is the right person to have access to said data?

Again, please take on board that I don't have control of the part of the
software that decides whether the password is valid. That is SQL server.
What threats do you envision and are trying to protect against?

Here goes again, then:
Someone being able to produce a "crack program" that enables the layman to
find out his colleague's SQL server password by running the "crack program"
on his computer when he's not looking, the crack program working by reading
my application's registry key.
I highly recommend "Writing Secure Code" by Michael Howard et al [1]. It
has a chapter on storing secrets securely on Windows machine. All of
them essentially boil down to trusting Windows authentication: if the
person managed to log into her Windows account, you assume that she is
indeed who she says she is.

I think CryptProtectData will enable me to do this.

[1] http://www.amazon.com/exec/obidos/tg/detail/-/0735617228
--
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
 
G

Guest

For example, if I want to send data from my laptop to my server at home,
then it's relatively straightforward for me to make sure that the key is not
known by anyone other than those two computers.

No offence, and that may be a very interesting and productive thing for you
to do, but how is it relevant to this thread? This is a case of where to
store the key on the client. As far as the encryption goes, it's nothing to
do with encrypting it on one machine and decyrpting it again on the other - I
don't know why everybody instantly assumes that it is - maybe because it
makes keeping the key secret easier?

Fortunately I'm not using your algorithm. So my key has a good chance of
remaining secret.

Great - I'm happy for you. But how does *mine* stand a chance of remaining
secret, when it is a problem of persistence rather than one of transfer?
I'm still not quite sure exactly what it is you're trying to achieve here.

Read the full thread. I've explained it many times, and posted a link to
someone else's similar scenario.
It sounds like you might be attempting to store credentials for connecting
to a SQL Server database in a way that stops people from just reading the
raw connection string and using those credentials for their own purposes,
but I'm not really sure if that's what you're doing.

Yes, that's exactly what I'm doing.
If that is what you
are doing, there are a few well-known solutions to this problem that work a
whole lot better than the approach you are trying to use. (The two obvious
ones being integrated security

In some environments that isn't available, for instance we have servers on
the same domain as the rest of the office. However, we're not the same
department as the IT department, so switching on windows authentication for
our servers would apparently give the domain administrators (in the IT
department) full access to the "BUILTIN\Administrators" server role, which we
don't want to do.

and the DPAPI, which is a technology built into Windows that is
designed to solve pretty much exactly this problem.)

That's probably what I'll go with. There's still unanswered questions
though, such as what if two users just happen to have the same password.
 
G

Guest

OK thanks
Just one question - presumably the "salt" always has to be the same?
If so, does it not suffer from the same problems of secret persistence as
the key itself does?


Igor Tandetnik said:
RoyFine said:
consider a database table that has encrypted passwords (not simple xor
mapping encryption, but a one-way hash of the password). if i look
at the encrypted password values, it seems like just so much muddle
to me. but in my spare time, i hash 5 million or so common passwords
(in prior spare time, i wrote a program to generate these) and i save
the hashed value with the plaintext. then i look in your password
table, and i just might find a few values there that are the same as
the ones that i computed - if we used the same algorithm to hash,
then i have just discovered a few passwords. this is a dictionary
attack (using my dictionary of plaintext trial passwords and the
corresponding hash)! the literature suggests that with todays
computer power, these sorts of attacks are trivial and you can break
an entire password file of a hundred or so in just minutes.

Enter *Salt* - salt is a random string that is concatenated with the
plaintext passwod before you run it through the hash (one-way)
function, then both the salt and the one way has are stored in the
database. if you are using a system generated guid, then every
stored value is now 128 bits longer. but the dictionary attack just
got a lot harder - now i have to compute the dictionary once for
every password/salt combination. now, instead of minutes to recover
the passwords, the time jumps up to a couple of weeks - see feldmeier
and karn, unix security-10 years later, applied cryptography [pg
52-53] by bruce scheiner, and the following link:
http://groups.google.com/[email protected]&output=gplain

To make dictionary attack even more difficult, you can use stretching
(aka iteration) - instead of just calculating the hash once, you iterate
it 2^N times for some N. Iterate means you calculate the hash of the
password+salt, then the hash of that hash, then the hash of last hash
and so on. The point of the exercise is as follows: when you verify the
password, you need to perform this iteration only once. Suppose it takes
you a second to do that - not too terrible for the user to wait.
However, the attacker perapring the dictionary must do the iteration for
each password/salt combination, and those seconds start to add up. If
the unsalted password could be attacked in minutes, salted one in weeks,
then for salted and stretched it might take years or decades.
--
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
 
R

Richard Blewett [DevelopMentor]

If you are worried about the "bad guy" sneaking up to his colleagues machine when the colleague is logged on and away from his machine, then I don't think CryptProtectData is going to help you as it uses (by default) the logged on user's details to protect the data.If you're worried about him sneaking over to his colleagues machine and logging on as himself (or someone other than the person who owns the data) and trying to crack the password then CryptProtectData will help you.

In the first scenario there is no real way to protect the data because all you really do is create a paper chase for the correct key to decrypt - the secret that unlocks the encyption algortihm is going to be available *somewhere* to the bad guy.

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk


Here goes again, then:
Someone being able to produce a "crack program" that enables the layman to
find out his colleague's SQL server password by running the "crack program"
on his computer when he's not looking, the crack program working by reading
my application's registry key.
I highly recommend "Writing Secure Code" by Michael Howard et al [1]. It
has a chapter on storing secrets securely on Windows machine. All of
them essentially boil down to trusting Windows authentication: if the
person managed to log into her Windows account, you assume that she is
indeed who she says she is.

I think CryptProtectData will enable me to do this.
 
J

Jon Skeet [C# MVP]

Bonj said:
Just one question - presumably the "salt" always has to be the same?
If so, does it not suffer from the same problems of secret persistence as
the key itself does?

The salt is generated randomly when the encrypted password is stored,
and stored *with* that password.

That way, the same password won't (unless you're very unlucky) map to
the same encrypted password.
 
G

Guest

If you are worried about the "bad guy" sneaking up to his colleagues
machine when the colleague is logged on and away from his machine, then I
don't think CryptProtectData is going to help you as it uses (by default) the
logged on user's details to protect the data.If you're worried about him
sneaking over to his colleagues machine and logging on as himself (or someone
other than the person who owns the data) and trying to crack the password
then CryptProtectData will help you.
In the first scenario there is no real way to protect the data because all you really do is create a paper chase for the correct key to decrypt - the secret that unlocks the encyption algortihm is going to be available *somewhere* to the bad guy.

Regards

I suppose you're right.

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk


Here goes again, then:
Someone being able to produce a "crack program" that enables the layman to
find out his colleague's SQL server password by running the "crack program"
on his computer when he's not looking, the crack program working by reading
my application's registry key.
I highly recommend "Writing Secure Code" by Michael Howard et al [1]. It
has a chapter on storing secrets securely on Windows machine. All of
them essentially boil down to trusting Windows authentication: if the
person managed to log into her Windows account, you assume that she is
indeed who she says she is.

I think CryptProtectData will enable me to do this.
 
G

Guest

That's a good explanation, thanks.


Ian Griffiths said:
"Bonj" replied:
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?

Only marginally. It's a bare minimum requirement, but it's very easy to
demonstrate algorithms that meet this requirement and yet are still
completely unsecure. So having this property is unfortunately not really a
strong indicator of the quality of the algorithm.

With respect to your particular algorithm, you seem to want actual concrete
proof that it's of no use, so here goes... There's problem with your
algorithm that is related to the problem above.

Even if a given input byte doesn't necessarily produce the same output byte
every time, it's also bad if a given input byte in a given input position
always encrypts to the same output byte. (Indeed these are effectively just
the same problem on different scales.) With a robust encryption system,
changes in one byte position in the input tend to have a much more
widespread effect in the output. Without this property, then all sorts of
attacks become quite simple - you can do the same kind of statistical
analysis that has already been discussed for each byte offset. Obviously
this takes longer than with a simple one byte substitution, but it's still a
major weakness, which is why you'll never see a serious encryption algorithm
that has this problem.

And I'm afraid your code suffers from this problem.

To illustrate why, let me point out something about your approach. You've
actually made your algorithm look a lot more complex than it really is.
Your Encrypt routine really does nothing more than XOR with the same
repeating 256 byte pattern every time. You'll find that if you call your
Encrypt function like this:

BYTE cheat[256];
BYTE zero[256];
ZeroMemory(zero, 256);
Encrypt((_TCHAR*)zero, 256, cheat);

the 'cheat' array will now contain the 256 byte repeating pattern that you
XOR all your input with. You can now just use a much simpler routine:

for (int i = 0; i < dataByteCount; ++i)
{
data ^= cheat[i % 256];
}

This is effectively equivalent to both your Encrypt and Decrypt routine. I
was able to take the byte buffer generated by your Encrypt routine and
recover the original string data this way. And looking at this code it's
very obvious what's being done to the data.

Your code makes it look like you're doing something more complex than you
really are, because you are using a roundabout way of choosing the repeating
256 byte pattern that you XOR the data with - you're deriving it from the
input keys rather than using them directly. But this roundabout derivation
doesn't add any security - cryptanalysis techniques that can be brought to
bear on repeating XOR patterns will work just fine regardless of how the bit
pattern was generated - it's the fact that it repeats that is important.
(Indeed your code might even be less secure than simply XORing against one
of the 256 byte input keys - it is possible that your munging introduces
patterns or statistical artifacts into the bit patterns that could be
exploited to make the attack more efficient.) Data encrypted this way can
be analyzed using exactly the same statistical techniques as can be used
with single byte substitution. It will take a little longer to do, but this
is ultimately a very unsecure encryption system. You would be a whole lot
better off with any of the encryption algorithms offered by the Crypto API.

(Also, a chosen plaintext attack would allow the attacker to get enough
information to decrypt *everything* in just one go. For example, my code
above to generate the 'cheat' block was a chosen plaintext attack, where my
chosen plaintext is all zeroes. But it happens to work for any 256 byte
chosen plaintext. And since you're talking about encrypting people's
passwords, then presumably I get to choose the plaintext - it's my password.
All I need to do is enter a 256 byte password, look at what you encrypt that
to, XOR it with my original password, and I've now got the 256 byte pattern
you're XORing everything with. I can now decrypt any password you encrypt.)

I'm by no means a crypto expert by the way, but it only takes the most basic
understanding of cryptanalysis to know that a simple repeating 256 byte XOR
is easily attacked. I'm afraid I have to agree with everyone who has been
telling you that encryption systems devised by people who don't know
anything about encryption tend to be utterly unsecure. Possibly you don't
believe this yet, because you think that if you keep working at it you'll
get there eventually. And maybe you will, but I'm not sure you'll get there
without learning a lot more about crytpanalysis - pretty much every
successful encryption algorithm has learned from the attacks made on older
algorithms. And if you do this learning, you'll discover just how many
people have tried before you to roll their own brand new systems, only to
fail to come up with anything useful. And you'll also learn why it is that
so many people have told you not to bother trying to roll your own
encryption algorithm...

Of course there may well be utterly novel new ways of doing encryption as
yet undiscovered. But historically, it looks like the odds are against you.
And I still think it's insane to try and invent your own in the hope that
you'll hit upon a new technique rather than relying on tried and tested
techniques.
 
I

Ian Griffiths [C# MVP]

What threats do you envision and are trying to protect against?
Here goes again, then:
Someone being able to produce a "crack program" that enables the layman to
find out his colleague's SQL server password by running the "crack
program"
on his computer when he's not looking, the crack program working by
reading
my application's registry key.

Given the set of requirements you have outlined, you will never be able to
protect against this attack. Only by restricting physical access to the
machine could you make such a crack impossible. If a skilled attacker gets
unrestricted physical access to the machine when the relevant user is logged
on, then there is no way on earth you can keep a secret. (Unless you
require the user to type in a password or something whenever the data needs
to be retrieved, which is contrary to what you're trying to achieve here.)

The fact is, that if your program is able to recover the full credentials,
then it will be technically possible to write a program that also recovers
these same full credentials.

The best you can do is make it hard for such a program to work. DPAPI does
a good job of this. One of the benefits it offers is that an attacker would
not only need physical access to the machine, she would also need to be able
to run this 'crack program' while logged in under her colleague's user
account.

You can also make life *much* harder for the attacker if it's acceptable for
your program to ask the user for a password onces when they first start it.
(I'm not sure from your description whether that's acceptable or not. I'm
not sure if you're just trying to avoid asking the user for passwords time
and time again, or whether you're trying to avoid asking them for a password
at all.) If it is acceptable, you can use this password to add extra
protection with DPAPI - it would mean that even if the attacker had physical
access to the user's machine while logged on as the user, they would still
need this last password before their crack program would run.

This means that the cracker somehow needs to get the password. (That's
still not so hard given the power you think your attacker will have. Two
obvious attacks are (1) install a keystroke logger, or (2) take a snapshot
of your program using NTSD and then trawl through it to find the
password...)


Of course there's a much more low-tech attack than the 'crack program'
approach which you're not going to be able to prevent: the attacker walks
up to their colleague's machine and just uses this program of yours...


--
Ian Griffiths - http://www.interact-sw.co.uk/iangblog/
DevelopMentor - http://www.develop.com/

Let's take yet another step back: _why_ do you need the key constantly
persisted in software on the client?

Because it's a "password remember" feature for a windows app, to enable
the
application to logon to SQL servers that don't use windows authentication,
so
that the user of the PC doesn't have to constantly type in the password
every
time he uses it.
It's nothing to do with sending an encrypted message down a wire and
decrypting it again at the other end, and I don't control the part of the
software that decides whether or not the password is valid, it must be
enclosed in the connection string.
What do you need this key for

To log on to SQL server
, what
data are you trying to protect

The connection string
, who needs access to this data

Only the person that stored it (the application stores it when they type
it
in for the first time)
, how do
you plan to know she is the right person to have access to said data?

Again, please take on board that I don't have control of the part of the
software that decides whether the password is valid. That is SQL server.
What threats do you envision and are trying to protect against?

Here goes again, then:
Someone being able to produce a "crack program" that enables the layman to
find out his colleague's SQL server password by running the "crack
program"
on his computer when he's not looking, the crack program working by
reading
my application's registry key.
I highly recommend "Writing Secure Code" by Michael Howard et al [1]. It
has a chapter on storing secrets securely on Windows machine. All of
them essentially boil down to trusting Windows authentication: if the
person managed to log into her Windows account, you assume that she is
indeed who she says she is.

I think CryptProtectData will enable me to do this.

[1] http://www.amazon.com/exec/obidos/tg/detail/-/0735617228
--
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

Ian Griffiths [C# MVP]

Bonj said:
No offence, and that may be a very interesting and productive thing
for you to do, but how is it relevant to this thread?

I came up with the example because you hadn't previously told us your full
requirements. (I know you think you had, but it was only clear from your
most recent problem statement.) Clear the example is totally relevant to
the question in the subject line. As it happens, it's also relevant to your
problem, despite what you appear to think.

Now that I understand your requirements, I am confident that what I
described is very relevant because it illustrates a weakness in your
algorithm, one that can be exploited in the scenario you describe as well as
in the scenario I described.

The weakness described in the laptop <-> home server scenario is the same as
the weakness in your scenario: anyone who gets a way of seeing the encrypted
data will be able to use a statistical attack to work out what the key is.
The only difference between the scenario I described and the one you
describe is where this encrypted data lives, and by extension, the way in
which the attacker gets her hands on that data. In the networked scenario,
you'd use a packet sniffer. But in your case, you would need to harvest
encrypted passwords from the registries of various users' machines. But
having obtained sufficient encrypted data, the statistical crypto attack is
identical in both cases because the attack is the same in both cases.

The fact that I'm doing this with data in the registry rather than data
being sent over the network is wholly irrelevant - the important thing about
the example I gave is that the encrypted data that is directly visible to an
attacker. (You've made it clear this is the case, since the attack you
describe involves the attacker having access to the machine. They would
need to get this access repeatedly to launch this particular attack of
course.) And even if the key may not be as directly visible to them, the
encrypted data can be used to discover the key. (Or a bit pattern that is
as good as the key.)

It's the fact that your algorithm makes it fairly easy to deduce the key
given nothing but the encrypted data that makes it a bad algorithm.

Things get even easier if the attacker is able to run your program - your
algorithm then makes it supremely easy to write the 'crack program' that you
are worried about. All I need to do is make up a nice long password, and
get your program to store it. Then I can XOR my credentials against what
you stored in the database, and I've got your XOR bit pattern. I can now
use this to recover anyone's credentials from what is stored in their
registry. (This is a 'chosen plaintext' attack.)

This is a case of where to store the key on the client. As far as the
encryption goes, it's nothing to do with encrypting it on one machine
and decyrpting it again on the other

Actually that's precisely what it might be. The attack would look like
this: the attacker gradually acquires the encrypted data in the registry
from her colleagues' machines. She builds up a collection of such pieces of
data, and when she has enough to succeed in her statistical attack, she is
now able to decrypt the data on her own machine.

The important thing is not whether the data went over a network (it probably
didn't with this attack - a USB disk would be the obvious mode of transfer).
Nor is it relevant whether or not the data got transferred. It's the fact
that it is visible to the attacker. After all, if the data was not visible
to your attacker, why on earth would you bother encrypting it? Isn't the
fact that attackers will be able to see the data the whole reason you want
to encrypt? So the fact that your algorithm is useless if the attacker can
see the data is the problem.

- I don't know why everybody
instantly assumes that it is - maybe because it
makes keeping the key secret easier?

The reason people keep coming up with networked examples is not because they
think that this is what's happening in your case. It's because they are
assuming (correctly) that in your scenario, encrypted data will be visible
to an attacker. So they are talking about a very common scenario in which
encrypted data becomes visible to the attacker. The way in which the data
becomes visible to the attacker is different, but the way in which it
becomes visible isn't relevant.

The fact that a network is involved in these examples isn't the point. The
key feature of all these examples is that the encrytped data is visible to
the attacker, just like it is in your scenario. That's why these examples
are all wholly relevant to your scenario. People aren't assuming that your
data is being passed over the network, they're just showing you common and
well-understood scenarios *in which the data is visible to the attacker*.
The data is visible to the attacker in your scenario too, which is why you
should be paying attention to these examples.

Great - I'm happy for you. But how does *mine* stand a chance of
remaining secret, when it is a problem of persistence rather than one
of transfer?

Are you saying that the encrypted data will not be visible to the attacker?
The issue of transfer is irrelevant, so please stop getting hung up on it.
The only relevant issue is what's visible to the attacker and what's not.

As for how your key will remain secret... Well that's why you use the
DPAPI. The DPAPI makes it very much more difficult to discover what the key
is. The key is not stored directly anywhere on the system - it is derived
from a number of different sources, some of which are not accessible to
normal users. (If your attacker is prepared to remove the hard disk, clone
it, and perform forensics on it to discover these hidden keys, then all bets
are off. But if your attacker is that determined, then you're probably out
of luck. Theoretically the attacker could also write a device driver to do
the same thing, but it's a very difficult attack; I've never heard of anyone
executing it successfully. And again it requires a level of skill and
determination that's quite formidable. And it would only be an option if
the machine was left unattended while logged in with an admin account.)

Read the full thread. I've explained it many times, and posted a link to
someone else's similar scenario.

I've read the full thread several times and with all due respect, as far as
I can tell you've only just recently posted a full coherent explanation.
(And I don't think I'm alone in thinking that, as everyone seemed to be
confused as to what you're trying to achieve until just lately.)

And don't forget that you started by asking "How good an encryption
algorithm is this?" which is a much more general question. You can't blame
people for answering the question you put in the subject line!


That's probably what I'll go with. There's still unanswered questions
though, such as what if two users just happen to have the same password.

The DPAPI uses various input data to drive the way in which it encrypts
data. If two different users encrypt *exactly* the same data, it will end
up storing different data, because it uses user identity as one of the
inputs to the key generation. (Actually it's better than that - merely
knowing who the user was isn't sufficient - you need to be logged in as that
user to decrypt the data.) Also, if the same user stores the same secret on
two different machines, the data stored is also different, because DPAPI
uses the machine identity as one of the inputs to its encryption algorithm.
 
I

Ian Griffiths [C# MVP]

Actually it's vitally important that the salt is different every time.

And the salt is not secret. It's only there to make dictionary attacks
harder, by ensuring that identical data hashes to different values. It's
not there to enable decryption.

--
Ian Griffiths - http://www.interact-sw.co.uk/iangblog/
DevelopMentor - http://www.develop.com/

Bonj said:
OK thanks
Just one question - presumably the "salt" always has to be the same?
If so, does it not suffer from the same problems of secret persistence as
the key itself does?


Igor Tandetnik said:
RoyFine said:
consider a database table that has encrypted passwords (not simple xor
mapping encryption, but a one-way hash of the password). if i look
at the encrypted password values, it seems like just so much muddle
to me. but in my spare time, i hash 5 million or so common passwords
(in prior spare time, i wrote a program to generate these) and i save
the hashed value with the plaintext. then i look in your password
table, and i just might find a few values there that are the same as
the ones that i computed - if we used the same algorithm to hash,
then i have just discovered a few passwords. this is a dictionary
attack (using my dictionary of plaintext trial passwords and the
corresponding hash)! the literature suggests that with todays
computer power, these sorts of attacks are trivial and you can break
an entire password file of a hundred or so in just minutes.

Enter *Salt* - salt is a random string that is concatenated with the
plaintext passwod before you run it through the hash (one-way)
function, then both the salt and the one way has are stored in the
database. if you are using a system generated guid, then every
stored value is now 128 bits longer. but the dictionary attack just
got a lot harder - now i have to compute the dictionary once for
every password/salt combination. now, instead of minutes to recover
the passwords, the time jumps up to a couple of weeks - see feldmeier
and karn, unix security-10 years later, applied cryptography [pg
52-53] by bruce scheiner, and the following link:
http://groups.google.com/[email protected]&output=gplain

To make dictionary attack even more difficult, you can use stretching
(aka iteration) - instead of just calculating the hash once, you iterate
it 2^N times for some N. Iterate means you calculate the hash of the
password+salt, then the hash of that hash, then the hash of last hash
and so on. The point of the exercise is as follows: when you verify the
password, you need to perform this iteration only once. Suppose it takes
you a second to do that - not too terrible for the user to wait.
However, the attacker perapring the dictionary must do the iteration for
each password/salt combination, and those seconds start to add up. If
the unsalted password could be attacked in minutes, salted one in weeks,
then for salted and stretched it might take years or decades.
--
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
 
A

Alex

How would I make sure that I am linking with odbc statically?

I think I am, but want to make sure of it.
I don't think you can do it in general case. Usually DB-makers provide
windows ODBC drivers as DLLs, so you'd have to go through ODBC library
which is implemented as DLL on Windows. To link statically you'd need
to have a static library implementing ODBC interface (unless you use
your database API directly), which is not generally available AFAIK.
What is the DLL called that the proxy replaces, so I can make sure
my app doesn't depend on it?
odbc32.dll. Not that eliminating dependency on ODBC is usually
practical though ...

Alex.
 
B

Bonj

The weakness described in the laptop said:
as the weakness in your scenario: anyone who gets a way of seeing the
encrypted data will be able to use a statistical attack to work out what
the key is. The only difference between the scenario I described and the
one you describe is where this encrypted data lives, and by extension, the
way in which the attacker gets her hands on that data. In the networked
scenario, you'd use a packet sniffer. But in your case, you would need to
harvest encrypted passwords from the registries of various users'
machines. But having obtained sufficient encrypted data, the statistical
crypto attack is identical in both cases because the attack is the same in
both cases.

Right, I see the point now. If you can see the encrypted target, and you can
see the plaintext and the encrypted version of a 'control example' (or a
few), then you can derive the key and hence decrypt the target.
The fact that I'm doing this with data in the registry rather than data
being sent over the network is wholly irrelevant - the important thing
about the example I gave is that the encrypted data that is directly
visible to an attacker. (You've made it clear this is the case, since the
attack you describe involves the attacker having access to the machine.
They would need to get this access repeatedly to launch this particular
attack of course.) And even if the key may not be as directly visible to
them, the encrypted data can be used to discover the key. (Or a bit
pattern that is as good as the key.)

Right, I see - I didn't get the point you were making in that the only thing
about the network is that you can see the data going over it. I was falsely
under the impression that your network example was implying to be taking
advantage of that asymmetric key technology.
 
H

Hendrik Schober

Jon Skeet said:
[...]

The salt is generated randomly when the encrypted password is stored,
and stored *with* that password.

I am not getting it. If the salt becomes
part of the data to get hashed, and is
stored with the hashed data, isn't it
then that I simply know part of the data
to get hashed?
I know must be wrong here somewhere, I'm
just not seeing where.


Schobi

--
(e-mail address removed) 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
 
J

Jon Skeet [C# MVP]

Hendrik Schober said:
Jon Skeet said:
[...]

The salt is generated randomly when the encrypted password is stored,
and stored *with* that password.

I am not getting it. If the salt becomes
part of the data to get hashed, and is
stored with the hashed data, isn't it
then that I simply know part of the data
to get hashed?
I know must be wrong here somewhere, I'm
just not seeing where.

Yes, you know part of the data to get hashed. However, it means that if
you want to precompute *all* the possible hashes, it takes much longer.
Basically it's a measure against dictionary attacks.
 
H

Hendrik Schober

Jon Skeet said:
[...]
I am not getting it. If the salt becomes
part of the data to get hashed, and is
stored with the hashed data, isn't it
then that I simply know part of the data
to get hashed?
I know must be wrong here somewhere, I'm
just not seeing where.

Yes, you know part of the data to get hashed. However, it means that if
you want to precompute *all* the possible hashes, it takes much longer.
Basically it's a measure against dictionary attacks.


Mhmm. I don't get it.
Let's assume we have some data D that gets
hashed. Then we have some salt value S,
which gets stored along with the hashed
data H.
Without the salting, we would try to find
D's that, when hashed, become H.
With salting, we try to find D's that, wenn
added S and then hashed, become H.
The difference is that the second method
requires us to add S before hashing D. But
this is only one operation, so it doesn't
multiply the number of tries we need?
What am I missing?

Schobi

--
(e-mail address removed) 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
 
R

Roy Fine

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.

now assume that i get access to your file that contains the hashed
passwords. I see the hashed value "xyz" in the file, where xyz is on the
order of some random 128 bit value. i look up xyz in my table of hashed
passwords and see if there is any password that hashed to xyz - if so, i
know the value that hashed to xyz, and therefore i know the password.

now consider the case where you concatentate a salt value to every password
before hashing it, and you then store two values in the password file - the
salt and the hashed value. you need to store the salt (it is unique for
each entry in the password file) in order to verify a password. i get
access to your new file, and now i have to rebuild my dictionary once for
every password/salt combination that i find. that is certainly doable - but
instead of cracking 50% of your unsalted password file in a matter of
minutes, it now takes a couple of months for each password/salt combination.
if your users change their passwrds every 4 weeks, then i am out of luck
until i get a *much* faster computer.

bottom line - salt only addresses one kind of attack -the dictionary attack,
and then, the salt only makes it more difficult

regards
roy fine



Hendrik Schober said:
Jon Skeet said:
[...]
The salt is generated randomly when the encrypted password is stored,
and stored *with* that password.

I am not getting it. If the salt becomes
part of the data to get hashed, and is
stored with the hashed data, isn't it
then that I simply know part of the data
to get hashed?
I know must be wrong here somewhere, I'm
just not seeing where.

Yes, you know part of the data to get hashed. However, it means that if
you want to precompute *all* the possible hashes, it takes much longer.
Basically it's a measure against dictionary attacks.


Mhmm. I don't get it.
Let's assume we have some data D that gets
hashed. Then we have some salt value S,
which gets stored along with the hashed
data H.
Without the salting, we would try to find
D's that, when hashed, become H.
With salting, we try to find D's that, wenn
added S and then hashed, become H.
The difference is that the second method
requires us to add S before hashing D. But
this is only one operation, so it doesn't
multiply the number of tries we need?
What am I missing?

Schobi

--
(e-mail address removed) 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
 
R

Roy Fine

Hendrik Schober said:
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

--
(e-mail address removed) 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
 
H

Hendrik Schober

Roy Fine said:
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

--
(e-mail address removed) 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
 
R

Roy Fine

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;
}
 
B

Bonj

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
 
Top