lib/slosilo/symmetric.rb in slosilo-1.1.0 vs lib/slosilo/symmetric.rb in slosilo-2.0.0
- old
+ new
@@ -1,33 +1,54 @@
module Slosilo
class Symmetric
+ VERSION_MAGIC = 'G'
+ TAG_LENGTH = 16
+
def initialize
- @cipher = OpenSSL::Cipher.new 'AES-256-CBC'
+ @cipher = OpenSSL::Cipher.new 'aes-256-gcm' # NB: has to be lower case for whatever reason.
end
-
+
+ # This lets us do a final sanity check in migrations from older encryption versions
+ def cipher_name
+ @cipher.name
+ end
+
def encrypt plaintext, opts = {}
@cipher.reset
@cipher.encrypt
- @cipher.key = opts[:key]
+ @cipher.key = (opts[:key] or raise("missing :key option"))
@cipher.iv = iv = random_iv
- ctxt = @cipher.update(plaintext)
- iv + ctxt + @cipher.final
+ @cipher.auth_data = opts[:aad] || "" # Nothing good happens if you set this to nil, or don't set it at all
+ ctext = @cipher.update(plaintext) + @cipher.final
+ tag = @cipher.auth_tag(TAG_LENGTH)
+ "#{VERSION_MAGIC}#{tag}#{iv}#{ctext}"
end
-
+
def decrypt ciphertext, opts = {}
+ version, tag, iv, ctext = unpack ciphertext
+
+ raise "Invalid version magic: expected #{VERSION_MAGIC} but was #{version}" unless version == VERSION_MAGIC
+
@cipher.reset
@cipher.decrypt
@cipher.key = opts[:key]
- @cipher.iv, ctxt = ciphertext.unpack("a#{@cipher.iv_len}a*")
- ptxt = @cipher.update(ctxt)
- ptxt + @cipher.final
+ @cipher.iv = iv
+ @cipher.auth_tag = tag
+ @cipher.auth_data = opts[:aad] || ""
+ @cipher.update(ctext) + @cipher.final
end
def random_iv
@cipher.random_iv
end
def random_key
@cipher.random_key
+ end
+
+ private
+ # return tag, iv, ctext
+ def unpack msg
+ msg.unpack "aa#{TAG_LENGTH}a#{@cipher.iv_len}a*"
end
end
end