lib/slosilo/symmetric.rb in slosilo-3.0.0 vs lib/slosilo/symmetric.rb in slosilo-3.0.1

- old
+ new

@@ -3,45 +3,54 @@ VERSION_MAGIC = 'G' TAG_LENGTH = 16 def initialize @cipher = OpenSSL::Cipher.new 'aes-256-gcm' # NB: has to be lower case for whatever reason. + @cipher_mutex = Mutex.new 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] or raise("missing :key option")) - @cipher.iv = iv = random_iv - @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}" + # All of these operations in OpenSSL must occur atomically, so we + # synchronize their access to make this step thread-safe. + @cipher_mutex.synchronize do + @cipher.reset + @cipher.encrypt + @cipher.key = (opts[:key] or raise("missing :key option")) + @cipher.iv = iv = random_iv + @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 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 = iv - @cipher.auth_tag = tag - @cipher.auth_data = opts[:aad] || "" - @cipher.update(ctext) + @cipher.final + # All of these operations in OpenSSL must occur atomically, so we + # synchronize their access to make this step thread-safe. + @cipher_mutex.synchronize do + @cipher.reset + @cipher.decrypt + @cipher.key = opts[:key] + @cipher.iv = iv + @cipher.auth_tag = tag + @cipher.auth_data = opts[:aad] || "" + @cipher.update(ctext) + @cipher.final + end end - + def random_iv @cipher.random_iv end - + def random_key @cipher.random_key end private