serket 0.1.2 → 0.2.0

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
  SHA1:
3
- metadata.gz: 5ba69de85b66353c39bb9ab36bbe137c03096ace
4
- data.tar.gz: 9992acd318cbc1aa4d739fcc6224f1bd71189314
3
+ metadata.gz: 9add635d8b06b59c7bc47526c0b22b90b9bedd17
4
+ data.tar.gz: b357446a204828c351bee22546f4e4f1365d8fe6
5
5
  SHA512:
6
- metadata.gz: c8e7853161ae2026ec1eb2051000263c0da21ec2e171d01fde51d60900ce64c22c5c32fc83c66725c74ad873a8df79bcf0d401b40b71aebe6985a8104355678c
7
- data.tar.gz: d01c0d8e9154170783a00cf2bccac560fdde8b4703428de75a7b26a1cc6be370ddbaf6215b4c5d1c151cc244fea4ecaf3d6382eb7011a85479247e1f51030dcf
6
+ metadata.gz: 6c613a58ca1b059019288a0240a44901d97697ab5fa6f76755a6c31816dcffe0b2ebaaf4e3f58c7487e20336ed927229bd77e282e1423cf2be890e24e7db91b1
7
+ data.tar.gz: d203cd2cc7363a52aee031cf942d96d01e8eb37d66f8080111d881a619217e5e90f0db4d99acf67d228dc7dc5e1e541503c47dfc326eb2447d7fb57599cd3335
data/README.md CHANGED
@@ -76,6 +76,7 @@ There are a few more configuration options.
76
76
  | format | :delimited | :delimited, :json |
77
77
  | symmetric_algorithm | AES-256-CBC | Any valid cipher from OpenSSL::Cipher |
78
78
  | delimiter | :: | Anything not base64 |
79
+ | encoding | utf-8 | Any valid ruby encoding |
79
80
 
80
81
  These can all be modified in the configuration block, eg:
81
82
 
@@ -126,6 +127,15 @@ Serket.configure do |config|
126
127
  end
