ubiq-security 1.0.0 → 1.0.1

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.
@@ -13,154 +13,161 @@
13
13
  #
14
14
  # https://ubiqsecurity.com/legal
15
15
  #
16
+
17
+ # frozen_string_literal: true
18
+
16
19
  require 'rb-readline'
17
20
  require 'byebug'
18
21
  require 'httparty'
19
- require "active_support/all"
22
+ require 'active_support/all'
20
23
  require_relative './auth.rb'
21
24
  require_relative './algo.rb'
22
25
  require 'webrick'
23
26
 
27
+ # Ubiq Security Modules for encrypting / decrypting data
24
28
  module Ubiq
29
+ # Ubiq Encryption object
30
+ # This object represents a single data encryption key and can be used to
31
+ # encrypt several separate plain texts using the same key
32
+ class Encryption
33
+ def initialize(creds, uses)
34
+ raise 'Some of your credentials are missing, please check!' unless validate_creds(creds)
25
35
 
26
- # Ubiq Encryption object
27
- # This object represents a single data encryption key and can be used to encrypt several separate plain texts using the same key
28
- class Encryption
29
- def initialize(creds, uses)
30
-
31
- raise RuntimeError, 'Some of your credentials are missing, please check!' if !validate_creds(creds)
32
-
33
- # Set host, either the default or the one given by caller
34
- @host = creds.host.blank? ? UBIQ_HOST : creds.host
36
+ # Set host, either the default or the one given by caller
37
+ @host = creds.host.blank? ? UBIQ_HOST : creds.host
35
38
 
36
- # Set the credentials in instance varibales to be used among methods
37
- # The client's public API key (used to identify the client to the server
38
- @papi = creds.access_key_id
39
+ # Set the credentials in instance varibales to be used among methods
40
+ # The client's public API key (used to identify the client to the server
41
+ @papi = creds.access_key_id
39
42
 
40
- # The client's secret API key (used to authenticate HTTP requests)
41
- @sapi = creds.secret_signing_key
43
+ # The client's secret API key (used to authenticate HTTP requests)
44
+ @sapi = creds.secret_signing_key
42
45
 
43
- # The client's secret RSA encryption key/password (used to decrypt the client's RSA key from the server). This key is not retained by this object.
44
- @srsa = creds.secret_crypto_access_key
46
+ # The client's secret RSA encryption key/password (used to decrypt the
47
+ # client's RSA key from the server). This key is not retained by this object.
48
+ @srsa = creds.secret_crypto_access_key
45
49
 
46
- # Build the endpoint URL
47
- url = endpoint_base + '/encryption/key'
50
+ # Build the endpoint URL
51
+ url = endpoint_base + '/encryption/key'
48
52
 
49
- # Build the Request Body with the number of uses of key
50
- query = {uses: uses}
53
+ # Build the Request Body with the number of uses of key
54
+ query = { uses: uses }
51
55
 
52
- # Retrieve the necessary headers to make the request using Auth Object
53
- headers = Auth.build_headers(@papi, @sapi, endpoint, query, @host,'post')
56
+ # Retrieve the necessary headers to make the request using Auth Object
57
+ headers = Auth.build_headers(@papi, @sapi, endpoint, query, @host, 'post')
54
58
 
55
- @encryption_started = false
56
- @encryption_ready = true
59
+ @encryption_started = false
60
+ @encryption_ready = true
57
61
 
58
- # Request a new encryption key from the server. if the request
59
- # fails, the function raises a HTTPError indicating
60
- # the status code returned by the server. this exception is
61
- # propagated back to the caller
62
+ # Request a new encryption key from the server. if the request
63
+ # fails, the function raises a HTTPError indicating
64
+ # the status code returned by the server. this exception is
65
+ # propagated back to the caller
62
66
 
63
- begin
64
- response = HTTParty.post(
65
- url,
66
- body: query.to_json,
67
- headers: headers
68
- )
69
- rescue HTTParty::Error
70
- raise RuntimeError, 'Cant reach server'
67
+ begin
68
+ response = HTTParty.post(
69
+ url,
70
+ body: query.to_json,
71
+ headers: headers
72
+ )
73
+ rescue HTTParty::Error
74
+ raise 'Cant reach server'
75
+ end
76
+
77
+ # Response status is 201 Created
78
+ if response.code == WEBrick::HTTPStatus::RC_CREATED
79
+ # The code below largely assumes that the server returns
80
+ # a json object that contains the members and is formatted
81
+ # according to the Ubiq REST specification.
82
+
83
+ # Build the key object
84
+ @key = {}
85
+ @key['id'] = response['key_fingerprint']
86
+ @key['session'] = response['encryption_session']
87
+ @key['security_model'] = response['security_model']
88
+ @key['algorithm'] = response['security_model']['algorithm'].downcase
89
+ @key['max_uses'] = response['max_uses']
90
+ @key['uses'] = 0
91
+ @key['encrypted'] = Base64.strict_decode64(response['encrypted_data_key'])
92
+
93
+ # Get encrypted private key from response body
94
+ encrypted_private_key = response['encrypted_private_key']
95
+ # Get wrapped data key from response body
96
+ wrapped_data_key = response['wrapped_data_key']
97
+ # Decrypt the encryped private key using @srsa supplied
98
+ private_key = OpenSSL::PKey::RSA.new(encrypted_private_key, @srsa)
99
+ # Decode WDK from base64 format
100
+ wdk = Base64.strict_decode64(wrapped_data_key)
101
+ # Use private key to decrypt the wrapped data key
102
+ dk = private_key.private_decrypt(wdk, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
103
+ @key['raw'] = dk
104
+ # Build the algorithm object
105
+ @algo = Algo.new.get_algo(@key['algorithm'])
106
+ else
107
+ # Raise the error if response is not 201
108
+ raise "HTTPError Response: Expected 201, got #{response.code}"
109
+ end
71
110
  end
72
111
 
73
- # Response status is 201 Created
74
- if response.code == WEBrick::HTTPStatus::RC_CREATED
75
- # The code below largely assumes that the server returns
76
- # a json object that contains the members and is formatted
77
- # according to the Ubiq REST specification.
78
-
79
- # Build the key object
80
- @key = {}
81
- @key['id'] = response['key_fingerprint']
82
- @key['session'] = response['encryption_session']
83
- @key['security_model'] = response['security_model']
84
- @key['algorithm'] = response['security_model']['algorithm'].downcase
85
- @key['max_uses'] = response['max_uses']
86
- @key['uses'] = 0
87
- @key['encrypted'] = Base64.strict_decode64(response['encrypted_data_key'])
88
-
89
- # Get encrypted private key from response body
90
- encrypted_private_key = response['encrypted_private_key']
91
- # Get wrapped data key from response body
92
- wrapped_data_key = response['wrapped_data_key']
93
- # Decrypt the encryped private key using @srsa supplied
94
- private_key = OpenSSL::PKey::RSA.new(encrypted_private_key,@srsa)
95
- # Decode WDK from base64 format
96
- wdk = Base64.strict_decode64(wrapped_data_key)
97
- # Use private key to decrypt the wrapped data key
98
- dk = private_key.private_decrypt(wdk,OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
99
- @key['raw'] = dk
100
- # Build the algorithm object
101
- @algo = Algo.new.get_algo(@key['algorithm'])
102
- else
103
- # Raise the error if response is not 201
104
- raise RuntimeError, "HTTPError Response: Expected 201, got #{response.code}"
105
- end
112
+ def begin
113
+ # Begin the encryption process
106
114
 
107
- end
115
+ # When this function is called, the encryption object increments
116
+ # the number of uses of the key and creates a new internal context
117
+ # to be used to encrypt the data.
118
+ # If the encryption object is not yet ready to be used, throw an error
119
+ raise 'Encryption not ready' unless @encryption_ready
108
120
 
109
- def begin
110
- # Begin the encryption process
111
-
112
- # When this function is called, the encryption object increments
113
- # the number of uses of the key and creates a new internal context
114
- # to be used to encrypt the data.
115
- # If the encryption object is not yet ready to be used, throw an error
116
- raise RuntimeError, 'Encryption not ready' if !@encryption_ready
117
-
118
- # if Encryption cipher context already exists
119
- raise RuntimeError, 'Encryption already in progress' if @encryption_started
120
- # If max uses > uses
121
- raise RuntimeError, 'Maximum key uses exceeded' if @key['uses'] >= @key['max_uses']
122
- @key['uses'] += 1
123
- # create a new Encryption context and initialization vector
124
- @enc , @iv = Algo.new.encryptor(@algo, @key['raw'])
125
-
126
- # Pack the result into bytes to get a byte string
127
- struct = [0, 0, @algo[:id], @iv.length, @key['encrypted'].length].pack('CCCCn')
128
- @encryption_started = true
129
- return struct + @iv + @key['encrypted']
130
- end
121
+ # if Encryption cipher context already exists
122
+ raise 'Encryption already in progress' if @encryption_started
123
+ # If max uses > uses
124
+ raise 'Maximum key uses exceeded' if @key['uses'] >= @key['max_uses']
131
125
 
132
- def update(data)
133
- raise RuntimeError, 'Encryption is not Started' if !@encryption_started
134
- # Encryption of some plain text is perfomed here
135
- # Any cipher text produced by the operation is returned
136
- @enc.update(data)
137
- end
126
+ @key['uses'] += 1
127
+ # create a new Encryption context and initialization vector
128
+ @enc, @iv = Algo.new.encryptor(@algo, @key['raw'])
138
129
 
139
- def end
140
- raise RuntimeError, 'Encryption is not Started' if !@encryption_started
141
- # This function finalizes the encryption (producing the final
142
- # cipher text for the encryption, if necessary) and adds any
143
- # authentication information (if required by the algorithm).
144
- # Any data produced is returned by the function.
145
-
146
- # Finalize an encryption
147
- res = @enc.final
148
- if @algo[:tag_length] != 0
149
- # Add the tag to the cipher text
150
- res+= @enc.auth_tag
130
+ # Pack the result into bytes to get a byte string
131
+ struct = [0, 0, @algo[:id], @iv.length, @key['encrypted'].length].pack('CCCCn')
132
+ @encryption_started = true
133
+ return struct + @iv + @key['encrypted']
134
+ end
135
+
136
+ def update(data)
137
+ raise 'Encryption is not Started' unless @encryption_started
138
+
139
+ # Encryption of some plain text is perfomed here
140
+ # Any cipher text produced by the operation is returned
141
+ @enc.update(data)
151
142
  end
152
- @encryption_started = false
153
- # Return the encrypted result
154
- return res
155
- end
156
143
 
157
- def close
158
- raise RuntimeError, 'Encryption currently running' if @encryption_started
159
- # If the key was used less times than was requested, send an update to the server
160
- if @key['uses'] < @key['max_uses']
161
- query_url = "#{endpoint}/#{@key['id']}/#{@key['session']}"
144
+ def end
145
+ raise 'Encryption is not Started' unless @encryption_started
146
+
147
+ # This function finalizes the encryption (producing the final
148
+ # cipher text for the encryption, if necessary) and adds any
149
+ # authentication information (if required by the algorithm).
150
+ # Any data produced is returned by the function.
151
+
152
+ # Finalize an encryption
153
+ res = @enc.final
154
+ if @algo[:tag_length] != 0
155
+ # Add the tag to the cipher text
156
+ res += @enc.auth_tag
157
+ end
158
+ @encryption_started = false
159
+ # Return the encrypted result
160
+ return res
161
+ end
162
+
163
+ def close
164
+ raise 'Encryption currently running' if @encryption_started
165
+
166
+ # If the key was used less times than was requested, send an update to the server
167
+ if @key['uses'] < @key['max_uses']
168
+ query_url = "#{endpoint}/#{@key['id']}/#{@key['session']}"
162
169
  url = "#{endpoint_base}/encryption/key/#{@key['id']}/#{@key['session']}"
163
- query = {actual: @key['uses'], requested: @key['max_uses']}
170
+ query = { actual: @key['uses'], requested: @key['max_uses'] }
164
171
  headers = Auth.build_headers(@papi, @sapi, query_url, query, @host, 'patch')
165
172
  response = HTTParty.patch(
166
173
  url,
@@ -168,40 +175,43 @@ class Encryption
168
175
  headers: headers
169
176
  )
170
177
  remove_instance_variable(:@key)
171
- @encryption_ready = false;
178
+ @encryption_ready = false
179
+ end
172
180
  end
173
- end
174
181
 
175
- def endpoint_base
176
- @host + '/api/v0'
177
- end
182
+ def endpoint_base
183
+ @host + '/api/v0'
184
+ end
185
+
186
+ def endpoint
187
+ '/api/v0/encryption/key'
188
+ end
178
189
 
179
- def endpoint
180
- '/api/v0/encryption/key'
190
+ def validate_creds(credentials)
191
+ # This method checks for the presence of the credentials
192
+ !credentials.access_key_id.blank? &&
193
+ !credentials.secret_signing_key.blank? &&
194
+ !credentials.secret_crypto_access_key.blank?
195
+ end
181
196
  end
182
197
 
183
198
  def validate_creds(credentials)
184
199
  # This method checks for the presence of the credentials
185
- !credentials.access_key_id.blank? and !credentials.secret_signing_key.blank? and !credentials.secret_crypto_access_key.blank?
200
+ !credentials.access_key_id.blank? &&
201
+ !credentials.secret_signing_key.blank? &&
202
+ !credentials.secret_crypto_access_key.blank?
186
203
  end
187
204
 
188
- end
189
-
190
- def validate_creds(credentials)
191
- # This method checks for the presence of the credentials
192
- !credentials.access_key_id.blank? and !credentials.secret_signing_key.blank? and !credentials.secret_crypto_access_key.blank?
193
- end
194
-
195
- def encrypt(creds, data)
196
- begin
197
- enc = Encryption.new(creds, 1)
198
- res = enc.begin() + enc.update(data) + enc.end()
199
- enc.close()
200
- rescue
201
- enc.close() if enc
202
- raise
205
+ def encrypt(creds, data)
206
+ begin
207
+ enc = Encryption.new(creds, 1)
208
+ res = enc.begin + enc.update(data) + enc.end
209
+ enc.close
210
+ rescue StandardError
211
+ enc&.close
212
+ raise
213
+ end
214
+ return res
203
215
  end
204
- return res
205
216
  end
206
217
 
207
- end
@@ -14,5 +14,5 @@
14
14
  # https://ubiqsecurity.com/legal
15
15
  #
16
16
  module Ubiq
17
- UBIQ_HOST = 'api.ubiqsecurity.com:8811'
17
+ UBIQ_HOST = 'api.ubiqsecurity.com:8811'
18
18
  end
@@ -17,6 +17,5 @@
17
17
  # frozen_string_literal: true
18
18
 
19
19
  module Ubiq
20
- VERSION = "1.0.0"
20
+ VERSION = '1.0.1'
21
21
  end
22
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ubiq-security
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ubiq Security, Inc.