slosilo 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 19532fb817cc0d993257331452fd6fc36be49da8
4
- data.tar.gz: 63c9b867b4e125aff0e5680e21a9a31605629716
3
+ metadata.gz: 761d6e24aaa95427bbc3d7449bc980b29b602bca
4
+ data.tar.gz: 79950d2ab62c71a6f9ebdb1f68afdfd13c53894e
5
5
  SHA512:
6
- metadata.gz: 799000b32ea19b4b5ca3fb63901007e16c659af8ea383f3d469ed4a91a1c23b10529eeffda3167b73e0bf67043258622c997b68fefd110cf5fb96cedc8b3769c
7
- data.tar.gz: c017465fd76fd4aa9812924ead3c3342d66d3f87f222cd94c0f08c0eadd2dd66c7088e3bc5333ae6d4a83f165c2329456cc38158b2de5d17e76dd1fe0d098449
6
+ metadata.gz: de1ab282bd0067317a21e2d40dbb0668c737e487bc2e29e25120f460191d2c8a550b25ec98719a4d99d72176a73f0b47007703733ad5a0e77077a13c1fc54d6d
7
+ data.tar.gz: e7444706c7f1af27f3a7eebf350252b37a033ca4b225a5d8ea6d24afbf49f40d42e6613187f8f0fe2322c9bf73dc1b54d5e36796ba7ef10aa8c95ff54f5aa8b3
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Slosilo is providing a ruby interface to some cryptographic primitives:
4
4
  - symmetric encryption,
5
- - a mixin for easy encryption of object attributes (WARNING: unauthenticated, see below),
5
+ - a mixin for easy encryption of object attributes,
6
6
  - asymmetric encryption and signing,
7
7
  - a keystore in a postgres sequel db -- it allows easy storage and retrieval of keys,
8
8
  - a keystore in files.
@@ -17,6 +17,20 @@ And then execute:
17
17
 
18
18
  $ bundle
19
19
 
20
+ ## Compatibility
21
+
22
+ Version 2.0 introduced new symmetric encryption scheme using AES-256-GCM
23
+ for authenticated encryption. It allows you to provide AAD on all symmetric
24
+ encryption primitives. It's also **NOT COMPATIBLE** with CBC used in version <2.
25
+
26
+ This means you'll have to migrate all your existing data. There's no easy way to
27
+ do this currently provided; it's recommended to create a database migration and
28
+ put relevant code fragments in it directly. (This will also have the benefit of making
29
+ the migration self-contained.)
30
+
31
+ Since symmetric encryption is used in processing asymetrically encrypted messages,
32
+ this incompatibility extends to those too.
33
+
20
34
  ## Usage
21
35
 
22
36
  ### Symmetric encryption
@@ -24,12 +38,14 @@ And then execute:
24
38
  ```ruby
25
39
  sym = Slosilo::Symmetric.new
26
40
  key = sym.random_key
27
- ciphertext = sym.encrypt "secret message", key: key
41
+ # additional authenticated data
42
+ message_id = "message 001"
43
+ ciphertext = sym.encrypt "secret message", key: key, aad: message_id
28
44
  ```
29
45
 
30
46
  ```ruby
31
47
  sym = Slosilo::Symmetric.new
32
- message = sym.decrypt ciphertext, key: key
48
+ message = sym.decrypt ciphertext, key: key, aad: message_id
33
49
  ```
34
50
 
35
51
  ### Encryption mixin
@@ -39,11 +55,15 @@ require 'slosilo'
39
55
 
40
56
  class Foo
41
57
  attr_accessor :foo
42
- attr_encrypted :foo
58
+ attr_encrypted :foo, aad: :id
43
59
 
44
60
  def raw_foo
45
61
  @foo
46
62
  end
63
+
64
+ def id
65
+ "unique record id"
66
+ end
47
67
  end
48
68
 