127
128
  ```
128
129
 
130
+ You can do a sanity-check with your api endpoint by sending a post request for a model with decrypted_fields:
131
+ ```
132
+ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"decrypted_model": {"name": "bm5gkjwdfv6QBUqFPEnOaw==::CtQJyXdbuLeVzmIOIr0h/F9yh7xvz5KWUgxe/u4IkORGOW4KjU4bw+Wzve2vV1nLYUEWJJprr8sb+grm+Ao2sngNejiHzSkJKqZA/Pclw/Ok8KgHgN7olUz4BoCSdivIDRIT9ar06sNBrqOvLd4iGUlpMkpLdSJ69K08ebSvg5tED+PcK/oI6SJoVxRoUMYdYa9AfeIS9Ld5BgvhsaJgCKr089kfH2CzwpzlmRfdxb2qgyDXnk9PG/4WUEjjbamF/R74FNBdWkTLxZeLGdMImh87CQ6AOJ/v8l1JSzpPWwEjtmhTbFEzJPuA01tP5U5D07si0esJnab/B48iACEoLg==::iSmdDgnTzkEUv0yLbtFa8Q=="}}' http://localhost:3000/api/v1/decrypted_models
133
+ ```
134
+
135
+ This should automatically decrypt the name for the decrypted_model before saving if you use the provided private key located in spec/resources/test_private_key.pem (and keep the default configs for delimited with ::)
136
+
137
+ **Just be sure to use your own keys in production!**
138
+
129
139
  ### Android Java Client
130
140
 
131
141
  You can see an example java client for use with Android in EncryptUtil.java
@@ -1,11 +1,23 @@
1
1
  module Serket
2
+ # Controls various configuration options such as key locations, desired
3
+ # algorithms and expected cipher text format.
4
+ #
5
+ # * +private_key_path+ - The filepath to a RSA private key
6
+ # * +public_key_path+ - The filepath to a RSA public key
7
+ # * +delimiter+ - If the format is set to :delimited, use this delimiter.
8
+ # Must not be a character in base64.
9
+ # * +format+ - May be :delimited or :json
10
+ # * +symmetric_algorithm+ - May be any algorithm that may be used with OpenSSL::Cipher
11
+ # * +encoding+ - Any valid ruby encoding
12
+ #
2
13
  class Configuration
3
- attr_accessor :private_key_path, :public_key_path, :delimiter, :format, :symmetric_algorithm
14
+ attr_accessor :private_key_path, :public_key_path, :delimiter, :format, :symmetric_algorithm, :encoding
4
15
 
5
16
  def initialize
6
17
  @delimiter = "::"
7
18
  @format = :delimited
8
19
  @symmetric_algorithm = 'AES-256-CBC'
20
+ @encoding = 'utf-8'
9
21
  end
10
22
  end
11
23
  end
@@ -1,4 +1,23 @@
1
1
  module Serket
2
+ # If a class extends DecryptedFields, then the getter method will be overridden
3
+ # for each attribute that is listed.
4
+ #
5
+ # For example:
6
+ #
7
+ # class Person
8
+ # extend Serket::DecryptedFields
9
+ #
10
+ # decrypted_fields :name, :email
11
+ # end
12
+ #
13
+ # This will create a method name=(value) and email=(value)
14
+ #
15
+ # It assumes the encrypted name and email will be assigned to an
16
+ # instance of person, and will automatically decrypt the encrypted
17
+ # value using the configured private key.
18
+ #
19
+ # This currently relies on the write_attribute, which is available in
20
+ # ActiveRecord::Base. This currently is only intended for use with rails.
2
21
  module DecryptedFields
3
22
  def decrypted_fields(*fields)
4
23
  fields.each do |field|
@@ -1,4 +1,24 @@
1
1
  module Serket
2
+ # If a class extends EncryptedFields, then the getter method will be overridden
3
+ # for each attribute that is listed.
4
+ #
5
+ # For example:
6
+ #
7
+ # class Person
8
+ # extend Serket::EncryptedFields
9
+ #
10
+ # encrypted_fields :name, :email
11
+ # end
12
+ #
13
+ # This will create a method name=(value) and email=(value)
14
+ #
15
+ # When a value is assigned to name or email for a given person instance,
16
+ # it will automatically generate an encrypted version using the
17
+ # currently configured public key, and will store the cipher text instead
18
+ # of the plaintext value that was assigned.
19
+ #
20
+ # This currently relies on the write_attribute, which is available in
21
+ # ActiveRecord::Base. This currently is only intended for use with rails.
2
22
  module EncryptedFields
3
23
  def encrypted_fields(*fields)
4
24
  fields.each do |field|
@@ -2,8 +2,10 @@ require 'openssl'
2
2
  require 'base64'
3
3
 
4
4
  module Serket
5
+ # Used to decrypt a field given a private key, field delimiter, symmetric
6
+ # algorithm, encoding, and format (:json or :delimited)
5
7
  class FieldDecrypter
6
- attr_accessor :field_delimiter, :private_key_filepath, :symmetric_algorithm
8
+ attr_accessor :field_delimiter, :private_key_filepath, :symmetric_algorithm, :encoding
7
9
 
8
10
  def initialize(options = {})
9
11
  options ||= {}
@@ -12,16 +14,23 @@ module Serket
12
14
  @field_delimiter = options[:field_delimiter] || Serket.configuration.delimiter
13
15
  @symmetric_algorithm = options[:symmetric_algorithm] || Serket.configuration.symmetric_algorithm
14
16
  @format = options[:format] || Serket.configuration.format
17
+ @encoding = options[:encoding] || Serket.configuration.encoding
15
18
  end
16
19
 
20
+ # Decrypt the provided cipher text, and return the plaintext
21
+ # Return nil if whitespace
17
22
  def decrypt(field)
18
23
  return if field !~ /\S/
19
24
  iv, encrypted_aes_key, encrypted_text = parse(field)
20
25
  private_key = OpenSSL::PKey::RSA.new(File.read(private_key_filepath))
21
26
  decrypted_aes_key = private_key.private_decrypt(Base64.decode64(encrypted_aes_key))
22
- decrypt_data(iv, decrypted_aes_key, encrypted_text)
27
+ decrypted_field = decrypt_data(iv, decrypted_aes_key, encrypted_text)
28
+ decrypted_field.force_encoding(encoding)
23
29
  end
24
30
 
31
+ # What delimiter to use if the format is :delimited.
32
+ #
33
+ # Allow anything that is not base64.
25
34
  def field_delimiter=(delimiter)
26
35
  if delimiter =~ /[A-Za-z0-9\/+]/
27
36
  raise "This is not a valid delimiter! Must not be a character in Base64."
@@ -39,6 +48,14 @@ module Serket
39
48
  aes.update(Base64.decode64(encrypted_text)) + aes.final
40
49
  end
41
50
 
51
+ # Extracts the initialization vector, encrypted key, and
52
+ # cipher text according to the specified format.
53
+ #
54
+ # delimited:
55
+ # * Expected format: iv::encrypted-key::ciphertext
56
+ #
57
+ # json:
58
+ # * Expected keys: iv, key, message
42
59
  def parse(field)
43
60
  case @format
44
61
  when :delimited
@@ -2,26 +2,32 @@ require 'openssl'
2
2
  require 'base64'
3
3
 
4
4
  module Serket
5
+ # Used to encrypt a field given a public key, field delimiter, symmetric
6
+ # algorithm, encoding and format (:json or :delimited)
5
7
  class FieldEncrypter
6
- attr_accessor :field_delimiter, :public_key_filepath, :symmetric_algorithm
8
+ attr_accessor :field_delimiter, :public_key_filepath, :symmetric_algorithm, :encoding
7
9
 
8
10
  def initialize(options = {})
9
11
  options ||= {}
10
12
 
11
- @public_key_filepath = Serket.configuration.public_key_path
13
+ @public_key_filepath = Serket.configuration.public_key_path
12
14
  @field_delimiter = options[:field_delimiter] || Serket.configuration.delimiter
13
15
  @symmetric_algorithm = options[:symmetric_algorithm] || Serket.configuration.symmetric_algorithm
14
16
  @format = options[:format] || Serket.configuration.format
17
+ @encoding = options[:encoding] || Serket.configuration.encoding
15
18
  end
16
19
 
20
+ # Return encrypted string according to specified format.
21
+ # Return nil if field is whitespace.
17
22
  def encrypt(field)
18
23
  return if field !~ /\S/
19
24
  aes = OpenSSL::Cipher.new(symmetric_algorithm)
20
25
  aes_key = aes.random_key
21
26
  iv = aes.random_iv
22
- encrypt_data(iv, aes_key, field)
27
+ encrypt_data(iv, aes_key, field.force_encoding(encoding))
23
28
  end
24
29
 
30
+ # Allow any field delimiter except a base64 character.
25
31
  def field_delimiter=(delimiter)
26
32
  if delimiter =~ /[A-Za-z0-9\/+]/
27
33
  raise "This is not a valid delimiter! Must not be a character in Base64."
@@ -44,6 +50,8 @@ module Serket
44
50
  parse(Base64.encode64(iv), Base64.encode64(encrypted_aes_key), Base64.encode64(encrypted_text))
45
51
  end
46
52
 
53
+ # Format the final encrypted string to be returned depending
54
+ # on specified format.
47
55
  def parse(iv, encrypted_key, encrypted_text)
48
56
  case @format
49
57
  when :delimited
@@ -1,3 +1,3 @@
1
1
  module Serket
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -34,4 +34,24 @@ describe Serket::FieldEncrypter do
34
34
  @parsed_json.has_key?('message').should be_true
35
35
  end
36
36
  end
37
+
38
+ describe "encoding" do
39
+ it "should encrypt and decrypt an accent character" do
40
+ characters = %w(á é í ó ú ü ñ ¿ ¡)
41
+ characters.each do |c|
42
+ encrypted = @field_encrypter.encrypt(c)
43
+ decrypted = @field_decrypter.decrypt(encrypted)
44
+ c.should == decrypted
45
+ end
46
+ end
47
+
48
+ it "should encrypt and decrypt khmer" do
49
+ characters = %w(ឃ ង ទ ម វ ស )
50
+ characters.each do |c|
51
+ encrypted = @field_encrypter.encrypt(c)
52
+ decrypted = @field_decrypter.decrypt(encrypted)
53
+ c.should == decrypted
54
+ end
55
+ end
56
+ end
37
57
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Nipper