The scheme that I proposed to dogisland of the StrongCoin project is as follows.
privkey = 32-byte EC private key, big-endian form
salt = 4-byte random salt value
symkey = PBKDF(password, salt, SHA256, 4096)
pwcheck = SHA256(SHA256(privkey | salt))
protkey = AES-CBC-256(privkey, symkey) | pwcheck[0:64] | salt
The 44-byte protkey value then has a type byte (136) prefixed to the beginning, and is base-58 encoded as per the bitcoin function EncodeBase58Check().
Interesting, although your layering/composing of different cryptographic schemes may come back to bite you.
As I see it, you want to encrypt the password and also verify that the encrypted bits are unchanged. Here's a slight modification of the above:
privkey = 32-byte EC private key, big-endian form
salt = 4-byte random salt value
symkey =
PBKDF2(HMAC-SHA1, password, salt, 4096, 64)cryptedprivkey =
(privkey XOR symkey[0:32])pwcheck =
HMAC-SHA1(symkey[33:64],cryptedprivkey)protkey = cryptedprivkey | pwcheck | salt- You should use the more recent PBKDF2 (http://www.di-mgt.com.au/cryptoKDFs.html), which allows you to produce arbitrary length keys. In this case we're generating a 64-byte length key, half of which we'll use for encryption and the other half for authentication.
- Next we encrypt the privkey with half the symkey by XOR'ing them together, a simple stream cipher. This avoids the use of AES in client code (slow in Javascript?, missing an initialization vector, plaintext length < AES block size of 128 bits) and should be pretty safe. Stream ciphers like RC4 are simply a random keystream XOR with the plaintext and are difficult to break, provided the random keystream is truly unpredictable and you never repeat the key. The trouble with stream ciphers then manifests when you have a large enough chunk of data to encode, then without a proper CPRNG like RC4 the keystream may repeat etc. and thus block ciphers under CBC become useful. Since we have a 32-byte private key and a 32-byte symkey to XOR together, this should not be the issue.
- We then use a MAC, specifically a HMAC-SHA1, to act as the password check against modification. We use the second half of the symkey as the secret. HMAC's are particularly designed for message authentication.
Alternatively (safer/more paranoid) you could use two salts to produce two 32-byte keys, one for the encryption, one for the authentication.