-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Explicit encryption required? #33
Comments
@moritzploss thanks for opening this issue and your great feedback, your observation is spot-on. |
Great, I'll give it a go (hopefully soon) |
So far I found that if the One way to achieve this would be to get rid of the So to encrypt: Before def encrypt(plaintext) do
iv = :crypto.strong_rand_bytes(16) # create random Initialisation Vector
key = get_key() # get the *latest* key in the list of encryption keys
{ciphertext, tag} =
:crypto.block_encrypt(:aes_gcm, key, iv, {@aad, to_string(plaintext), 16})
iv <> tag <> ciphertext # "return" iv with the cipher tag & ciphertext
end After def encrypt(plaintext) do
iv = :crypto.strong_rand_bytes(16)
key = get_key() # get latest key
key_id = get_key_id() # get latest ID; can be more elegant, but you get the idea
{ciphertext, tag} =
:crypto.block_encrypt(:aes_gcm, key, iv, {@aad, plaintext, 16})
iv <> tag <> <<key_id::unsigned-big-integer-32>> <> ciphertext
end And to decrypt: Before def decrypt(ciphertext) do
<<iv::binary-16, tag::binary-16, ciphertext::binary>> = ciphertext
:crypto.block_decrypt(:aes_gcm, get_key(), iv, {@aad, ciphertext, tag})
end After def decrypt(ciphertext) do
<<iv::binary-16, tag::binary-16, key_id::unsigned-big-integer-32, ciphertext::binary>>
= ciphertext
:crypto.block_decrypt(:aes_gcm, get_key(key_id), iv, {@aad, ciphertext, tag})
end With that we could get rid of all the explicit encryption code in the User schema, as well as I don't know, do you think this is going in the right direction? |
@moritzploss yeah, looking good so far. 👍 |
… in issue dwyl#33) in order to make full use of the Ecto-Type behaviour and prevent unnecessary double load and dump and to make key rotation really work
First of all, thanks for this great tutorial! I learned a lot following along!
After going through the code several times, I'm wondering why we would need to explicitly encrypt/decrypt field values of our custom
EncryptedField
type before saving them in the database. Isn't that why we define our custom Ecto Types to begin with, so that we don't need to encrypt/decrypt values manually and explicitly, but rather leave these tasks to the callbacks that we define?For example, we use this function to explicitly encrypt the name and email field before insertion:
From what I understand, both the
email
andname
field are using our customEncryptedField
Ecto type, and therefore thedump
callback defined inEncryption.EncryptedField
will be called just before the data is inserted into the database, encrypting the field values before saving them.Similarly, we're explictly calling
EncryptedField.load
on the retrieved value inUser.one/0
:I guess we need this function so that we can explicitly specify the
key_id
, but doesn't that mean that we're encrypting the value twice before inserting it into the database (once implicitly, once explicitly), and decrypting it twice (once implicitly, once explicitly) when retrieving it?Thanks again for putting this tutorial together!
The text was updated successfully, but these errors were encountered: