slosilo 0.0.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.gitignore +0 -2
  2. data/LICENSE +2 -2
  3. data/README.md +8 -128
  4. data/lib/slosilo/adapters/abstract_adapter.rb +0 -4
  5. data/lib/slosilo/adapters/mock_adapter.rb +1 -14
  6. data/lib/slosilo/adapters/sequel_adapter/migration.rb +2 -5
  7. data/lib/slosilo/adapters/sequel_adapter.rb +5 -67
  8. data/lib/slosilo/attr_encrypted.rb +7 -33
  9. data/lib/slosilo/http_request.rb +59 -0
  10. data/lib/slosilo/key.rb +6 -129
  11. data/lib/slosilo/keystore.rb +12 -40
  12. data/lib/slosilo/rack/middleware.rb +123 -0
  13. data/lib/slosilo/symmetric.rb +17 -47
  14. data/lib/slosilo/version.rb +2 -21
  15. data/lib/slosilo.rb +2 -2
  16. data/lib/tasks/slosilo.rake +0 -10
  17. data/slosilo.gemspec +6 -19
  18. data/spec/http_request_spec.rb +107 -0
  19. data/spec/http_stack_spec.rb +44 -0
  20. data/spec/key_spec.rb +32 -175
  21. data/spec/keystore_spec.rb +2 -15
  22. data/spec/rack_middleware_spec.rb +109 -0
  23. data/spec/random_spec.rb +2 -12
  24. data/spec/sequel_adapter_spec.rb +22 -133
  25. data/spec/slosilo_spec.rb +12 -78
  26. data/spec/spec_helper.rb +15 -37
  27. data/spec/symmetric_spec.rb +26 -69
  28. metadata +51 -104
  29. checksums.yaml +0 -7
  30. data/.github/CODEOWNERS +0 -10
  31. data/.gitleaks.toml +0 -221
  32. data/.kateproject +0 -4
  33. data/CHANGELOG.md +0 -50
  34. data/CONTRIBUTING.md +0 -16
  35. data/Jenkinsfile +0 -132
  36. data/SECURITY.md +0 -42
  37. data/dev/Dockerfile.dev +0 -7
  38. data/dev/docker-compose.yml +0 -8
  39. data/lib/slosilo/adapters/file_adapter.rb +0 -42
  40. data/lib/slosilo/adapters/memory_adapter.rb +0 -31
  41. data/lib/slosilo/errors.rb +0 -15
  42. data/lib/slosilo/jwt.rb +0 -122
  43. data/publish.sh +0 -5
  44. data/secrets.yml +0 -1
  45. data/spec/encrypted_attributes_spec.rb +0 -114
  46. data/spec/file_adapter_spec.rb +0 -81
  47. data/spec/jwt_spec.rb +0 -102
  48. data/test.sh +0 -8
data/.gitignore CHANGED
@@ -17,5 +17,3 @@ test/version_tmp
17
17
  tmp
18
18
  .rvmrc
19
19
  .project
20
- .kateproject.d
21
- .idea
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2020 CyberArk Software Ltd. All rights reserved.
1
+ Copyright (c) 2012 Rafał Rzepecki
2
2
 
3
3
  MIT License
4
4
 
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,11 +1,7 @@
1
1
  # Slosilo
2
2
 
3
- Slosilo is providing a ruby interface to some cryptographic primitives:
4
- - symmetric encryption,
5
- - a mixin for easy encryption of object attributes,
6
- - asymmetric encryption and signing,
7
- - a keystore in a postgres sequel db -- it allows easy storage and retrieval of keys,
8
- - a keystore in files.
3
+ Slosilo is a keystore in the database. (Currently only works with postgres.)
4
+ It allows easy storage and retrieval of keys.
9
5
 
10
6
  ## Installation
11
7
 
@@ -17,121 +13,6 @@ And then execute:
17
13
 
18
14
  $ bundle
19
15
 
20
- ## Compatibility
21
-
22
- Version 3.0 introduced full transition to Ruby 3.
23
- Consumers who use slosilo in Ruby 2 projects, shall use slosilo V2.X.X.
24
-
25
- Version 2.0 introduced new symmetric encryption scheme using AES-256-GCM
26
- for authenticated encryption. It allows you to provide AAD on all symmetric
27
- encryption primitives. It's also **NOT COMPATIBLE** with CBC used in version <2.
28
-
29
- This means you'll have to migrate all your existing data. There's no easy way to
30
- do this currently provided; it's recommended to create a database migration and
31
- put relevant code fragments in it directly. (This will also have the benefit of making
32
- the migration self-contained.)
33
-
34
- Since symmetric encryption is used in processing asymetrically encrypted messages,
35
- this incompatibility extends to those too.
36
-
37
- ## Usage
38
-
39
- ### Symmetric encryption
40
-
41
- ```ruby
42
- sym = Slosilo::Symmetric.new
43
- key = sym.random_key
44
- # additional authenticated data
45
- message_id = "message 001"
46
- ciphertext = sym.encrypt "secret message", key: key, aad: message_id
47
- ```
48
-
49
- ```ruby
50
- sym = Slosilo::Symmetric.new
51
- message = sym.decrypt ciphertext, key: key, aad: message_id
52
- ```
53
-
54
- ### Encryption mixin
55
-
56
- ```ruby
57
- require 'slosilo'
58
-
59
- class Foo
60
- attr_accessor :foo
61
- attr_encrypted :foo, aad: :id
62
-
63
- def raw_foo
64
- @foo
65
- end
66
-
67
- def id
68
- "unique record id"
69
- end
70
- end
71
-
72
- Slosilo::encryption_key = Slosilo::Symmetric.new.random_key
73
-
74
- obj = Foo.new
75
- obj.foo = "bar"
76
- obj.raw_foo # => "\xC4\xEF\x87\xD3b\xEA\x12\xDF\xD0\xD4hk\xEDJ\v\x1Cr\xF2#\xA3\x11\xA4*k\xB7\x8F\x8F\xC2\xBD\xBB\xFF\xE3"
77
- obj.foo # => "bar"
78
- ```
79
-
80
- You can safely use it in ie. ActiveRecord::Base or Sequel::Model subclasses.
81
-
82
- ### Asymmetric encryption and signing
83
-
84
- ```ruby
85
- private_key = Slosilo::Key.new
86
- public_key = private_key.public
87
- ```
88
-
89
- #### Key dumping
90
- ```ruby
91
- k = public_key.to_s # => "-----BEGIN PUBLIC KEY----- ...
92
- (Slosilo::Key.new k) == public_key # => true
93
- ```
94
-
95
- #### Encryption
96
-
97
- ```ruby
98
- encrypted = public_key.encrypt_message "eagle one sees many clouds"
99
- # => "\xA3\x1A\xD2\xFC\xB0 ...
100
-
101
- public_key.decrypt_message encrypted
102
- # => OpenSSL::PKey::RSAError: private key needed.
103
-
104
- private_key.decrypt_message encrypted
105
- # => "eagle one sees many clouds"
106
- ```
107
-
108
- #### Signing
109
-
110
- ```ruby
111
- token = private_key.signed_token "missile launch not authorized"
112
- # => {"data"=>"missile launch not authorized", "timestamp"=>"2014-10-13 12:41:25 UTC", "signature"=>"bSImk...DzV3o", "key"=>"455f7ac42d2d483f750b4c380761821d"}
113
-
114
- public_key.token_valid? token # => true
115
-
116
- token["data"] = "missile launch authorized"
117
- public_key.token_valid? token # => false
118
- ```
119
-
120
- ### Keystore
121
-
122
- ```ruby
123
- Slosilo::encryption_key = ENV['SLOSILO_KEY']
124
- Slosilo.adapter = Slosilo::Adapters::FileAdapter.new "~/.keys"
125
-
126
- Slosilo[:own] = Slosilo::Key.new
127
- Slosilo[:their] = Slosilo::Key.new File.read("foo.pem")
128
-
129
- msg = Slosilo[:their].encrypt_message 'bar'
130
- p Slosilo[:own].signed_token msg
131
- ```
132
-
133
- ### Keystore in database
134
-
135
16
  Add a migration to create the necessary table:
136
17
 
137
18
  require 'slosilo/adapters/sequel_adapter/migration'
@@ -140,13 +21,12 @@ Remember to migrate your database
140
21
 
141
22
  $ rake db:migrate
142
23
 
143
- Then
144
- ```ruby
145
- Slosilo.adapter = Slosilo::Adapters::SequelAdapter.new
146
- ```
24
+ ## Usage
147
25
 
148
26
  ## Contributing
149
27
 
150
- We welcome contributions of all kinds to this repository. For instructions on
151
- how to get started and descriptions of our development workflows, please see our
152
- [contributing guide](CONTRIBUTING.md).
28
+ 1. Fork it
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create new Pull Request
@@ -7,10 +7,6 @@ module Slosilo
7
7
  raise NotImplementedError
8
8
  end
9
9
 
10
- def get_by_fingerprint fp
11
- raise NotImplementedError
12
- end
13
-
14
10
  def put_key id, key
15
11
  raise NotImplementedError
16
12
  end
@@ -1,21 +1,8 @@
1
1
  module Slosilo
2
2
  module Adapters
3
3
  class MockAdapter < Hash
4
- def initialize
5
- @fp = {}
6
- end
7
-
8
- def put_key id, key
9
- @fp[key.fingerprint] = id
10
- self[id] = key
11
- end
12
-
4
+ alias :put_key :[]=
13
5
  alias :get_key :[]
14
-
15
- def get_by_fingerprint fp
16
- id = @fp[fp]
17
- [self[id], id]
18
- end
19
6
  end
20
7
  end
21
8
  end
@@ -15,13 +15,10 @@ module Slosilo
15
15
 
16
16
  # Create the table for holding keys
17
17
  def create_keystore_table
18
- # docs say to not use create_table? in migration;
19
- # but we really want this to be robust in case there are any previous installs
20
- # and we can't use table_exists? because it rolls back
21
- create_table? keystore_table do
18
+ create_table keystore_table do
22
19
  String :id, primary_key: true
20
+ # Note: currently only postgres is supported
23
21
  bytea :key, null: false
24
- String :fingerprint, unique: true, null: false
25
22
  end
26
23
  end
27
24
 
@@ -6,89 +6,27 @@ module Slosilo
6
6
  def model
7
7
  @model ||= create_model
8
8
  end
9
-
10
- def secure?
11
- !Slosilo.encryption_key.nil?
12
- end
13
9
 
14
10
  def create_model
15
11
  model = Sequel::Model(:slosilo_keystore)
16
12
  model.unrestrict_primary_key
17
- model.attr_encrypted(:key, aad: :id) if secure?
13
+ model.attr_encrypted :key
18
14
  model
19
15
  end
20
16
 
21
17
  def put_key id, value
22
- fail Error::InsecureKeyStorage unless secure? || !value.private?
23
-
24
- attrs = { id: id, key: value.to_der }
25
- attrs[:fingerprint] = value.fingerprint if fingerprint_in_db?
26
- model.create attrs
18
+ model.create id: id, key: value
27
19
  end
28
20
 
29
21
  def get_key id
30
22
  stored = model[id]
31
23
  return nil unless stored
32
- Slosilo::Key.new stored.key
33
- end
34
-
35
- def get_by_fingerprint fp
36
- if fingerprint_in_db?
37
- stored = model[fingerprint: fp]
38
- return nil unless stored
39
- [Slosilo::Key.new(stored.key), stored.id]
40
- else
41
- warn "Please migrate to a new database schema using rake slosilo:migrate for efficient fingerprint lookups"
42
- find_by_fingerprint fp
43
- end
24
+ stored.key
44
25
  end
45
-
26
+
46
27
  def each
47
28
  model.each do |m|
48
- yield m.id, Slosilo::Key.new(m.key)
49
- end
50
- end
51
-
52
- def recalculate_fingerprints
53
- # Use a transaction to ensure that all fingerprints are updated together. If any update fails,
54
- # we want to rollback all updates.
55
- model.db.transaction do
56
- model.each do |m|
57
- m.update fingerprint: Slosilo::Key.new(m.key).fingerprint
58
- end
59
- end
60
- end
61
-
62
-
63
- def migrate!
64
- unless fingerprint_in_db?
65
- model.db.transaction do
66
- model.db.alter_table :slosilo_keystore do
67
- add_column :fingerprint, String
68
- end
69
-
70
- # reload the schema
71
- model.set_dataset model.dataset
72
-
73
- recalculate_fingerprints
74
-
75
- model.db.alter_table :slosilo_keystore do
76
- set_column_not_null :fingerprint
77
- add_unique_constraint :fingerprint
78
- end
79
- end
80
- end
81
- end
82
-
83
- private
84
-
85
- def fingerprint_in_db?
86
- model.columns.include? :fingerprint
87
- end
88
-
89
- def find_by_fingerprint fp
90
- each do |id, k|
91
- return [k, id] if k.fingerprint == fp
29
+ yield m.id, m.key
92
30
  end
93
31
  end
94
32
  end
@@ -5,47 +5,21 @@ 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
24
8
  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
-
30
- # In ruby 3 .arity for #proc returns both 1 and 2, depends on internal #proc
31
- # This method is also being called with aad which is string, in such case the arity is 1
32
- raise ":aad proc must take two arguments" unless (auth_data.arity.abs == 2 || auth_data.arity.abs == 1)
33
-
34
9
  # push a module onto the inheritance hierarchy
35
10
  # this allows calling super in classes
36
11
  include(accessors = Module.new)
37
12
  accessors.module_eval do
38
13
  a.each do |attr|
39
14
  define_method "#{attr}=" do |value|
40
- super(EncryptedAttributes.encrypt(value, aad: auth_data[self]))
15
+ super(EncryptedAttributes.encrypt value)
41
16
  end
42
17
  define_method attr do
43
- EncryptedAttributes.decrypt(super(), aad: auth_data[self])
18
+ EncryptedAttributes.decrypt(super())
44
19
  end
45
20
  end
46
21
  end
47
22
  end
48
-
49
23
  end
50
24
 
51
25
  def self.included base
@@ -53,14 +27,14 @@ module Slosilo
53
27
  end
54
28
 
55
29
  class << self
56
- def encrypt value, opts={}
30
+ def encrypt value
57
31
  return nil unless value
58
- cipher.encrypt value, key: key, aad: opts[:aad]
32
+ cipher.encrypt value, key: key
59
33
  end
60
34
 
61
- def decrypt ctxt, opts={}
35
+ def decrypt ctxt
62
36
  return nil unless ctxt
63
- cipher.decrypt ctxt, key: key, aad: opts[:aad]
37
+ cipher.decrypt ctxt, key: key
64
38
  end
65
39
 
66
40
  def key
@@ -82,4 +56,4 @@ module Slosilo
82
56
  end
83
57
  end
84
58
 
85
- Object.send :include, Slosilo::EncryptedAttributes
59
+ Object.send:include, Slosilo::EncryptedAttributes
@@ -0,0 +1,59 @@
1
+ module Slosilo
2
+ # A mixin module which simplifies generating signed and encrypted requests.
3
+ # It's designed to be mixed into a standard Net::HTTPRequest object
4
+ # and ensures the request is signed and optionally encrypted before execution.
5
+ # Requests prepared this way will be recognized by Slosilo::Rack::Middleware.
6
+ #
7
+ # As an example, you can use it with RestClient like so:
8
+ # RestClient.add_before_execution_proc do |req, params|
9
+ # require 'slosilo'
10
+ # req.extend Slosilo::HTTPRequest
11
+ # req.keyname = :somekey
12
+ # end
13
+ #
14
+ # The request won't be encrypted unless you set the destination keyname.
15
+
16
+ module HTTPRequest
17
+ # Encrypt the request with key named @keyname from Slosilo::Keystore.
18
+ # If calling this manually, make sure to encrypt before signing.
19
+ def encrypt!
20
+ return unless @keyname
21
+ return unless body && !body.empty?
22
+ self.body, key = Slosilo[@keyname].encrypt body
23
+ self['X-Slosilo-Key'] = Base64::urlsafe_encode64 key
24
+ end
25
+
26
+ # Sign the request with :own key from Slosilo::Keystore.
27
+ # If calling this manually, make sure to encrypt before signing.
28
+ def sign!
29
+ token = Slosilo[:own].signed_token signed_data
30
+ self['Timestamp'] = token["timestamp"]
31
+ self['X-Slosilo-Signature'] = token["signature"]
32
+ end
33
+
34
+ # Build the data hash to sign.
35
+ def signed_data
36
+ data = { "path" => path, "body" => [body].pack('m0') }
37
+ if key = self['X-Slosilo-Key']
38
+ data["key"] = key
39
+ end
40
+ if authz = self['Authorization']
41
+ data["authorization"] = authz
42
+ end
43
+ data
44
+ end
45
+
46
+ # Encrypt, sign and execute the request.
47
+ def exec *a
48
+ # we need to hook here because the body might be set
49
+ # in several ways and here it's hopefully finalized
50
+ encrypt!
51
+ sign!
52
+ super *a
53
+ end
54
+
55
+ # Name of the key used to encrypt the request.
56
+ # Use it to establish the identity of the receiver.
57
+ attr_accessor :keyname
58
+ end
59
+ end
data/lib/slosilo/key.rb CHANGED
@@ -3,8 +3,6 @@ require 'json'
3
3
  require 'base64'
4
4
  require 'time'
5
5
 
6
- require 'slosilo/errors'
7
-
8
6
  module Slosilo
9
7
  class Key
10
8
  def initialize raw_key = nil
@@ -15,10 +13,6 @@ module Slosilo
15
13
  else
16
14
  OpenSSL::PKey::RSA.new 2048
17
15
  end
18
- rescue OpenSSL::PKey::PKeyError => e
19
- # old openssl versions used to report ArgumentError
20
- # which arguably makes more sense here, so reraise as that
21
- raise ArgumentError, e, e.backtrace
22
16
  end
23
17
 
24
18
  attr_reader :key
@@ -33,28 +27,18 @@ module Slosilo
33
27
  key = @key.public_encrypt key
34
28
  [ctxt, key]
35
29
  end
36
-
37
- def encrypt_message plaintext
38
- c, k = encrypt plaintext
39
- k + c
40
- end
41
30
 
42
31
  def decrypt ciphertext, skey
43
32
  key = @key.private_decrypt skey
44
33
  cipher.decrypt ciphertext, key: key
45
34
  end
46
-
47
- def decrypt_message ciphertext
48
- k, c = ciphertext.unpack("A256A*")
49
- decrypt c, k
50
- end
51
35
 
52
36
  def to_s
53
37
  @key.public_key.to_pem
54
38
  end
55
39
 
56
40
  def to_der
57
- @to_der ||= @key.to_der
41
+ @key.to_der
58
42
  end
59
43
 
60
44
  def sign value
@@ -74,119 +58,23 @@ module Slosilo
74
58
  def signed_token data
75
59
  token = { "data" => data, "timestamp" => Time.new.utc.to_s }
76
60
  token["signature"] = Base64::urlsafe_encode64(sign token)
77
- token["key"] = fingerprint
78
61
  token
79
62
  end
80
-
81
- JWT_ALGORITHM = 'conjur.org/slosilo/v2'.freeze
82
-
83
- # Issue a JWT with the given claims.
84
- # `iat` (issued at) claim is automatically added.
85
- # Other interesting claims you can give are:
86
- # - `sub` - token subject, for example a user name;
87
- # - `exp` - expiration time (absolute);
88
- # - `cidr` (Conjur extension) - array of CIDR masks that are accepted to
89
- # make requests that bear this token
90
- def issue_jwt claims
91
- token = Slosilo::JWT.new claims
92
- token.add_signature \
93
- alg: JWT_ALGORITHM,
94
- kid: fingerprint,
95
- &method(:sign)
96
- token.freeze
97
- end
98
-
99
- DEFAULT_EXPIRATION = 8 * 60
100
63
 
101
- def token_valid? token, expiry = DEFAULT_EXPIRATION
102
- return jwt_valid? token if token.respond_to? :header
64
+ def token_valid? token, expiry = 8 * 60
103
65
  token = token.clone
104
- expected_key = token.delete "key"
105
- return false if (expected_key and (expected_key != fingerprint))
106
66
  signature = Base64::urlsafe_decode64(token.delete "signature")
107
67
  (Time.parse(token["timestamp"]) + expiry > Time.now) && verify_signature(token, signature)
108
68
  end
109
-
110
- # Validate a JWT.
111
- #
112
- # Convenience method calling #validate_jwt and returning false if an
113
- # exception is raised.
114
- #
115
- # @param token [JWT] pre-parsed token to verify
116
- # @return [Boolean]
117
- def jwt_valid? token
118
- validate_jwt token
119
- true
120
- rescue
121
- false
122
- end
123
-
124
- # Validate a JWT.
125
- #
126
- # First checks whether algorithm is 'conjur.org/slosilo/v2' and the key id
127
- # matches this key's fingerprint. Then verifies if the token is not expired,
128
- # as indicated by the `exp` claim; in its absence tokens are assumed to
129
- # expire in `iat` + 8 minutes.
130
- #
131
- # If those checks pass, finally the signature is verified.
132
- #
133
- # @raises TokenValidationError if any of the checks fail.
134
- #
135
- # @note It's the responsibility of the caller to examine other claims
136
- # included in the token; consideration needs to be given to handling
137
- # unrecognized claims.
138
- #
139
- # @param token [JWT] pre-parsed token to verify
140
- def validate_jwt token
141
- def err msg
142
- raise Error::TokenValidationError, msg, caller
143
- end
144
-
145
- header = token.header
146
- err 'unrecognized algorithm' unless header['alg'] == JWT_ALGORITHM
147
- err 'mismatched key' if (kid = header['kid']) && kid != fingerprint
148
- iat = Time.at token.claims['iat'] || err('unknown issuing time')
149
- exp = Time.at token.claims['exp'] || (iat + DEFAULT_EXPIRATION)
150
- err 'token expired' if exp <= Time.now
151
- err 'invalid signature' unless verify_signature token.string_to_sign, token.signature
152
- true
153
- end
154
69
 
155
70
  def sign_string value
156
- salt = shake_salt
157
- key.private_encrypt(hash_function.digest(salt + value)) + salt
158
- end
159
-
160
- def fingerprint
161
- @fingerprint ||= OpenSSL::Digest::SHA256.hexdigest key.public_key.to_der
162
- end
163
-
164
- def == other
165
- to_der == other.to_der
166
- end
167
-
168
- alias_method :eql?, :==
169
-
170
- def hash
171
- to_der.hash
172
- end
173
-
174
- # return a new key with just the public part of this
175
- def public
176
- Key.new(@key.public_key)
177
- end
178
-
179
- # checks if the keypair contains a private key
180
- def private?
181
- @key.private?
71
+ _salt = salt
72
+ key.private_encrypt(hash_function.digest(_salt + value)) + _salt
182
73
  end
183
74
 
184
75
  private
185
-
186
- # Note that this is currently somewhat shallow stringification --
187
- # to implement originating tokens we may need to make it deeper.
188
76
  def stringify value
189
- string = case value
77
+ case value
190
78
  when Hash
191
79
  value.to_a.sort.to_json
192
80
  when String
@@ -194,20 +82,9 @@ module Slosilo
194
82
  else
195
83
  value.to_json
196
84
  end
197
-
198
- # Make sure that the string is ascii_8bit (i.e. raw bytes), and represents
199
- # the utf-8 encoding of the string. This accomplishes two things: it normalizes
200
- # the representation of the string at the byte level (so we don't have an error if
201
- # one username is submitted as ISO-whatever, and the next as UTF-16), and it prevents
202
- # an incompatible encoding error when we concatenate it with the salt.
203
- if string.encoding != Encoding::ASCII_8BIT
204
- string.encode(Encoding::UTF_8).force_encoding(Encoding::ASCII_8BIT)
205
- else
206
- string
207
- end
208
85
  end
209
86
 
210
- def shake_salt
87
+ def salt
211
88
  Slosilo::Random::salt
212
89
  end
213
90