Hi Michael. Great points, and thanks for them.
If you look back a few revisions, you can see we had been using ECIES until recently. The main motivation for switching was that it's not available in a lot of other toolkits, there is incompatibility among toolkits that do implement it, and specifically there's no implementation in JS, which is a near-term requirement (non-browser-downloaded, etc, etc). We tried to commission a javascript port but haven't (yet) gotten any takers, and were leery about attempting one ourselves. Agree about an off-the-shelf KDF and MAC. About the key validation, BC is decoding the keys before this point but cannot find specifically whether they are or are not validating, but had assumed so. I think makes sense to borrow the briar parser and use it for decoding or at least for validation. Thanks again, - Michael On Mar 20, 2014, at 9:17 AM, Michael Rogers <mich...@briarproject.org> wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA256 > > Hi Michael, > > What you're trying to do is very similar to ECIES. You should probably > use ECIES, which has received more review than your design. It's > implemented in BouncyCastle, and there was recently a thread on the > BouncyCastle mailing list about how to use it. > > The cost of deriving the shared secret via ECDH will vastly outweigh > the cost of symmetric MAC and encryption operations, so there's little > point in cutting corners. > > If you decide to stick with your own design, here are a couple of > comments: > > On 19/03/14 16:01, Michael Powers wrote: >> (3) To ensure you can decrypt your own message, you encode one of >> the keys for yourself. Might your private key be compromised when >> used with your own public key moreso than someone else's public >> key? > > Good question - I don't know if it's safe to derive an ECDH shared > secret from a private key and the corresponding public key. An > alternative would be to save a random symmetric key alongside your > public/private key pair, and use that instead of a shared secret for > deriving the encryption and authentication keys for your own copy of > the message. > >> * Takes the specified 32 bytes, appends its sha-256 digest, and >> xor * encrypts those 64 bytes with the sha-512 hash of the ECDH >> shared secret * and the entry id. > > Are entry IDs supposed to be unique across all messages? > > What happens if a sender accidentally reuses an entry ID? What happens > if Alice sends a message to Bob with entry ID n, and Bob sends a > message to Alice with entry ID n? The messages have the same shared > secret and entry ID, therefore the same shared hash. > > The adversary can XOR the encrypted keys to get the XOR of the > unencrypted keys. Does it help the adversary in some way to know that > message 1 is encrypted with unknown key k1, message 2 is encrypted > with unknown key k2, and the XOR of k1 and k2 is x? I don't know, I'm > not a cryptanalyst. ;-) But it makes me uneasy that the adversary has > *any* knowledge about the keys. > >> KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", >> "BC"); keyAgreement.init(privateKey); >> keyAgreement.doPhase(publicKey, true); byte[] sharedSecret = >> keyAgreement.generateSecret(); > > Make sure you validate the public key before using it. See SEC 1 > section 3.2.2.1, and Java code here: > > http://code.briarproject.org/akwizgran/briar/blob/master/briar-core/src/org/briarproject/crypto/Sec1KeyParser.java > >> // generate 512 bits using shared secret and entry id MessageDigest >> sha512 = MessageDigest.getInstance("SHA-512"); >> sha512.update(sharedSecret); >> sha512.update(ByteBuffer.allocate(8).putLong(entryId)); byte[] >> sharedHash = sha512.digest(); > > This homebrew key derivation function is a reinvention of the > concatenation KDF from NIST SP 800-56A section 5.8. You should think > about why the NIST KDF includes extra inputs, such as the identities > of the parties in the key exchange and the output length, and why it's > so careful about delimiting the inputs. > >> * Takes the specified 64 byte encoded input and xor decrypts it >> with the * sha-512 hash of the ECDH shared secret and the entry id. >> Then checks to * see if the last 32 bytes is the sha-256 hash of >> the first 32 bytes. > > You're reinventing a MAC. Please just use a MAC. > >> KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", >> "BC"); keyAgreement.init(privateKey); >> keyAgreement.doPhase(publicKey, true); byte[] sharedSecret = >> keyAgreement.generateSecret(); > > Validate the public key. > >> // verify that the digest of first 32 bytes matches last 32 bytes >> for (i = 0; i < 32; i++) { if (digest[i] != decoded[i + 32]) { // >> incorrectly decoded: we're not the intended recipient return null; >> } } > > You should use a constant-time comparison here to avoid timing > attacks. Something like: > > boolean matches = true; > for (i = 0; i < 32; i++) { > matches &= (digest[i] == decoded[i + 32]); > } > if (!matches) { > // incorrectly decoded: we're not the intended recipient > return null; > } > >> int maximumOutputLength = bufferedBlockCipher >> .getOutputSize(inputLength); byte[] output = new >> byte[maximumOutputLength]; > > Now that you're using PKCS padding, this is simply the output length - > no need to truncate. > > But anyway this is irrelevant - use ECIES! > > Cheers, > Michael > > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.10 (GNU/Linux) > > iQEcBAEBCAAGBQJTKupbAAoJEBEET9GfxSfMqjEH/jtUZ4krXgyyIisNtynmQbYO > Ona2renHcbZr7ajBZgEMFGeuFK2dmH9v0aqrsTrnke3RLA2YN2gxe6pzvdJE6z6/ > CoIwcPIAqe1bE2iZN/HiFrrLoamQqX2YiTRQbooCc2+FulmWJVs3tzaTFltwlS6U > MfADfNzbzPIgN1pZ3oZ75AMAzXvlTS8RF7zjiuE7WGWB0YkhMHe9BrbSL5n+7HSh > krrKAUscw1cXtlC+/g3KzR0wOtHd1Io5Y55GTJEj+X+q+enZ5AiJ+rJNHM/bwckw > EtY4vWwOu0NQjypJRpLweqeTD80lHFerqOT1nzOrXa4vnV8SnRR9mOL37UTUSAw= > =yytB > -----END PGP SIGNATURE----- > -- > Liberationtech is public & archives are searchable on Google. Violations of > list guidelines will get you moderated: > https://mailman.stanford.edu/mailman/listinfo/liberationtech. Unsubscribe, > change to digest, or change password by emailing moderator at > compa...@stanford.edu. -- Liberationtech is public & archives are searchable on Google. Violations of list guidelines will get you moderated: https://mailman.stanford.edu/mailman/listinfo/liberationtech. Unsubscribe, change to digest, or change password by emailing moderator at compa...@stanford.edu.