rom_encrypted_attribute 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4fa68f6b6119a75fb160eed6c69ecb341f0966e09b2e1e2d234d0ce20e1f2a1c
4
- data.tar.gz: 4f33329807bc3337d001ebe8c4840ae10ed70272db064343588fc38c444f0452
3
+ metadata.gz: a969ae5d8669ac0bba27f0ba1aeb8ad53b42962c4a63dea849033f3398ea0048
4
+ data.tar.gz: 752b299f84b9a569983e7b937fb8588f404572032d4fd58d64a022399ffbeb98
5
5
  SHA512:
6
- metadata.gz: 3ca2ba7ffdb4b96fdc97ca403100bd996593724953a9938483619f82916d62ac7a2c7161e19401fef5cad66837ea6571235dc8064cdb0a7aace0aae3a1776453
7
- data.tar.gz: cc3dc7e8b45d235d5fdf10cd069b84c9ee8a590fcc9247d6df36fedf3529634980c95a32b5978030294cd36ed26858aea4ca4ad97b5debcf1f957dffacfe0957
6
+ metadata.gz: a8a2e9a6dbebf654fff5349968e66b8a77909720ffedafeb1dfa9e7232d789c758123c36f078266fd6895fbacebed1d79a8aa78e439450bcb437cd6cbcdbfe80
7
+ data.tar.gz: 414fbbf17de5976ec4940f1d4244dc215f1b6ebfb3d4b98d80c2c72ba574c9ebe79a48d5db1b8960ef302f3320afcf1e6e19ee1845d228c81865c4b09587b14e
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # RomEncryptedAttribute
2
2
 
