ubiq-security 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +17 -0
- data/README.md +188 -0
- data/Rakefile +6 -0
- data/lib/ubiq-security.rb +22 -0
- data/lib/ubiq/algo.rb +69 -0
- data/lib/ubiq/auth.rb +99 -0
- data/lib/ubiq/credentials.rb +105 -0
- data/lib/ubiq/decrypt.rb +268 -0
- data/lib/ubiq/encrypt.rb +207 -0
- data/lib/ubiq/host.rb +18 -0
- data/lib/ubiq/version.rb +22 -0
- data/ubiq-security.gemspec +30 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 20d4dacbe17d8162ab7d308069b82e2b54b89cf7a7253763919742ef350597e3
|
4
|
+
data.tar.gz: 370015b19528bc6a81678e3b0f7f270b0524b6309f23dc6087d04256edad1e27
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7ed8203d50dbe828d649af7decc40f300f1b2b5d74e912db9119e84444c840dc45a8fcc1c8e0b3fa49a8d7a6ebf73fbb9ce935e7244c1669d9d072af61674c52
|
7
|
+
data.tar.gz: ddd4e2690d2d47a737fda60d53524d9b57eec456410f14f5e4a56cb61e447e632f6c7a70bc0cc2dfc5126b95191df739dd6484089e07e6126f2d848989b28841
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at support@ubiqsecurity.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [https://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: https://contributor-covenant.org
|
74
|
+
[version]: https://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
3
|
+
|
4
|
+
NOTICE: All information contained herein is, and remains the property
|
5
|
+
of Ubiq Security, Inc. The intellectual and technical concepts contained
|
6
|
+
herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
7
|
+
covered by U.S. and Foreign Patents, patents in process, and are
|
8
|
+
protected by trade secret or copyright law. Dissemination of this
|
9
|
+
information or reproduction of this material is strictly forbidden
|
10
|
+
unless prior written permission is obtained from Ubiq Security, Inc.
|
11
|
+
|
12
|
+
Your use of the software is expressly conditioned upon the terms
|
13
|
+
and conditions available at:
|
14
|
+
|
15
|
+
https://ubiqsecurity.com/legal
|
16
|
+
|
17
|
+
|
data/README.md
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# Ubiq Security Ruby Library
|
2
|
+
|
3
|
+
The Ubiq Security Ruby library provides convenient interaction with the
|
4
|
+
Ubiq Security Platform API from applications written in the Ruby language.
|
5
|
+
It includes a pre-defined set of classes that will provide simple interfaces
|
6
|
+
to encrypt and decrypt data
|
7
|
+
|
8
|
+
## Documentation
|
9
|
+
|
10
|
+
See the [Ruby API docs](https://ubiqsecurity.com/docs/api?lang=ruby).
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
|
17
|
+
To install using [Bundler][bundler] add the following to your project's Gemfile
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem ubiq-security
|
21
|
+
```
|
22
|
+
|
23
|
+
To manually install `ubiq-security` via [Rubygems][rubygems] simply use gem to install it:
|
24
|
+
|
25
|
+
```sh
|
26
|
+
gem install ubiq-security
|
27
|
+
```
|
28
|
+
|
29
|
+
To build and install directly from a clone of the gitlab repository source:
|
30
|
+
|
31
|
+
```sh
|
32
|
+
git clone https://gitlab.com/ubiqsecurity/ubiq-ruby.git
|
33
|
+
cd ubiq-ruby
|
34
|
+
rake install:local
|
35
|
+
```
|
36
|
+
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
The library needs to be configured with your account credentials which is
|
41
|
+
available in your [Ubiq Dashboard][dashboard] [Credentials][credentials]. The credentials can be
|
42
|
+
explicitly set, set using environment variables, loaded from an explicit file
|
43
|
+
or read from the default location [~/.ubiq/credentials]
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
require 'ubiq-security'
|
47
|
+
include Ubiq
|
48
|
+
```
|
49
|
+
|
50
|
+
### Read credentials from a specific file and use a specific profile
|
51
|
+
```ruby
|
52
|
+
credentials = ConfigCredentials.new( "some-credential-file", "some-profile").get_attributes
|
53
|
+
```
|
54
|
+
|
55
|
+
|
56
|
+
### Read credentials from ~/.ubiq/credentials and use the default profile
|
57
|
+
```ruby
|
58
|
+
credentials = ConfigCredentials.new().get_attributes
|
59
|
+
```
|
60
|
+
|
61
|
+
|
62
|
+
### Use the following environment variables to set the credential values
|
63
|
+
UBIQ_ACCESS_KEY_ID
|
64
|
+
UBIQ_SECRET_SIGNING_KEY
|
65
|
+
UBIQ_SECRET_CRYPTO_ACCESS_KEY
|
66
|
+
```ruby
|
67
|
+
credentials = Credentials()
|
68
|
+
```
|
69
|
+
|
70
|
+
|
71
|
+
### Explicitly set the credentials
|
72
|
+
```ruby
|
73
|
+
credentials = Credentials(access_key_id = "...", secret_signing_key = "...", secret_crypto_access_key = "...")
|
74
|
+
```
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
### Encrypt a simple block of data
|
80
|
+
|
81
|
+
Pass credentials and data into the encryption function. The encrypted data
|
82
|
+
will be returned.
|
83
|
+
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
require "ubiq-security"
|
87
|
+
include Ubiq
|
88
|
+
|
89
|
+
encrypted_data = encrypt(credentials, plaintext_data)
|
90
|
+
```
|
91
|
+
|
92
|
+
|
93
|
+
### Decrypt a simple block of data
|
94
|
+
|
95
|
+
Pass credentials and encrypted data into the decryption function. The plaintext data
|
96
|
+
will be returned.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
require "ubiq-security"
|
100
|
+
include Ubiq
|
101
|
+
|
102
|
+
plaintext_data = decrypt(credentials, encrypted_data)
|
103
|
+
```
|
104
|
+
|
105
|
+
|
106
|
+
### Encrypt a large data element where data is loaded in chunks
|
107
|
+
|
108
|
+
- Create an encryption object using the credentials.
|
109
|
+
- Call the encryption instance begin method
|
110
|
+
- Call the encryption instance update method repeatedly until all the data is processed
|
111
|
+
- Call the encryption instance end method
|
112
|
+
- Call the encryption instance close method
|
113
|
+
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
require "ubiq-security"
|
117
|
+
include Ubiq
|
118
|
+
|
119
|
+
# Process 1 MiB of plaintext data at a time
|
120
|
+
BLOCK_SIZE = 1024 * 1024
|
121
|
+
|
122
|
+
# Rest of the program
|
123
|
+
....
|
124
|
+
encryption = Encryption.new(credentials, 1)
|
125
|
+
|
126
|
+
# Write out the header information
|
127
|
+
encrypted_data = encryption.begin()
|
128
|
+
|
129
|
+
# Loop until the end of the input file is reached
|
130
|
+
until infile.eof?
|
131
|
+
chunk = infile.read BLOCK_SIZE
|
132
|
+
encrypted_data += encryption.update(chunk))
|
133
|
+
end
|
134
|
+
# Make sure any additional encrypted data is retrieved from encryption instance
|
135
|
+
encrypted_data += encryption.end()
|
136
|
+
|
137
|
+
# Make sure to release any resources used during the encryption process
|
138
|
+
encryption.close()
|
139
|
+
```
|
140
|
+
|
141
|
+
### Decrypt a large data element where data is loaded in chunks
|
142
|
+
|
143
|
+
- Create an instance of the decryption object using the credentials.
|
144
|
+
- Call the decryption instance begin method
|
145
|
+
- Call the decryption instance update method repeatedly until all the data is processed
|
146
|
+
- Call the decryption instance end method
|
147
|
+
- Call the decryption instance close method
|
148
|
+
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
require "ubiq-security"
|
152
|
+
include Ubiq
|
153
|
+
|
154
|
+
# Process 1 MiB of encrypted data at a time
|
155
|
+
BLOCK_SIZE = 1024 * 1024
|
156
|
+
|
157
|
+
# Rest of the program
|
158
|
+
....
|
159
|
+
|
160
|
+
decryption = Decryption(credentials)
|
161
|
+
|
162
|
+
# Start the decryption and get any header information
|
163
|
+
plaintext_data = decryption.begin())
|
164
|
+
|
165
|
+
# Loop until the end of the input file is reached
|
166
|
+
until infile.eof?
|
167
|
+
chunk = infile.read BLOCK_SIZE
|
168
|
+
plaintext_data += decryption.update(chunk)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Make sure an additional plaintext data is retrieved from decryption instance
|
172
|
+
plaintext_data += decryption.end()
|
173
|
+
|
174
|
+
# Make sure to release any resources used during the decryption process
|
175
|
+
decryption.close()
|
176
|
+
```
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
|
181
|
+
[bundler]: https://bundler.io
|
182
|
+
[rubygems]: https://rubygems.org
|
183
|
+
[gem]: https://rubygems.org/gems/uniq-security
|
184
|
+
[dashboard]:https://dev.ubiqsecurity.com/docs/dashboard
|
185
|
+
[credentials]:https://dev.ubiqsecurity.com/docs/how-to-create-api-keys
|
186
|
+
|
187
|
+
|
188
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
2
|
+
#
|
3
|
+
# NOTICE: All information contained herein is, and remains the property
|
4
|
+
# of Ubiq Security, Inc. The intellectual and technical concepts contained
|
5
|
+
# herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
6
|
+
# covered by U.S. and Foreign Patents, patents in process, and are
|
7
|
+
# protected by trade secret or copyright law. Dissemination of this
|
8
|
+
# information or reproduction of this material is strictly forbidden
|
9
|
+
# unless prior written permission is obtained from Ubiq Security, Inc.
|
10
|
+
#
|
11
|
+
# Your use of the software is expressly conditioned upon the terms
|
12
|
+
# and conditions available at:
|
13
|
+
#
|
14
|
+
# https://ubiqsecurity.com/legal
|
15
|
+
|
16
|
+
require "ubiq/version"
|
17
|
+
require "ubiq/encrypt"
|
18
|
+
require "ubiq/decrypt"
|
19
|
+
require "ubiq/credentials"
|
20
|
+
|
21
|
+
|
22
|
+
|
data/lib/ubiq/algo.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
2
|
+
#
|
3
|
+
# NOTICE: All information contained herein is, and remains the property
|
4
|
+
# of Ubiq Security, Inc. The intellectual and technical concepts contained
|
5
|
+
# herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
6
|
+
# covered by U.S. and Foreign Patents, patents in process, and are
|
7
|
+
# protected by trade secret or copyright law. Dissemination of this
|
8
|
+
# information or reproduction of this material is strictly forbidden
|
9
|
+
# unless prior written permission is obtained from Ubiq Security, Inc.
|
10
|
+
#
|
11
|
+
# Your use of the software is expressly conditioned upon the terms
|
12
|
+
# and conditions available at:
|
13
|
+
#
|
14
|
+
# https://ubiqsecurity.com/legal
|
15
|
+
#
|
16
|
+
|
17
|
+
require "active_support/all"
|
18
|
+
require 'openssl'
|
19
|
+
|
20
|
+
module Ubiq
|
21
|
+
|
22
|
+
class Algo
|
23
|
+
|
24
|
+
def set_algo
|
25
|
+
@algorithm = {
|
26
|
+
"aes-256-gcm"=>{
|
27
|
+
id:0,
|
28
|
+
algorithm: OpenSSL::Cipher::AES256,
|
29
|
+
mode: OpenSSL::Cipher::AES256.new(:GCM),
|
30
|
+
key_length: 32,
|
31
|
+
iv_length: 12,
|
32
|
+
tag_length: 16
|
33
|
+
},
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_algo(name)
|
38
|
+
set_algo[name]
|
39
|
+
end
|
40
|
+
|
41
|
+
def encryptor(obj,key, iv=nil)
|
42
|
+
# key : A byte string containing the key to be used with this encryption
|
43
|
+
# If the caller specifies the initialization vector, it must be
|
44
|
+
# the correct length and, if so, will be used. If it is not
|
45
|
+
# specified, the function will generate a new one
|
46
|
+
|
47
|
+
cipher = obj[:mode]
|
48
|
+
raise RuntimeError, 'Invalid key length' if key.length != obj[:key_length]
|
49
|
+
|
50
|
+
raise RuntimeError, 'Invalid initialization vector length' if (iv!= nil and iv.length != obj[:iv_length])
|
51
|
+
cipher.encrypt
|
52
|
+
cipher.key = key
|
53
|
+
iv = cipher.random_iv
|
54
|
+
return cipher, iv
|
55
|
+
end
|
56
|
+
|
57
|
+
def decryptor(obj, key, iv)
|
58
|
+
cipher = obj[:mode]
|
59
|
+
raise RuntimeError, 'Invalid key length' if key.length != obj[:key_length]
|
60
|
+
|
61
|
+
raise RuntimeError, 'Invalid initialization vector length' if (iv!= nil and iv.length != obj[:iv_length])
|
62
|
+
cipher = obj[:mode]
|
63
|
+
cipher.decrypt
|
64
|
+
cipher.key = key
|
65
|
+
cipher.iv = iv
|
66
|
+
return cipher
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/ubiq/auth.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
2
|
+
#
|
3
|
+
# NOTICE: All information contained herein is, and remains the property
|
4
|
+
# of Ubiq Security, Inc. The intellectual and technical concepts contained
|
5
|
+
# herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
6
|
+
# covered by U.S. and Foreign Patents, patents in process, and are
|
7
|
+
# protected by trade secret or copyright law. Dissemination of this
|
8
|
+
# information or reproduction of this material is strictly forbidden
|
9
|
+
# unless prior written permission is obtained from Ubiq Security, Inc.
|
10
|
+
#
|
11
|
+
# Your use of the software is expressly conditioned upon the terms
|
12
|
+
# and conditions available at:
|
13
|
+
#
|
14
|
+
# https://ubiqsecurity.com/legal
|
15
|
+
#
|
16
|
+
require "active_support/all"
|
17
|
+
|
18
|
+
module Ubiq
|
19
|
+
|
20
|
+
class Auth
|
21
|
+
# HTTP Authentication for the Ubiq Platform
|
22
|
+
|
23
|
+
# This module implements HTTP authentication for the Ubiq platform
|
24
|
+
# via message signing as described by the IETF httpbis-message-signatures
|
25
|
+
# draft specification.
|
26
|
+
|
27
|
+
def self.build_headers(papi, sapi, endpoint, query, host, http_method)
|
28
|
+
|
29
|
+
# This function calculates the signature for the message, adding the Signature header
|
30
|
+
# to contain the data. Certain HTTP headers are required for
|
31
|
+
# signature calculation and will be added by this code as
|
32
|
+
# necessary. The constructed headers object is returned
|
33
|
+
|
34
|
+
# the '(request-target)' is part of the signed data.
|
35
|
+
# it's value is 'http_method path?query'
|
36
|
+
reqt = "#{http_method} #{endpoint}"
|
37
|
+
|
38
|
+
# The time at which the signature was created expressed as the unix epoch
|
39
|
+
created = Time.now.to_i
|
40
|
+
|
41
|
+
# the Digest header is always included/overridden by
|
42
|
+
# this code. it is a hash of the body of the http message
|
43
|
+
# and is always present even if the body is empty
|
44
|
+
hash_sha512 = OpenSSL::Digest::SHA512.new
|
45
|
+
hash_sha512 << JSON.dump(query)
|
46
|
+
digest = 'SHA-512='+Base64.strict_encode64(hash_sha512.digest)
|
47
|
+
|
48
|
+
# Initialize the headers object to be returned via this method
|
49
|
+
all_headers = {}
|
50
|
+
# The content type of request
|
51
|
+
all_headers['content-type'] = 'application/json'
|
52
|
+
# The request target calculated above(reqt)
|
53
|
+
all_headers['(request-target)'] = reqt
|
54
|
+
# The date and time in GMT format
|
55
|
+
all_headers['date'] = get_date
|
56
|
+
# The host specified by the caller
|
57
|
+
all_headers['host'] = get_host(host)
|
58
|
+
all_headers['(created)'] = created
|
59
|
+
all_headers['digest'] = digest
|
60
|
+
headers = ['content-type', 'date', 'host', '(created)', '(request-target)', 'digest']
|
61
|
+
|
62
|
+
# include the specified headers in the hmac calculation. each
|
63
|
+
# header is of the form 'header_name: header value\n'
|
64
|
+
# included headers are also added to an ordered list of headers
|
65
|
+
# which is included in the message
|
66
|
+
hmac = OpenSSL::HMAC.new(sapi, OpenSSL::Digest::SHA512.new)
|
67
|
+
headers.each do |header|
|
68
|
+
if all_headers.key?(header)
|
69
|
+
hmac << "#{header}: #{all_headers[header]}\n"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
all_headers.delete('(created)')
|
74
|
+
all_headers.delete('(request-target)')
|
75
|
+
all_headers.delete('host')
|
76
|
+
|
77
|
+
# Build the Signature header itself
|
78
|
+
all_headers['signature'] = 'keyId="' + papi + '"'
|
79
|
+
all_headers['signature'] += ', algorithm="hmac-sha512"'
|
80
|
+
all_headers['signature'] += ', created=' + created.to_s
|
81
|
+
all_headers['signature'] += ', headers="' + headers.join(" ") + '"'
|
82
|
+
all_headers['signature'] += ', signature="'
|
83
|
+
all_headers['signature'] += Base64.strict_encode64(hmac.digest)
|
84
|
+
all_headers['signature'] += '"'
|
85
|
+
|
86
|
+
return all_headers
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.get_host(host)
|
90
|
+
uri = URI(host)
|
91
|
+
return "#{uri.hostname}:#{uri.port}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.get_date
|
95
|
+
DateTime.now.in_time_zone('GMT').strftime("%a, %d %b %Y") + " " + DateTime.now.in_time_zone('GMT').strftime("%H:%M:%S") + " GMT"
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
2
|
+
#
|
3
|
+
# NOTICE: All information contained herein is, and remains the property
|
4
|
+
# of Ubiq Security, Inc. The intellectual and technical concepts contained
|
5
|
+
# herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
6
|
+
# covered by U.S. and Foreign Patents, patents in process, and are
|
7
|
+
# protected by trade secret or copyright law. Dissemination of this
|
8
|
+
# information or reproduction of this material is strictly forbidden
|
9
|
+
# unless prior written permission is obtained from Ubiq Security, Inc.
|
10
|
+
#
|
11
|
+
# Your use of the software is expressly conditioned upon the terms
|
12
|
+
# and conditions available at:
|
13
|
+
#
|
14
|
+
# https://ubiqsecurity.com/legal
|
15
|
+
#
|
16
|
+
require 'configparser'
|
17
|
+
require 'rb-readline'
|
18
|
+
require 'byebug'
|
19
|
+
|
20
|
+
module Ubiq
|
21
|
+
|
22
|
+
class CredentialsInfo
|
23
|
+
|
24
|
+
def initialize(access_key_id, secret_signing_key, secret_crypto_access_key, host)
|
25
|
+
@access_key_id = access_key_id
|
26
|
+
@secret_signing_key = secret_signing_key
|
27
|
+
@secret_crypto_access_key = secret_crypto_access_key
|
28
|
+
@host = host
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_attributes
|
32
|
+
return OpenStruct.new(access_key_id: @access_key_id, secret_signing_key: @secret_signing_key, secret_crypto_access_key: @secret_crypto_access_key, host: @host)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
class ConfigCredentials < CredentialsInfo
|
38
|
+
def initialize(config_file, profile)
|
39
|
+
# If config file is not found
|
40
|
+
if config_file != nil and !File.exists?(config_file)
|
41
|
+
raise RuntimeError, "Unable to open config file #{config_file} or contains missing values"
|
42
|
+
end
|
43
|
+
|
44
|
+
if config_file == nil
|
45
|
+
config_file = "~/.ubiq/credentials"
|
46
|
+
end
|
47
|
+
|
48
|
+
# If config file is found
|
49
|
+
if File.exists?(File.expand_path(config_file))
|
50
|
+
@creds = load_config_file(config_file, profile)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_attributes
|
55
|
+
return @creds
|
56
|
+
end
|
57
|
+
|
58
|
+
def load_config_file(file, profile)
|
59
|
+
config = ConfigParser.new(File.expand_path(file))
|
60
|
+
|
61
|
+
# Create empty dictionaries for the default and supplied profile
|
62
|
+
p = {}
|
63
|
+
d = {}
|
64
|
+
|
65
|
+
# get the default profile if there is one
|
66
|
+
if config['default'].present?
|
67
|
+
d = config['default']
|
68
|
+
end
|
69
|
+
|
70
|
+
# get the supplied profile if there is one
|
71
|
+
if config[profile].present?
|
72
|
+
p = config[profile]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Use given profile if it is available, otherwise use default.
|
76
|
+
access_key_id = p.key?('ACCESS_KEY_ID') ? p['ACCESS_KEY_ID'] : d['ACCESS_KEY_ID']
|
77
|
+
secret_signing_key = p.key?('SECRET_SIGNING_KEY') ? p['SECRET_SIGNING_KEY'] : d['SECRET_SIGNING_KEY']
|
78
|
+
secret_crypto_access_key = p.key?('SECRET_CRYPTO_ACCESS_KEY') ? p['SECRET_CRYPTO_ACCESS_KEY'] : d['SECRET_CRYPTO_ACCESS_KEY']
|
79
|
+
host = p.key?('SERVER') ? p['SERVER'] : d['SERVER']
|
80
|
+
|
81
|
+
# If the provided host does not contain http protocol then add to it
|
82
|
+
if !host.include?('http://') and !host.include?('https://')
|
83
|
+
host = 'https://' + host
|
84
|
+
end
|
85
|
+
|
86
|
+
return CredentialsInfo.new(access_key_id, secret_signing_key, secret_crypto_access_key, host).set_attributes
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Credentials < CredentialsInfo
|
91
|
+
|
92
|
+
def initialize(papi, sapi, srsa, host)
|
93
|
+
@access_key_id = papi.present? ? papi : ENV['UBIQ_ACCESS_KEY_ID']
|
94
|
+
@secret_signing_key = sapi.present? ? sapi : ENV['UBIQ_SECRET_SIGNING_KEY']
|
95
|
+
@secret_crypto_access_key = srsa.present? ? srsa : ENV['UBIQ_SECRET_CRYPTO_ACCESS_KEY']
|
96
|
+
@host = host.present? ? host : ENV['UBIQ_SERVER']
|
97
|
+
end
|
98
|
+
|
99
|
+
@creds = CredentialsInfo.new(@access_key_id, @secret_signing_key, @secret_crypto_access_key, @host).set_attributes
|
100
|
+
|
101
|
+
def get_attributes
|
102
|
+
return @creds
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/ubiq/decrypt.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
# Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
2
|
+
#
|
3
|
+
# NOTICE: All information contained herein is, and remains the property
|
4
|
+
# of Ubiq Security, Inc. The intellectual and technical concepts contained
|
5
|
+
# herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
6
|
+
# covered by U.S. and Foreign Patents, patents in process, and are
|
7
|
+
# protected by trade secret or copyright law. Dissemination of this
|
8
|
+
# information or reproduction of this material is strictly forbidden
|
9
|
+
# unless prior written permission is obtained from Ubiq Security, Inc.
|
10
|
+
#
|
11
|
+
# Your use of the software is expressly conditioned upon the terms
|
12
|
+
# and conditions available at:
|
13
|
+
#
|
14
|
+
# https://ubiqsecurity.com/legal
|
15
|
+
#
|
16
|
+
require 'rb-readline'
|
17
|
+
require 'byebug'
|
18
|
+
require 'httparty'
|
19
|
+
require "active_support/all"
|
20
|
+
require_relative './auth.rb'
|
21
|
+
require_relative './algo.rb'
|
22
|
+
require_relative './encrypt.rb'
|
23
|
+
require 'webrick'
|
24
|
+
|
25
|
+
module Ubiq
|
26
|
+
|
27
|
+
class Decryption
|
28
|
+
def initialize(creds)
|
29
|
+
# Initialize the decryption module object
|
30
|
+
# Set the credentials in instance varibales to be used among methods
|
31
|
+
# the server to which to make the request
|
32
|
+
raise RuntimeError, 'Some of your credentials are missing, please check!' if !validate_creds(creds)
|
33
|
+
@host = creds.host.blank? ? UBIQ_HOST : creds.host
|
34
|
+
|
35
|
+
# The client's public API key (used to identify the client to the server
|
36
|
+
@papi = creds.access_key_id
|
37
|
+
|
38
|
+
# The client's secret API key (used to authenticate HTTP requests)
|
39
|
+
@sapi = creds.secret_signing_key
|
40
|
+
|
41
|
+
# 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.
|
42
|
+
@srsa = creds.secret_crypto_access_key
|
43
|
+
|
44
|
+
@decryption_ready = true
|
45
|
+
@decryption_started = false
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def endpoint_base
|
50
|
+
@host + '/api/v0'
|
51
|
+
end
|
52
|
+
|
53
|
+
def endpoint
|
54
|
+
'/api/v0/decryption/key'
|
55
|
+
end
|
56
|
+
|
57
|
+
def begin
|
58
|
+
# Begin the decryption process
|
59
|
+
|
60
|
+
# This interface does not take any cipher text in its arguments
|
61
|
+
# in an attempt to maintain an API that corresponds to the
|
62
|
+
# encryption object. In doing so, the work that can take place
|
63
|
+
# in this function is limited. without any data, there is no
|
64
|
+
# way to determine which key is in use or decrypt any data.
|
65
|
+
#
|
66
|
+
# this function simply throws an error if starting an decryption
|
67
|
+
# while one is already in progress, and initializes the internal
|
68
|
+
# buffer
|
69
|
+
|
70
|
+
raise RuntimeError, 'Decryption is not ready' if !@decryption_ready
|
71
|
+
|
72
|
+
raise RuntimeError, 'Decryption Already Started' if @decryption_started
|
73
|
+
|
74
|
+
raise RuntimeError, 'Decryption already in progress' if @key.present? and @key.key?("dec")
|
75
|
+
@decryption_started = true
|
76
|
+
@data = ''
|
77
|
+
end
|
78
|
+
|
79
|
+
def update(data)
|
80
|
+
# Decryption of cipher text is performed here
|
81
|
+
# Cipher text must be passed to this function in the order in which it was output from the encryption.update function.
|
82
|
+
|
83
|
+
# Each encryption has a header on it that identifies the algorithm
|
84
|
+
# used and an encryption of the data key that was used to encrypt
|
85
|
+
# the original plain text. there is no guarantee how much of that
|
86
|
+
# data will be passed to this function or how many times this
|
87
|
+
# function will be called to process all of the data. to that end,
|
88
|
+
# this function buffers data internally, when it is unable to
|
89
|
+
# process it.
|
90
|
+
#
|
91
|
+
# The function buffers data internally until the entire header is
|
92
|
+
# received. once the header has been received, the encrypted data
|
93
|
+
# key is sent to the server for decryption. after the header has
|
94
|
+
# been successfully handled, this function always decrypts all of
|
95
|
+
# the data in its internal buffer *except* for however many bytes
|
96
|
+
# are specified by the algorithm's tag size. see the end() function
|
97
|
+
# for details.
|
98
|
+
|
99
|
+
raise RuntimeError, 'Decryption is not Started' if !@decryption_started
|
100
|
+
|
101
|
+
# Append the incoming data in the internal data buffer
|
102
|
+
@data = @data + data
|
103
|
+
|
104
|
+
# if there is no key or 'dec' member of key, then the code is still trying to build a complete header
|
105
|
+
if !@key.present? or !@key.key?("dec")
|
106
|
+
struct_length = [1,1,1,1,1].pack('CCCCn').length
|
107
|
+
packed_struct = @data[0...struct_length]
|
108
|
+
|
109
|
+
# Does the buffer contain enough of the header to
|
110
|
+
# determine the lengths of the initialization vector
|
111
|
+
# and the key?
|
112
|
+
if @data.length > struct_length
|
113
|
+
# Unpack the values packed in encryption
|
114
|
+
version, flag_for_later, algorithm_id, iv_length, key_length = packed_struct.unpack('CCCCn')
|
115
|
+
|
116
|
+
# verify flag and version are 0
|
117
|
+
raise RuntimeError, 'invalid encryption header' if version != 0 or flag_for_later != 0
|
118
|
+
|
119
|
+
# Does the buffer contain the entire header?
|
120
|
+
if @data.length > struct_length + iv_length + key_length
|
121
|
+
# Extract the initialization vector
|
122
|
+
iv = @data[struct_length...iv_length + struct_length]
|
123
|
+
# Extract the encryped key
|
124
|
+
encrypted_key = @data[struct_length + iv_length...key_length + struct_length + iv_length]
|
125
|
+
# Remove the header from the buffer
|
126
|
+
@data = @data[struct_length + iv_length + key_length..-1]
|
127
|
+
|
128
|
+
# generate a local identifier for the key
|
129
|
+
hash_sha512 = OpenSSL::Digest::SHA512.new
|
130
|
+
hash_sha512 << encrypted_key
|
131
|
+
client_id = hash_sha512.digest
|
132
|
+
|
133
|
+
if @key.present?
|
134
|
+
if @key['client_id'] != client_id
|
135
|
+
close()
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# IF key object not exists, request a new one from the server
|
140
|
+
if !@key.present?
|
141
|
+
url = endpoint_base + "/decryption/key"
|
142
|
+
query = {encrypted_data_key: Base64.strict_encode64(encrypted_key)}
|
143
|
+
headers = Auth.build_headers(@papi, @sapi, endpoint, query, @host, 'post')
|
144
|
+
|
145
|
+
response = HTTParty.post(
|
146
|
+
url,
|
147
|
+
body: query.to_json,
|
148
|
+
headers: headers
|
149
|
+
)
|
150
|
+
|
151
|
+
# Response status is 200 OK
|
152
|
+
if response.code == WEBrick::HTTPStatus::RC_OK
|
153
|
+
@key = {}
|
154
|
+
@key['finger_print'] = response['key_fingerprint']
|
155
|
+
@key['client_id'] = client_id
|
156
|
+
@key['session'] = response['encryption_session']
|
157
|
+
|
158
|
+
@key['algorithm'] = 'aes-256-gcm'
|
159
|
+
|
160
|
+
encrypted_private_key = response['encrypted_private_key']
|
161
|
+
# Decrypt the encryped private key using SRSA
|
162
|
+
private_key = OpenSSL::PKey::RSA.new(encrypted_private_key,@srsa)
|
163
|
+
|
164
|
+
wrapped_data_key = response['wrapped_data_key']
|
165
|
+
# Decode WDK from base64 format
|
166
|
+
wdk = Base64.strict_decode64(wrapped_data_key)
|
167
|
+
# Use private key to decrypt the wrapped data key
|
168
|
+
dk = private_key.private_decrypt(wdk,OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
|
169
|
+
|
170
|
+
@key['raw'] = dk
|
171
|
+
@key['uses'] = 0
|
172
|
+
else
|
173
|
+
# Raise the error if response is not 200
|
174
|
+
raise RuntimeError, "HTTPError Response: Expected 201, got #{response.code}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# If the key object exists, create a new decryptor
|
179
|
+
# with the initialization vector from the header and
|
180
|
+
# the decrypted key (which is either new from the
|
181
|
+
# server or cached from the previous decryption). in
|
182
|
+
# either case, increment the key usage
|
183
|
+
|
184
|
+
if @key.present?
|
185
|
+
@algo = Algo.new.get_algo(@key['algorithm'])
|
186
|
+
@key['dec'] = Algo.new.decryptor(@algo, @key['raw'], iv)
|
187
|
+
@key['uses'] += 1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# if the object has a key and a decryptor, then decrypt whatever
|
194
|
+
# data is in the buffer, less any data that needs to be saved to
|
195
|
+
# serve as the tag.
|
196
|
+
plain_text = ''
|
197
|
+
if @key.present? and @key.key?("dec")
|
198
|
+
size = @data.length - @algo[:tag_length]
|
199
|
+
if size > 0
|
200
|
+
plain_text = @key['dec'].update(@data[0..size-1])
|
201
|
+
@data = @data[size..-1]
|
202
|
+
end
|
203
|
+
return plain_text
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
def end
|
209
|
+
raise RuntimeError, 'Decryption is not Started' if !@decryption_started
|
210
|
+
# The update function always maintains tag-size bytes in
|
211
|
+
# the buffer because this function provides no data parameter.
|
212
|
+
# by the time the caller calls this function, all data must
|
213
|
+
# have already been input to the decryption object.
|
214
|
+
|
215
|
+
sz = @data.length - @algo[:tag_length]
|
216
|
+
|
217
|
+
raise RuntimeError, 'Invalid Tag!' if sz < 0
|
218
|
+
if sz == 0
|
219
|
+
@key['dec'].auth_tag = @data
|
220
|
+
begin
|
221
|
+
pt = @key['dec'].final
|
222
|
+
# Delete the decryptor context
|
223
|
+
@key.delete('dec')
|
224
|
+
# Return the decrypted plain data
|
225
|
+
@decryption_started = false
|
226
|
+
return pt
|
227
|
+
rescue Exception => e
|
228
|
+
print 'Invalid cipher data or tag!'
|
229
|
+
return ''
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def close
|
235
|
+
raise RuntimeError, 'Decryption currently running' if @decryption_started
|
236
|
+
# Reset the internal state of the decryption object
|
237
|
+
if @key.present?
|
238
|
+
if @key['uses'] > 0
|
239
|
+
query_url = "#{endpoint}/#{@key['finger_print']}/#{@key['session']}"
|
240
|
+
url = "#{endpoint_base}/decryption/key/#{@key['finger_print']}/#{@key['session']}"
|
241
|
+
query = {uses: @key['uses']}
|
242
|
+
headers = Auth.build_headers(@papi, @sapi, query_url, query, @host, 'patch')
|
243
|
+
response = HTTParty.patch(
|
244
|
+
url,
|
245
|
+
body: query.to_json,
|
246
|
+
headers: headers
|
247
|
+
)
|
248
|
+
remove_instance_variable(:@data)
|
249
|
+
remove_instance_variable(:@key)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
def decrypt(creds, data)
|
257
|
+
begin
|
258
|
+
dec = Decryption.new(creds)
|
259
|
+
res = dec.begin() + dec.update(data) + dec.end()
|
260
|
+
dec.close()
|
261
|
+
rescue
|
262
|
+
dec.close() if dec
|
263
|
+
raise
|
264
|
+
end
|
265
|
+
return res
|
266
|
+
|
267
|
+
end
|
268
|
+
end
|
data/lib/ubiq/encrypt.rb
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
# Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
2
|
+
#
|
3
|
+
# NOTICE: All information contained herein is, and remains the property
|
4
|
+
# of Ubiq Security, Inc. The intellectual and technical concepts contained
|
5
|
+
# herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
6
|
+
# covered by U.S. and Foreign Patents, patents in process, and are
|
7
|
+
# protected by trade secret or copyright law. Dissemination of this
|
8
|
+
# information or reproduction of this material is strictly forbidden
|
9
|
+
# unless prior written permission is obtained from Ubiq Security, Inc.
|
10
|
+
#
|
11
|
+
# Your use of the software is expressly conditioned upon the terms
|
12
|
+
# and conditions available at:
|
13
|
+
#
|
14
|
+
# https://ubiqsecurity.com/legal
|
15
|
+
#
|
16
|
+
require 'rb-readline'
|
17
|
+
require 'byebug'
|
18
|
+
require 'httparty'
|
19
|
+
require "active_support/all"
|
20
|
+
require_relative './auth.rb'
|
21
|
+
require_relative './algo.rb'
|
22
|
+
require 'webrick'
|
23
|
+
|
24
|
+
module Ubiq
|
25
|
+
|
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
|
35
|
+
|
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
|
+
|
40
|
+
# The client's secret API key (used to authenticate HTTP requests)
|
41
|
+
@sapi = creds.secret_signing_key
|
42
|
+
|
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
|
45
|
+
|
46
|
+
# Build the endpoint URL
|
47
|
+
url = endpoint_base + '/encryption/key'
|
48
|
+
|
49
|
+
# Build the Request Body with the number of uses of key
|
50
|
+
query = {uses: uses}
|
51
|
+
|
52
|
+
# Retrieve the necessary headers to make the request using Auth Object
|
53
|
+
headers = Auth.build_headers(@papi, @sapi, endpoint, query, @host,'post')
|
54
|
+
|
55
|
+
@encryption_started = false
|
56
|
+
@encryption_ready = true
|
57
|
+
|
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
|
+
|
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'
|
71
|
+
end
|
72
|
+
|
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
|
106
|
+
|
107
|
+
end
|
108
|
+
|
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
|
131
|
+
|
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
|
138
|
+
|
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
|
151
|
+
end
|
152
|
+
@encryption_started = false
|
153
|
+
# Return the encrypted result
|
154
|
+
return res
|
155
|
+
end
|
156
|
+
|
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']}"
|
162
|
+
url = "#{endpoint_base}/encryption/key/#{@key['id']}/#{@key['session']}"
|
163
|
+
query = {actual: @key['uses'], requested: @key['max_uses']}
|
164
|
+
headers = Auth.build_headers(@papi, @sapi, query_url, query, @host, 'patch')
|
165
|
+
response = HTTParty.patch(
|
166
|
+
url,
|
167
|
+
body: query.to_json,
|
168
|
+
headers: headers
|
169
|
+
)
|
170
|
+
remove_instance_variable(:@key)
|
171
|
+
@encryption_ready = false;
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def endpoint_base
|
176
|
+
@host + '/api/v0'
|
177
|
+
end
|
178
|
+
|
179
|
+
def endpoint
|
180
|
+
'/api/v0/encryption/key'
|
181
|
+
end
|
182
|
+
|
183
|
+
def validate_creds(credentials)
|
184
|
+
# 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?
|
186
|
+
end
|
187
|
+
|
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
|
203
|
+
end
|
204
|
+
return res
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
data/lib/ubiq/host.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
2
|
+
#
|
3
|
+
# NOTICE: All information contained herein is, and remains the property
|
4
|
+
# of Ubiq Security, Inc. The intellectual and technical concepts contained
|
5
|
+
# herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
6
|
+
# covered by U.S. and Foreign Patents, patents in process, and are
|
7
|
+
# protected by trade secret or copyright law. Dissemination of this
|
8
|
+
# information or reproduction of this material is strictly forbidden
|
9
|
+
# unless prior written permission is obtained from Ubiq Security, Inc.
|
10
|
+
#
|
11
|
+
# Your use of the software is expressly conditioned upon the terms
|
12
|
+
# and conditions available at:
|
13
|
+
#
|
14
|
+
# https://ubiqsecurity.com/legal
|
15
|
+
#
|
16
|
+
module Ubiq
|
17
|
+
UBIQ_HOST = 'api.ubiqsecurity.com:8811'
|
18
|
+
end
|
data/lib/ubiq/version.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright 2020 Ubiq Security, Inc., Proprietary and All Rights Reserved.
|
2
|
+
#
|
3
|
+
# NOTICE: All information contained herein is, and remains the property
|
4
|
+
# of Ubiq Security, Inc. The intellectual and technical concepts contained
|
5
|
+
# herein are proprietary to Ubiq Security, Inc. and its suppliers and may be
|
6
|
+
# covered by U.S. and Foreign Patents, patents in process, and are
|
7
|
+
# protected by trade secret or copyright law. Dissemination of this
|
8
|
+
# information or reproduction of this material is strictly forbidden
|
9
|
+
# unless prior written permission is obtained from Ubiq Security, Inc.
|
10
|
+
#
|
11
|
+
# Your use of the software is expressly conditioned upon the terms
|
12
|
+
# and conditions available at:
|
13
|
+
#
|
14
|
+
# https://ubiqsecurity.com/legal
|
15
|
+
#
|
16
|
+
|
17
|
+
# frozen_string_literal: true
|
18
|
+
|
19
|
+
module Ubiq
|
20
|
+
VERSION = "1.0.0"
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'lib/ubiq/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "ubiq-security"
|
5
|
+
spec.version = Ubiq::VERSION
|
6
|
+
spec.authors = ["Ubiq Security, Inc."]
|
7
|
+
spec.email = ["support@ubiqsecurity.com"]
|
8
|
+
|
9
|
+
spec.summary = %q{Ruby Client Library for accessing the Ubiq Platform}
|
10
|
+
spec.description = "Provide data encryption to any application with a couple of API calls. " \
|
11
|
+
"See https://www.ubiqsecurity.com for details."
|
12
|
+
spec.homepage = "https://dev.ubiqsecurity.com/docs/ruby-library"
|
13
|
+
spec.license = "Nonstandard"
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = "https://gitlab.com/ubiqsecurity/ubiq-ruby"
|
18
|
+
spec.metadata["changelog_uri"] = "https://gitlab.com/ubiqsecurity/ubiq-ruby/-/blob/master/README.md"
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|example)/}) }
|
24
|
+
end
|
25
|
+
spec.bindir = "exe"
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
spec.add_runtime_dependency 'rb-readline', '~> 0.2', '>= 0.2'
|
29
|
+
spec.add_runtime_dependency 'httparty', '~> 0.15', '>= 0.15'
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ubiq-security
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ubiq Security, Inc.
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rb-readline
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.2'
|
20
|
+
- - "~>"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0.2'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.2'
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0.2'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: httparty
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.15'
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0.15'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0.15'
|
50
|
+
- - "~>"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0.15'
|
53
|
+
description: Provide data encryption to any application with a couple of API calls. See
|
54
|
+
https://www.ubiqsecurity.com for details.
|
55
|
+
email:
|
56
|
+
- support@ubiqsecurity.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- CODE_OF_CONDUCT.md
|
62
|
+
- Gemfile
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- lib/ubiq-security.rb
|
67
|
+
- lib/ubiq/algo.rb
|
68
|
+
- lib/ubiq/auth.rb
|
69
|
+
- lib/ubiq/credentials.rb
|
70
|
+
- lib/ubiq/decrypt.rb
|
71
|
+
- lib/ubiq/encrypt.rb
|
72
|
+
- lib/ubiq/host.rb
|
73
|
+
- lib/ubiq/version.rb
|
74
|
+
- ubiq-security.gemspec
|
75
|
+
homepage: https://dev.ubiqsecurity.com/docs/ruby-library
|
76
|
+
licenses:
|
77
|
+
- Nonstandard
|
78
|
+
metadata:
|
79
|
+
homepage_uri: https://dev.ubiqsecurity.com/docs/ruby-library
|
80
|
+
source_code_uri: https://gitlab.com/ubiqsecurity/ubiq-ruby
|
81
|
+
changelog_uri: https://gitlab.com/ubiqsecurity/ubiq-ruby/-/blob/master/README.md
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 2.3.0
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubygems_version: 3.0.3
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: Ruby Client Library for accessing the Ubiq Platform
|
101
|
+
test_files: []
|