How can I encrypt a file with an ec public key?
The high level strategy for this is as follows:
- Generate a temporary EC private key using
openssl ec
- Use the recipient's public key to derive a shared secret using
openssl pkeyutl
- Encrypt the plaintext using
openssl enc
using the derived secret key - Generate the EC public key from the private key using
openssl ecparam
- Generate the HMAC of the cipher text into a third file using
openssl dgst
- Delete the EC private key and the shared secret
The manual flow for this should roughly look at follows:
openssl ec -genkey -param_enc explicit -out temppriv.pem -name brainpool512r1
openssl pkeyutl -derive -inkey temppriv.pem -peerkey RecipientsPublicKey.pem -out SharedSecret.bin
openssl dgst -sha256 -out HashedSharedSecret SharedSecret.bin
openssl enc -aes-256-ofb -iv "00000000000000000000000000000000" -K "<Enter Hex From HashedSharedSecret here>" -in YourPlaintextFile -out ciphertext.enc
openssl ecparam -in tempprivkey.pem -pubout -out temppubkey.pem
openssl dgst -sha256 -hmac "<Enter Hex From HashedSharedSecret here>" -out MAC.bin ciphertext.enc
#strip the everything non-hex using your editor from MAC.bin
rm SharedSecret.bin
rm tempprivkey.pem
The script doing the encryption should roughly look like the following:
#!/bin/sh
EphemeralPrivateKey=$(openssl ecparam -genkey -param_enc explicit -name brainpool512r1) #generate the ephmeral private key
PrivateKeyBuffer=$(mktemp) #allocate a file to bufer the private key for the derive operation
PeerPublicKey="$1"
PlainTextFile="$2"
EphemeralPublicKeyFile="$3"
CipherTextFile="$4"
MACFile="$5"
echo -n "$EphemeralPrivateKey" > $PrivateKeyBuffer #buffer the private key
ProcessedDerivedSharedSecret=$(openssl pkeyutl -derive -inkey $PrivateKeyBuffer -peerkey $PeerPublicKey|openssl dgst -sha256) #derive the symmetric key using SHA-256 from the established secret
rm $PrivateKeyBuffer #remove the temporary file
ProcessedDerivedSharedSecret=${ProcessedDerivedSharedSecret#*= } #strip the (stdin)=
openssl enc -aes-256-ofb -iv "0000000000000000000000000000000" -K "$ProcessedDerivedSharedSecret" -in "$PlainTextFile" -out "$CipherTextFile" #encrypt using 0 IV and SHA-256 as key
MACValue=$(openssl dgst -sha256 -hmac "$ProcessedDerivedSharedSecret" "$CipherTextFile") #MAC it
MACValue=${MACValue#*= } #strip the (stdin)=
echo -n "$MACValue" > $MACFile #write the MAC
echo -n "$EphemeralPrivateKey" | openssl ec -param_enc explicit -pubout -out "$EphemeralPublicKeyFile" #write the ephemeral public key
The above code should work, but may not be optimal. The final message is composed from temppubkey.pem
, ciphertext.enc
and MAC.bin
, you may combine this in whatever way you prefer. Note that my choice for AES-256-OFB is no accident but intentional as CTR, CCM and GCM mode aren't available via the command line. Note further that I preferred AES-256 over the standard choice of AES-128 here because we can simply plug the output of SHA-256 in there. Note even further that using an all-zero IV is secure here as OFB "only" requires unique IVs per key and each key is fully random.
As for the security considerations: This method will generate a temporary private key for each file, ensuring all encryptions are unique and leakage of one shared secret won't leak all shared secrets for the same pair of communication partners. You could use digital signatures to ensure the message actually came from the same source.