Re: My own little replacement for the Unix crypt
From: beej (bj_at_con.sole)
Date: 02/29/04
- Next message: Mok-Kong Shen: "Re: Sun setting on stream ciphers?"
- Previous message: Mok-Kong Shen: "Re: 3DES and super-encryption"
- In reply to: Tom St Denis: "Re: My own little replacement for the Unix crypt"
- Next in thread: Lanny Ripple: "Re: My own little replacement for the Unix crypt"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Date: Sun, 29 Feb 2004 06:05:05 -0500
In article <c8016437.0402281551.13a0917f@posting.google.com>,
tomstdenis@yahoo.com says...
> beej <bj@con.sole> wrote in message news:<MPG.1aaa74047a18ee3e98a9f8@news.alt.net>...
> > I wanted a simple, effective crypto program for *nix, and since 'crypt'
> > is weak and everything else seems to be either commercial (expensive) or
> > of questionable origin I decided to write my own. I'm not foolish
> > enough to try to design a crypto algorithm, so I snagged the source for
> > Skipjack and used that. Here are the basic steps my little prog
> > employs. Does anyone notice any obvious or serious flaws here? How
> > secure is this?
>
> Yes. You didn't really state your goals or threat model. Therefore,
> I have no idea if it's secure because I don't know what it's for.
My goal is a small, simple program that would encrypt data a whole lot
better than crypt. Preferably well enough that a moderately experienced
cryptographer (say, a BS in mathematics and 3 - 5 years of practical
experience) armed with a mid-range RISC based server would need several
man-months to decipher a message.
> > 1. Get the names of the source and destination files from the user.
>
> Does it handle pipes?
No. It chokes on them. I've got code in there that fiddles with stdin
and stdout (the part where a user types in a password) and it seems to
break pipes.
> > 2. Ask the user whether to encrypt or decrypt the source file.
> >
> > If we're encrypting...
> >
> > 3. Get a password from the user.
>
> Do you echo the chars? How do you read it in? gets()? Can I specify
> the password on the command line?
Prompt for a password, turn off stdout, grab the password via fgets,
turn stdout back on. Repeat for verification. Then zeroize the
verification.
> > 4. Run the password through SHA to create a 160-bit irreversible hash.
> > 5. Use the hash to key a stream cipher.
>
> Bad idea. Same password will always produce the same stream.
>
> > 6. Call the stream cipher ten times, but instead of using the keystream
> > to encrypt any data, use the bytes to form a key for Skipjack.
>
> Now your skipjack key is the same for the same password.
You have to either store a key securely, or be able to reconstruct it.
The reason I used the password as the basis for the key, is that I chose
to reconstruct keys instead of storing them. (Reconstruction requires
repeatable data, and the password is the only repeatable data
available.)
> > 7. Grab the system time and use it to initialize the stock random number
> > generator that comes with Unix.
>
> Um? rand()? What if I encrypt two files below the clock resolution?
> [e.g. two processes with the same password?]
Actually, I used lrand48()... Which is allegedly a little better than
rand().
You could still get the same seed if you managed to launch two processes
and type in the passwords for them, all within a second of each other.
> > 8. Call the stock Unix random number generator eight times, and use the
> > bytes to form an initialization vector (for Cipher Block Chaining).
>
> Ok so now I have two messages with the same CBC IV.
>
> > 9. Read in the source file and encrypt it with Skipjack in Cipher Block
> > Chaining mode, using the key and initialization vector created above.
> > At the same time, form a 32-bit CRC value using the plaintext.
>
> CRC? You already have SHA-1 handy right? [see below]
>
> > 10. Dump the initialization vector, CRC value and ciphertext into the
> > destination file.
>
> Reasonable.
>
> > My own thoughts:
> >
> > 1. The user could supply a weak password. The program doesn't directly
> > use the password, so that offers a small degree of protection against a
> > bad password, but it would still be possible for an attacker to guess
> > passwords until the right one is found. I guess the only way to fix
> > this is to have the prog enforce some password rules.
>
> This is true of any program really. Though normally passwords don't
> lead to keys (you'd randomly generate a key and use the password to
> mask the password, or at least that's how I would do it).
A bad password would still be a problem, though.
> > 2. The stock RNG routines that come with Unix are notoriously bad, but
> > does that really matter for the initialization vector? The IV is
> > basically meant to be "extra" data, and there's nothing random about
> > data in general, so there's no point in trying to make the IV
> > cryptographically strong.
>
> I already "broke" your protocol. So yes, rand() isn't sufficient.
The real problem there isn't the quality of data from rand() it's the
fact that seeding from the system clock can sometimes yield identical
streams. What I really need is a better seed.
> > 3. Can the CRC (based on the original plaintext and stored as plaintext
> > with the encrypted data) be used to derive any of the original data? I
> > don't see how it could... But then, I'm not a mathematician.
>
> Yes it can. CRCs are linear so if I know plaintext blocks I can play
> with them. You have SHA-1 why not make HMAC-SHA-1 out of it? That at
> least is secure.
>
> Also because your Key+IV generation is weak [so is your key
> generation] I can easily make it encrypt two files with the same
> key+IV.
>
> First you should change your key generation. A simple trick is todo
> the following
>
> 1. Generate a random 10 byte string, K
Where would you suggest that I get ten cryptographically secure bytes
from? Got any canned CSPRNG code that I can use?
> 2. Hash the password and XOR it against K, call that MK [masked key]
In order for this to be as secure as possible, the password hash would
also have to be 10 bytes long. Any shorter, and you have to use some
bytes more than once. Any longer, and you have to select a subset of
bytes to use and hope that the hashes for two passwords don't produce
the same bytes in those positions. Is there a secure hash algorithm
that produces 10-byte hashes?
> 3. Derive IV via IV = hash(MK || "IV")
> 4. Derive the HMAC key from K via HK = hash(K || "hmac")
> 5. Emit the MK to the dest
> 6. Encrypt the file with skipjack using K/IV/HK
> 7. Emit the HMAC-SHA-1 to the dest
I like this idea, except for my questions about the first two steps.
> This has the benefit of a stronger MAC and the IV/key are not as easy
> to recycle. In fact all of the entropy [for a fixed password] comes
> from K so you really only need 10 random bytes for the entire process.
> Comes with the added bonus that you don't need to store the IV
> [though really MK just takes its place].
>
> .... Or .... Just use gnupg as another poster suggested ;-)
But that wouldn't be any fun.
- Next message: Mok-Kong Shen: "Re: Sun setting on stream ciphers?"
- Previous message: Mok-Kong Shen: "Re: 3DES and super-encryption"
- In reply to: Tom St Denis: "Re: My own little replacement for the Unix crypt"
- Next in thread: Lanny Ripple: "Re: My own little replacement for the Unix crypt"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
|