49
69
  Slosilo::encryption_key = Slosilo::Symmetric.new.random_key
@@ -56,13 +76,6 @@ obj.foo # => "bar"
56
76
 
57
77
  You can safely use it in ie. ActiveRecord::Base or Sequel::Model subclasses.
58
78
 
59
- #### Warning
60
-
61
- The encrypted data is not authenticated; it's intended to prevent
62
- opportunistic access to secrets by a third party which gets hold of a database
63
- dump. *IT DOES NOT prevent tampering.* If your threat model includes an attacker
64
- which can modify the database, `attr_encrypted` by itself IS NOT SECURE.
65
-
66
79
  ### Asymmetric encryption and signing
67
80
 
68
81
  ```ruby
@@ -14,7 +14,7 @@ module Slosilo
14
14
  def create_model
15
15
  model = Sequel::Model(:slosilo_keystore)
16
16
  model.unrestrict_primary_key
17
- model.attr_encrypted :key if secure?
17
+ model.attr_encrypted(:key, aad: :id) if secure?
18
18
  model
19
19
  end
20
20
 
@@ -5,21 +5,44 @@ module Slosilo
5
5
  # so we encrypt sensitive attributes before storing them
6
6
  module EncryptedAttributes
7
7
  module ClassMethods
8
+
9
+ # @param options [Hash]
10
+ # @option :aad [#to_proc, #to_s] Provide additional authenticated data for
11
+ # encryption. This should be something unique to the instance having
12
+ # this attribute, such as a primary key; this will ensure that an attacker can't swap
13
+ # values around -- trying to decrypt value with a different auth data will fail.
14
+ # This means you have to be able to recover it in order to decrypt attributes.
15
+ # The following values are accepted:
16
+ #
17
+ # * Something proc-ish: will be called with self each time auth data is needed.
18
+ # * Something stringish: will be to_s-d and used for all instances as auth data.
19
+ # Note that this will only prevent swapping in data using another string.
20
+ #
21
+ # The recommended way to use this option is to pass a proc-ish that identifies the record.
22
+ # Note the proc-ish can be a simple method name; for example in case of a Sequel::Model:
23
+ # attr_encrypted :secret, aad: :pk
8
24
  def attr_encrypted *a
25
+ options = a.last.is_a?(Hash) ? a.pop : {}
26
+ aad = options[:aad]
27
+ # note nil.to_s is "", which is exactly the right thing
28
+ auth_data = aad.respond_to?(:to_proc) ? aad.to_proc : proc{ |_| aad.to_s }
29
+ raise ":aad proc must take one argument" unless auth_data.arity.abs == 1 # take abs to allow *args arity, -1
30
+
9
31
  # push a module onto the inheritance hierarchy
10
32
  # this allows calling super in classes
11
33
  include(accessors = Module.new)
12
34
  accessors.module_eval do
13
35
  a.each do |attr|
14
36
  define_method "#{attr}=" do |value|
15
- super(EncryptedAttributes.encrypt value)
37
+ super(EncryptedAttributes.encrypt(value, aad: auth_data[self]))
16
38
  end
17
39
  define_method attr do
18
- EncryptedAttributes.decrypt(super())
40
+ EncryptedAttributes.decrypt(super(), aad: auth_data[self])
19
41
  end
20
42
  end
21
43
  end
22
44
  end
45
+
23
46
  end
24
47
 
25
48
  def self.included base
@@ -27,14 +50,14 @@ module Slosilo
27
50
  end
28
51
 
29
52
  class << self
30
- def encrypt value
53
+ def encrypt value, opts={}
31
54
  return nil unless value
32
- cipher.encrypt value, key: key
55
+ cipher.encrypt value, key: key, aad: opts[:aad]
33
56
  end
34
57
 
35
- def decrypt ctxt
58
+ def decrypt ctxt, opts={}
36
59
  return nil unless ctxt
37
- cipher.decrypt ctxt, key: key
60
+ cipher.decrypt ctxt, key: key, aad: opts[:aad]
38
61
  end
39
62
 
40
63
  def key
@@ -1,25 +1,40 @@
1
1
  module Slosilo
2
2
  class Symmetric
3
+ VERSION_MAGIC = 'G'
4
+ TAG_LENGTH = 16
5
+
3
6
  def initialize
4
- @cipher = OpenSSL::Cipher.new 'AES-256-CBC'
7
+ @cipher = OpenSSL::Cipher.new 'aes-256-gcm' # NB: has to be lower case for whatever reason.
5
8
  end
6
-
9
+
10
+ # This lets us do a final sanity check in migrations from older encryption versions
11
+ def cipher_name
12
+ @cipher.name
13
+ end
14
+
7
15
  def encrypt plaintext, opts = {}
8
16
  @cipher.reset
9
17
  @cipher.encrypt
10
- @cipher.key = opts[:key]
18
+ @cipher.key = (opts[:key] or raise("missing :key option"))
11
19
  @cipher.iv = iv = random_iv
12
- ctxt = @cipher.update(plaintext)
13
- iv + ctxt + @cipher.final
20
+ @cipher.auth_data = opts[:aad] || "" # Nothing good happens if you set this to nil, or don't set it at all
21
+ ctext = @cipher.update(plaintext) + @cipher.final
22
+ tag = @cipher.auth_tag(TAG_LENGTH)
23
+ "#{VERSION_MAGIC}#{tag}#{iv}#{ctext}"
14
24
  end
15
-
25
+
16
26
  def decrypt ciphertext, opts = {}
27
+ version, tag, iv, ctext = unpack ciphertext
28
+
29
+ raise "Invalid version magic: expected #{VERSION_MAGIC} but was #{version}" unless version == VERSION_MAGIC
30
+
17
31
  @cipher.reset
18
32
  @cipher.decrypt
19
33
  @cipher.key = opts[:key]
20
- @cipher.iv, ctxt = ciphertext.unpack("a#{@cipher.iv_len}a*")
21
- ptxt = @cipher.update(ctxt)
22
- ptxt + @cipher.final
34
+ @cipher.iv = iv
35
+ @cipher.auth_tag = tag
36
+ @cipher.auth_data = opts[:aad] || ""
37
+ @cipher.update(ctext) + @cipher.final
23
38
  end
24
39
 
25
40
  def random_iv
@@ -29,5 +44,11 @@ module Slosilo
29
44
  def random_key
30
45
  @cipher.random_key
31
46
  end
47
+
48
+ private
49
+ # return tag, iv, ctext
50
+ def unpack msg
51
+ msg.unpack "aa#{TAG_LENGTH}a#{@cipher.iv_len}a*"
52
+ end
32
53
  end
33
54
  end
@@ -1,3 +1,3 @@
1
1
  module Slosilo
2
- VERSION = "1.1.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+ require 'slosilo/attr_encrypted'
3
+
4
+ describe Slosilo::EncryptedAttributes do
5
+ before(:all) do
6
+ Slosilo::encryption_key = OpenSSL::Cipher.new("aes-256-gcm").random_key
7
+ end
8
+
9
+ let(:aad) { proc{ |_| "hithere" } }
10
+
11
+ let(:base){
12
+ Class.new do
13
+ attr_accessor :normal_ivar,:with_aad
14
+ def stupid_ivar
15
+ side_effect!
16
+ @_explicit
17
+ end
18
+ def stupid_ivar= e
19
+ side_effect!
20
+ @_explicit = e
21
+ end
22
+ def side_effect!
23
+
24
+ end
25
+ end
26
+ }
27
+
28
+ let(:sub){
29
+ Class.new(base) do
30
+ attr_encrypted :normal_ivar, :stupid_ivar
31
+ end
32
+ }
33
+
34
+ subject{ sub.new }
35
+
36
+ context "when setting a normal ivar" do
37
+ let(:value){ "some value" }
38
+ it "stores an encrypted value in the ivar" do
39
+ subject.normal_ivar = value
40
+ expect(subject.instance_variable_get(:"@normal_ivar")).to_not eq(value)
41
+ end
42
+
43
+ it "recovers the value set" do
44
+ subject.normal_ivar = value
45
+ expect(subject.normal_ivar).to eq(value)
46
+ end
47
+ end
48
+
49
+ context "when setting an attribute with an implementation" do
50
+ it "calls the base class method" do
51
+ expect(subject).to receive_messages(:side_effect! => nil)
52
+ subject.stupid_ivar = "hi"
53
+ expect(subject.stupid_ivar).to eq("hi")
54
+ end
55
+ end
56
+
57
+ context "when given an :aad option" do
58
+
59
+ let(:cipher){ Slosilo::EncryptedAttributes.cipher }
60
+ let(:key){ Slosilo::EncryptedAttributes.key}
61
+ context "that is a string" do
62
+ let(:aad){ "hello there" }
63
+ before{ sub.attr_encrypted :with_aad, aad: aad }
64
+ it "encrypts the value with the given string for auth data" do
65
+ expect(cipher).to receive(:encrypt).with("hello", key: key, aad: aad)
66
+ subject.with_aad = "hello"
67
+ end
68
+
69
+ it "decrypts the encrypted value" do
70
+ subject.with_aad = "foo"
71
+ expect(subject.with_aad).to eq("foo")
72
+ end
73
+ end
74
+
75
+ context "that is nil" do
76
+ let(:aad){ nil }
77
+ before{ sub.attr_encrypted :with_aad, aad: aad }
78
+ it "encrypts the value with an empty string for auth data" do
79
+ expect(cipher).to receive(:encrypt).with("hello",key: key, aad: "").and_call_original
80
+ subject.with_aad = "hello"
81
+ end
82
+
83
+ it "decrypts the encrypted value" do
84
+ subject.with_aad = "hello"
85
+ expect(subject.with_aad).to eq("hello")
86
+ end
87
+ end
88
+
89
+ context "that is a proc" do
90
+ let(:aad){
91
+ proc{ |o| "x" }
92
+ }
93
+
94
+ before{ sub.attr_encrypted :with_aad, aad: aad }
95
+
96
+ it "calls the proc with the object being encrypted" do
97
+ expect(aad).to receive(:[]).with(subject).and_call_original
98
+ subject.with_aad = "hi"
99
+ end
100
+
101
+ it "encrypts the value with the string returned for auth data" do
102
+ expect(cipher).to receive(:encrypt).with("hello", key: key, aad: aad[subject]).and_call_original
103
+ subject.with_aad = "hello"
104
+ end
105
+ it "decrypts the encrypted value" do
106
+ subject.with_aad = "hello"
107
+ expect(subject.with_aad).to eq("hello")
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+
114
+ end
data/spec/key_spec.rb CHANGED
@@ -77,8 +77,8 @@ describe Slosilo::Key do
77
77
  end
78
78
  end
79
79
 
80
- let(:ciphertext) { "\x8B\xE6\xEC\x8C\xAB\xA4\xC0\x8EF\"\x0F\xD5Yh\xA1\aq\x00\xF5\xAC\xAB\v\a\xEC\xF6G\xA6\e\x14N\xFF\x11\x98\xDA\x19\xB5\x8994_:\xA0\xF8\x06l\xDC\x9B\xB1\xE8z\x83\xCC\x9A\x02E\x02tOhu\x92F]h".force_encoding("ASCII-8BIT") }
81
- let(:skey) { "\x15\xFF\xD4>\x9C\xF4\x0F\xB6\x04C\x18\xC1\x96\xC3\xE0T\xA3\xF5\xE8\x17\xA6\xE0\x86~rrw\xC3\xDF\x11)$\x9B\r@\x0E\xE4Zv\rw-\xFC\x1C\x84\x17\xBD\xDB\x12u\xCD\r\xFEo\xD5\xC8[\x8FEA\\\xA9\xA2F#\x8BH -\xFA\xF7\xA9\xEBf\x97\xAAT}\x8E*\xC0r\x944p\xD0\x9A\xE7\xBD\a;O\f\xEF\xE4B.y\xFA\xB4e@O\xBB\x15>y\xC9\t=\x01\xE1J\xF3X\xA9\x9E3\x04^H\x1F\xFF\x19C\x93ve)@\xF7\t_\xCF\xDE\xF1\xB7]\x83lL\xB8%A\x93p{\xE9Y\xBAu\xCE\x99T\xDC\xDF\xE7\x0FD%\xB9AXb\x1CW\x94$P\xBB\xE1g\xDEE\t\xC4\x92\x9E\xFEt\xDF\xD0\xEA\x03\xC4\x12\xA9\x02~u\xF4\x92 ;\xA0\xCE.\b+)\x05\xEDo\xA5cF\xF8\x12\xD7F\x97\xE44\xBF\xF1@\xA5\xC5\xA8\xE5\a\xE8ra<\x04\xB5\xA2\f\t\xF7T\x97\e\xF5(^\xAB\xA5%84\x10\xD1\x13e<\xCA/\xBF}%\xF6\xB1%\xB2".force_encoding("ASCII-8BIT") }
80
+ let(:ciphertext){ "G\xAD^\x17\x11\xBBQ9-b\x14\xF6\x92#Q0x\xF4\xAD\x1A\x92\xC3VZW\x89\x8E\x8Fg\x93\x05B\xF8\xD6O\xCFGCTp\b~\x916\xA3\x9AN\x8D\x961\x1F\xA3mSf&\xAD\xA77/]z\xA89\x01\xA7\xA9\x92\f".force_encoding('ASCII-8BIT') }
81
+ let(:skey){ "\x82\x93\xFAA\xA6wQA\xE1\xB5\xA6b\x8C.\xCF#I\x86I\x83u\x99\rTA\xEF\xC4\x91\xC5)-\xEBQ\xB1\xC0\xC6\xFF\x90L\xFE\x1E\x15\x81\x12\x16\xDD:A\xC5d\xE1B\xD2f@\xB8o\xB7+N\xB7\n\x92\xDC\x9E\xE3\x83\xB8>h\a\xC7\xCC\xCF\xD0t\x06\x8B\xA8\xBF\xEFe\xA4{\x88\f\xDD\roF\xEB.\xDA\xBF\x9D_0>\xF03c'\x1F!)*-\x19\x97\xAC\xD2\x1F(,6h\a\x93\xDB\x8E\x97\xF9\x1A\x11\x84\x11t\xD9\xB2\x85\xB0\x12\x7F\x03\x00O\x8F\xBE#\xFFb\xA5w\xF3g\xCF\xB4\xF2\xB7\xDBiA=\xA8\xFD1\xEC\xBF\xD7\x8E\xB6W>\x03\xACNBa\xBF\xFD\xC6\xB32\x8C\xE2\xF1\x87\x9C\xAE6\xD1\x12\vkl\xBB\xA0\xED\x9A\xEE6\xF2\xD9\xB4LL\xE2h/u_\xA1i=\x11x\x8DGha\x8EG\b+\x84[\x87\x8E\x01\x0E\xA5\xB0\x9F\xE9vSl\x18\xF3\xEA\xF4NH\xA8\xF1\x81\xBB\x98\x01\xE8p]\x18\x11f\xA3K\xA87c\xBB\x13X~K\xA2".force_encoding('ASCII-8BIT') }
82
82
  describe '#decrypt' do
83
83
  it "decrypts the symmetric key and then uses it to decrypt the ciphertext" do
84
84
  expect(subject.decrypt(ciphertext, skey)).to eq(plaintext)
@@ -3,34 +3,56 @@ require 'spec_helper'
3
3
  describe Slosilo::Symmetric do
4
4
  # TODO transform it to class methods only?
5
5
  let(:plaintext) { "quick brown fox jumped over the lazy dog" }
6
+ let(:auth_data) { "some record id" }
6
7
  let(:key) { "^\xBAIv\xDB1\x0Fi\x04\x11\xFD\x14\xA7\xCD\xDFf\x93\xFE\x93}\v\x01\x11\x98\x14\xE0;\xC1\xE2 v\xA5".force_encoding("ASCII-8BIT") }
7
- let(:iv) { "\xA1\xFA#z\x16\x80R\xCC|\x0Fyc\xB7j\x17\xED".force_encoding("ASCII-8BIT") }
8
- let(:ciphertext) { "\xA1\xFA#z\x16\x80R\xCC|\x0Fyc\xB7j\x17\xED\x15\xC9r\xC9\xEE\xB9\xBC5\xB7\ni\x0F\f\xC8X\x80 h\a\xF4\xA6\xE3\x15\x9D\xF1-\xE5\bs\xF6\x02Z\x0F\xCD|S\x1A\xAA\x9At\xEFT\x17\xA5lT\x8C\xF3".force_encoding("ASCII-8BIT") }
8
+ let(:iv) { "\xD9\xABn\x01b\xFA\xBD\xC2\xE5\xEA\x01\xAC".force_encoding("ASCII-8BIT") }
9
+ let(:ciphertext) { "G^W1\x9C\xD4\xCC\x87\xD3\xFF\x86[\x0E3\xC0\xC8^\xD9\xABn\x01b\xFA\xBD\xC2\xE5\xEA\x01\xAC\x9E\xB9:\xF7\xD4ebeq\xDC \xC0sG\xA4\xAE,\xB8A|\x97\xBC\xFD\x85\xE1\xB93\x95>\xBD\n\x05\xFB\x15\x1F\x06#3M9".force_encoding('ASCII-8BIT') }
10
+
9
11
  describe '#encrypt' do
10
- it "encrypts with AES-256-CBC" do
12
+ it "encrypts with AES-256-GCM" do
11
13
  allow(subject).to receive_messages random_iv: iv
12
- expect(subject.encrypt(plaintext, key: key)).to eq(ciphertext)
14
+ expect(subject.encrypt(plaintext, key: key, aad: auth_data)).to eq(ciphertext)
13
15
  end
14
16
  end
15
17
 
16
18
  describe '#decrypt' do
17
- it "decrypts with AES-256-CBC" do
18
- expect(subject.decrypt(ciphertext, key: key)).to eq(plaintext)
19
+ it "decrypts with AES-256-GCM" do
20
+ expect(subject.decrypt(ciphertext, key: key, aad: auth_data)).to eq(plaintext)
21
+ end
22
+
23
+
24
+ context "when the ciphertext has been messed with" do
25
+ let(:ciphertext) { "pwnd!" } # maybe we should do something more realistic like add some padding?
26
+ it "raises an exception" do
27
+ expect{ subject.decrypt(ciphertext, key: key, aad: auth_data)}.to raise_exception
28
+ end
29
+ context "by adding a trailing 0" do
30
+ let(:new_ciphertext){ ciphertext + '\0' }
31
+ it "raises an exception" do
32
+ expect{ subject.decrypt(new_ciphertext, key: key, aad: auth_data) }.to raise_exception
33
+ end
34
+ end
19
35
  end
20
-
21
- context "when ciphertext happens to end in a zero" do
22
- let(:ciphertext) { "\x7F\xD6\xEAb\xE56\a\xD3\xC5\xF2J\n\x8C\x8Fg\xB7-\\\x8A\fh\x18\xC8\x91\xB9 \x97\xC9\x12\xE6\xA6\xAE\xB1I\x1E\x80\xAB\xD8\xDC\xBD\xB6\xCD\x9A\xA3MH\xA8\xB0\xC7\xDA\x87\xA7c\xD75,\xD2A\xB8\x9E\xE3o\x04\x00" }
23
- let(:key) { "4pSuk1rAQyuHA5uUYaj0X0BsiPCFb9Nc8J03XA6V5/Y" }
24
- it "works correctly" do
25
- expect(subject.decrypt(ciphertext, key: key)).to eq("R6KNTQ4aUivojbaqhgAqj1I4PaF8h/5/YcENy4uNbfk=")
36
+
37
+ context "when no auth_data is given" do
38
+ let(:auth_data){""}
39
+ let(:ciphertext){ "Gm\xDAT\xE8I\x9F\xB7\xDC\xBB\x84\xD3Q#\x1F\xF4\x8C\aV\x93\x8F_\xC7\xBC87\xC9U\xF1\xAF\x8A\xD62\x1C5H\x86\x17\x19=B~Y*\xBC\x9D\eJeTx\x1F\x02l\t\t\xD3e\xA4\x11\x13y*\x95\x9F\xCD\xC4@\x9C"}
40
+
41
+ it "decrypts the message" do
42
+ expect(subject.decrypt(ciphertext, key: key, aad: auth_data)).to eq(plaintext)
43
+ end
44
+
45
+ context "and the ciphertext has been messed with" do
46
+ it "raises an exception" do
47
+ expect{ subject.decrypt(ciphertext + "\0\0\0", key: key, aad: auth_data)}.to raise_exception
48
+ end
26
49
  end
27
50
  end
28
51
 
29
- context "when the iv ends in space" do
30
- let(:ciphertext) { "\xC0\xDA#\xE9\xE1\xFD\xEDJ\xADs4P\xA9\xD6\x92 \xF7\xF8_M\xF6\x16\xC2i$\x8BT^\b\xA1\xB2L&\xE9\x80\x02[]6i\x9B\xD3\xC3\xED\xA9\xD1\x94\xE8\x15\xFD\xDA\xFEUj\xC5upH*\xBF\x82\x15le" }
31
- let(:key) { "4pSuk1rAQyuHA5uUYaj0X0BsiPCFb9Nc8J03XA6V5/Y" }
32
- it "works correctly" do
33
- expect(subject.decrypt(ciphertext, key: key)).to eq("zGptmL3vd4obi1vqSiWHt/Ias2k+6qDtuq9vdow8jNA=")
52
+ context "when the auth data doesn't match" do
53
+ let(:auth_data){ "asdf" }
54
+ it "raises an exception" do
55
+ expect{ subject.decrypt(ciphertext, key: key, aad: auth_data)}.to raise_exception
34
56
  end
35
57
  end
36
58
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slosilo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafał Rzepecki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-20 00:00:00.000000000 Z
11
+ date: 2014-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -138,6 +138,7 @@ files:
138
138
  - lib/slosilo/version.rb
139
139
  - lib/tasks/slosilo.rake
140
140
  - slosilo.gemspec
141
+ - spec/encrypted_attributes_spec.rb
141
142
  - spec/file_adapter_spec.rb
142
143
  - spec/key_spec.rb
143
144
  - spec/keystore_spec.rb
@@ -166,11 +167,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
167
  version: '0'
167
168
  requirements: []
168
169
  rubyforge_project:
169
- rubygems_version: 2.2.2
170
+ rubygems_version: 2.0.14
170
171
  signing_key:
171
172
  specification_version: 4
172
173
  summary: Store SSL keys in a database
173
174
  test_files:
175
+ - spec/encrypted_attributes_spec.rb
174
176
  - spec/file_adapter_spec.rb
175
177
  - spec/key_spec.rb
176
178
  - spec/keystore_spec.rb