My goal is to allow two clients to send files securely over an untrusted network without the need for more than one block of information to be sent. Both clients have ECDSA keys of size 256 bits. I'd like to stress that this is purely for fun and to learn elliptic curve concepts. This will not be used in a serious environment. That being said, here's the protocol design:

  1. Generate a random ECIES value using a random private number and the reciever's public key. Call the resulting key "Key" and the public ECIES value "ECIESPub".

  2. Calculate the sha256 hash of "Key + filecontents" where + is concatenation and sign it with your ECDSA key. Call the result "Sig".

  3. Encrypt the file contents with Key using AES-256-CFB. Call the result "Encrypted" and the IV of the algorithm "IV".

  4. Create a new file with the original file name with ".enc" appended. (dual extensions is acceptable) Write "ECDSAPublicKey + ECIESPub + IV + Encrypted + Sig".

  5. Send this file to the recipient. eg. through skype or email.

On the reciever's end:

  1. Calculate "Key" using "ECIESPub" and your own private ECDSA key.

  2. Decrypt "Encrypted" with "Key" and "IV". Write the result to a new file with the filename of the received file with ".enc" simply removed.

  3. Calculate the sha256 hash of "Key + DecryptedFileContents" and verify it with "Sig" and the sender's ECDSA public key.

  4. If the signature is valid, display a fingerprint derived from the sender's public key for the reciever to compare with their record of fingerprints. If the signature is not valid, display a warning to the reciever. In neither case will the sender gain any information about the success or failure of verification.

Note: I include the key in the generation of the signature to prevent an attack where an attacker can switch out the public key and signature with their own without changing or knowing the secret shared key, on the condition that they know the plaintext. I don't know how practical this attack is, but I thought it was best to combat it.

Are there any glaring holes in this construction that I'm missing?

Quick edit: I realize I'm reusing a key for signing and encryption, however, the main concern about this is the occasional legal requirement to give up an encryption key. If that happens, the reciever can recalculate the key from the public ECIES value and give that up instead. The sender, however, simply won't have the key anymore as it is randomly generated, used once, then forgotten.

  • $\begingroup$ "Display a warning to the receiver" Does this imply you actually refuse decryption? If you want to be super-sure, you could exchange SHA256(key||message) with HMAC(key,message), however I think signing the message alone is enough. Side note: Anything stopping you from using ECIES + ECDSA? $\endgroup$
    – SEJPM
    Commented Jul 7, 2015 at 14:51
  • $\begingroup$ @user1193112 : $\;\;\;$ What do you mean by the initial step 1? $\:$ The ECDH parameters must already exist beforehand or be generated as part of EC PKE key generation. $\;\;\;\;\;\;\;\;$ $\endgroup$
    – user991
    Commented Jul 7, 2015 at 18:16
  • $\begingroup$ @SEJPM oops, i seemed to have mixed up my terminology. Turns out I'm using ECIES, not ECDH. And the file still gets decrypted and saved, just that the reciever gets a very obvious warning. It's up to them if they want to delete the possibly tampered file or not. $\endgroup$
    – Daffy
    Commented Jul 7, 2015 at 18:37
  • 1
    $\begingroup$ I see a length extension attack for Hash(key | data). I see possible padding oracle attacks on the unauthenticated ciphertext. Even if the code could be secure, it doesn't seem to follow established practices. $\endgroup$
    – Maarten Bodewes
    Commented Jul 7, 2015 at 23:16
  • 1
    $\begingroup$ Your method is vulnerable to surreptitious forwarding. $\:$ The adversary can choose an integer $c$ and let their public key be (receiver's_ECIES_public_key)^c and write "ECDSAPublicKey + ECIESPub^c + IV + Encrypted + Sig". $\;\;\;\;$ $\endgroup$
    – user991
    Commented Jul 8, 2015 at 8:27

1 Answer 1


The system you described—essentially, sign-then-encrypt with ECDSA and ECIES—is vulnerable to the following attack:

  • Alice sends Bob the signed-encrypted message ‘The deal is off.’
  • Bob removes the encryption layer, getting a signed message from Alice saying ‘The deal is off.’
  • Bob re-encrypts the message to Charlie.
  • Charlie verifies the message and thinks Alice has canceled the deal.

The problem here is that the message that Alice signed didn't specify a recipient. The same attack applies to practical systems like OpenPGP and S/MIME, as noted by Don Davis in 2001.

The mere use of signature is also vulnerable to the following attack:

  • Alice types ‘what a basket of deplorables the voters are’ into her phone, but accidentally sends it to a journalist Jamal instead of her running mate.
  • Jamal now has a signed message from the political candidate calling her constituents deplorables which he can show to anyone.
  • Bob wins the election.

The problem here is that anyone can verify Alice's message, because signatures by design provide third-party verifiability. (The respect Alice has for the voters may be another problem, and the respect Bob has for democracy, rule of law, and journalists, yet another problem, but let's not make this situation too real lest someone get diced up with a bone saw.)

There's a much simpler system, which is actually what Diffie and Hellman suggested in their seminal 1976 paper. Assume Alice has published her public key $A = [a]P$ in the telephone book, and Bob has published his, $B = [b]P$.

  1. To send a message $m$, Alice looks up Bob's public key $B$ in the telephone book and computes $k = H([a]B)$ to use with an authenticated cipher $E$ to send the ciphertext $E_k(m)$ to Bob.
  2. On receipt of a ciphertext $c$, Bob looks up Alice's public key $A$ in the telephone book and computes $k' = H([b]A)$ to open the message $m = {E_k}^{-1}(c)$, or drop it on the floor if verification fails.

If the telephone book hasn't been tampered with, $k = k'$ so Alice and Bob can communicate.

If Alice wants to save time for many messages to Bob, she can cache the shared secret $k$ and reuse it many times; likewise Bob. The only overhead is the authentication in the authenticated cipher $E$.

Bob can't forge a message from Alice to Charlie because Charlie has a different shared secret with Alice. Jamal can't cryptographically prove to anyone else Alice sent an incriminating message, because any ciphertext that Alice could have made, Jamal could have made too using the same shared secret.

This very simple protocol—and the protocol you proposed—has another issue: if Alice's long-term key $a$ ever gets exposed, anyone who learns it can decrypt any past messages Alice has ever exchanged with anyone. Modern protocols also do key agreements for each conversation like TLS, or each message like Signal, so that they can quickly erase the keys that would allow a network eavesdropper to decrypt past messages. If you want a bespoke protocol in an application for which existing systems like TLS are unfit for some reason, you might look into the Noise protocol framework and the Noise Explorer, a tool to automatically verify security properties of custom instances of Noise.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.