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