3
- This gem adds support for encrypted fields using [ROM](https://rom-rb.org/).
3
+ This gem adds support for encrypted attributes to [ROM](https://rom-rb.org/).
4
4
 
5
- Traditionally ROM suggested to put encryption logic in repository code (more precisely, in the mapper from database struct to an entity). I personally think this is not the greatest idea. Repository lies logically in application layer (or even domain layer), while encryption and decryption of data is a purely infrastructure concern. As such, it should be as low-level and hidden as possible.
5
+ Traditionally ROM team [suggested](https://discourse.rom-rb.org/t/question-encryption-support-thoughts/387) to put encryption logic in repository code (more precisely, in the mapper from database struct to an entity). I personally think this is not the greatest idea. Repository lies logically in the application layer (or even domain layer), while encryption and decryption of data is a purely infrastructure concern. As such, it should be as low-level and hidden as possible.
6
6
 
7
- In ROM terms it means doing it in a relation. This gem uses custom types to achieve encryption and decryption.
7
+ In ROM terms it means doing it in a relation. The gem leverages custom types to achieve encryption and decryption.
8
8
 
9
- The scheme is compatible with Rails' default settings for ActiveRecord encryption, so you can still read encrypted records as long as you provide the same primary key and salt derivation key.
9
+ The scheme is compatible with Rails' default settings for ActiveRecord encryption, so you can still read records encrypted with ActiveRecord from ROM (and vice versa) as long as you provide the same primary key and key derivation salt.
10
10
 
11
11
  ## Installation
12
12
 
@@ -27,7 +27,7 @@ class SecretNotes < ROM::Relation[:sql]
27
27
  EncryptedString, EncryptedStringReader =
28
28
  RomEncryptedAttribute.define_encrypted_attribute_types(
29
29
  primary_key: ENV["ENCRYPTION_PRIMARY_KEY"],
30
- derivation_salt: ENV["ENCRYPTION_DERIVATION_SALT"]
30
+ key_derivation_salt: ENV["ENCRYPTION_KEY_DERIVATION_SALT"]
31
31
  )
32
32
 
33
33
  schema(:secret_notes, infer: true) do
@@ -42,7 +42,7 @@ Of course, you can define it somewhere else and just `include` in the relation o
42
42
 
43
43
  * Due to a bug in `rom-sql`, reading unencrypted data is turned on by default
44
44
  * The gem uses SHA256 for key derivation and it's currently not configurable
45
- * Support for deterministic encryption from `ActiveRecord::Entryption` is not implemented
45
+ * Support for deterministic encryption from `ActiveRecord::Encryption` is not implemented
46
46
 
47
47
  ## Contributing
48
48
 
@@ -3,6 +3,7 @@
3
3
  require "base64"
4
4
  require "json"
5
5
  require_relative "key_derivator"
6
+ require_relative "payload"
6
7
 
7
8
  module RomEncryptedAttribute
8
9
  class Decryptor
@@ -11,10 +12,7 @@ module RomEncryptedAttribute
11
12
  end
12
13
 
13
14
  def decrypt(message)
14
- message = JSON.parse(message)
15
- data = Base64.strict_decode64(message["p"])
16
- iv = Base64.strict_decode64(message["h"]["iv"])
17
- auth_tag = Base64.strict_decode64(message["h"]["at"])
15
+ payload = RomEncryptedAttribute::Payload.decode(message)
18
16
 
19
17
  cipher = OpenSSL::Cipher.new("aes-256-gcm")
20
18
  key = @derivator.derive(cipher.key_len)
@@ -22,10 +20,10 @@ module RomEncryptedAttribute
22
20
  cipher.decrypt
23
21
  cipher.padding = 0
24
22
  cipher.key = key
25
- cipher.iv = iv
26
- cipher.auth_tag = auth_tag
23
+ cipher.iv = payload.initialization_vector
24
+ cipher.auth_tag = payload.auth_tag
27
25
  cipher.auth_data = ""
28
- cipher.update(data) + cipher.final
26
+ cipher.update(payload.message) + cipher.final
29
27
  rescue JSON::ParserError
30
28
  # we need to unconditionally support of reading unencrypted data due to a bug in rom-sql
31
29
  # https://github.com/rom-rb/rom-sql/issues/423
@@ -4,6 +4,7 @@ require "base64"
4
4
  require "json"
5
5
  require "openssl"
6
6
  require_relative "key_derivator"
7
+ require_relative "payload"
7
8
 
8
9
  module RomEncryptedAttribute
9
10
  class Encryptor
@@ -20,22 +21,7 @@ module RomEncryptedAttribute
20
21
  cipher.key = key
21
22
  cipher.iv = iv
22
23
  encrypted = cipher.update(message) + cipher.final
23
- serialize(encrypted, cipher: cipher, iv: iv)
24
- end
25
-
26
- private
27
-
28
- def serialize(encrypted, iv:, cipher:)
29
- payload =
30
- {
31
- "p" => Base64.strict_encode64(encrypted),
32
- "h" => {
33
- "iv" => Base64.strict_encode64(iv),
34
- "at" => Base64.strict_encode64(cipher.auth_tag)
35
- }
36
- }
37
-
38
- JSON.dump(payload)
24
+ Payload.new(message: encrypted, initialization_vector: iv, auth_tag: cipher.auth_tag).encode
39
25
  end
40
26
  end
41
27
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/types"
4
+ require "dry/struct"
5
+ require "base64"
6
+
7
+ class RomEncryptedAttribute::Payload < Dry::Struct
8
+ class Types
9
+ include Dry.Types()
10
+ end
11
+
12
+ attribute :message, Types::Strict::String
13
+ attribute :initialization_vector, Types::Strict::String
14
+ attribute :auth_tag, Types::Strict::String
15
+
16
+ def self.decode(database_value)
17
+ payload = JSON.parse(database_value)
18
+ new(
19
+ message: decode64(payload["p"]),
20
+ initialization_vector: decode64(payload.dig("h", "iv")),
21
+ auth_tag: decode64(payload.dig("h", "at"))
22
+ )
23
+ end
24
+
25
+ def self.decode64(value)
26
+ Base64.strict_decode64(value)
27
+ end
28
+
29
+ def encode
30
+ payload =
31
+ {
32
+ "p" => encode64(message),
33
+ "h" => {
34
+ "iv" => encode64(initialization_vector),
35
+ "at" => encode64(auth_tag)
36
+ }
37
+ }
38
+
39
+ JSON.dump(payload)
40
+ end
41
+
42
+ private
43
+
44
+ def encode64(value)
45
+ Base64.strict_encode64(value)
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RomEncryptedAttribute
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.2"
5
5
  end
@@ -7,13 +7,13 @@ require_relative "rom_encrypted_attribute/version"
7
7
  require "dry/types"
8
8
 
9
9
  module RomEncryptedAttribute
10
- def self.define_encrypted_attribute_types(primary_key:, derivation_salt:)
10
+ def self.define_encrypted_attribute_types(primary_key:, key_derivation_salt:)
11
11
  reader_type = Dry.Types.Constructor(String) do |value|
12
- RomEncryptedAttribute::Decryptor.new(secret: primary_key, salt: derivation_salt).decrypt(value)
12
+ RomEncryptedAttribute::Decryptor.new(secret: primary_key, salt: key_derivation_salt).decrypt(value)
13
13
  end
14
14
 
15
15
  writer_type = Dry.Types.Constructor(String) do |value|
16
- RomEncryptedAttribute::Encryptor.new(secret: primary_key, salt: derivation_salt).encrypt(value)
16
+ RomEncryptedAttribute::Encryptor.new(secret: primary_key, salt: key_derivation_salt).encrypt(value)
17
17
  end
18
18
 
19
19
  [writer_type, reader_type]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom_encrypted_attribute
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paweł Świątkowski
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-07 00:00:00.000000000 Z
11
+ date: 2023-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-types
@@ -82,6 +82,7 @@ files:
82
82
  - lib/rom_encrypted_attribute/decryptor.rb
83
83
  - lib/rom_encrypted_attribute/encryptor.rb
84
84
  - lib/rom_encrypted_attribute/key_derivator.rb
85
+ - lib/rom_encrypted_attribute/payload.rb
85
86
  - lib/rom_encrypted_attribute/version.rb
86
87
  - rom_encrypted_attribute.gemspec
87
88
  homepage: