security_client 0.1.0 → 0.1.5
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.
- checksums.yaml +4 -4
- data/README.md +61 -1
- data/lib/security_client.rb +163 -167
- data/lib/security_client/version.rb +1 -1
- data/security_client.gemspec +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 25ec3c95ad9fa1853fed49499126461b7872bb04688a677239ec8c1ad6963e5a
|
|
4
|
+
data.tar.gz: 61975e25115a99c7be9469d08c2ab9543e2923fd9155e657973eee62dba4846a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 371bddc6ede995b027bc0f4933b7352a660ed74875f9bbd5b3059cc65c728fdf5935ea6667c203e78f8f4f5602e3c5ea840eb6bcb881fd5f9226627d4a628f48
|
|
7
|
+
data.tar.gz: 92a9a1a0951cf8c78082795fd597817bc9e46f6f35d2d47a2fa715e2ab3c189fd4e3771aba5d825b261c6fc4d0cc03086929d8f5c64eac6304ddd36ffba82096
|
data/README.md
CHANGED
|
@@ -22,7 +22,67 @@ Or install it yourself as:
|
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
```ruby
|
|
26
|
+
# Initialize the Client
|
|
27
|
+
client = SecurityClient::Voltron.new(
|
|
28
|
+
access_key_id: 'Your access key',
|
|
29
|
+
secret_signing_key: 'Your secret signing key',
|
|
30
|
+
secret_crypto_access_key: 'Your secret crypto access key',
|
|
31
|
+
host: 'Your host'
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Simple Encryption
|
|
35
|
+
encrypted_result = client.encrypt(
|
|
36
|
+
uses: 'Key Uses',
|
|
37
|
+
data: 'Data to be encrypted'
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Simple Decryption
|
|
41
|
+
original_data = client.decrypt(
|
|
42
|
+
data: 'Encrypted Data'
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Piecewise Encryption
|
|
46
|
+
# Get your credentials ready
|
|
47
|
+
credentials = OpenStruct.new(
|
|
48
|
+
access_key_id: 'Your access key',
|
|
49
|
+
secret_signing_key: 'Your secret signing key',
|
|
50
|
+
secret_crypto_access_key: 'Your secret crypto access key',
|
|
51
|
+
host: 'Your host'
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Build the encryption object
|
|
55
|
+
enc = SecurityClient::Encryption.new(credentials, uses)
|
|
56
|
+
# Begin the encryption
|
|
57
|
+
enc.begin()
|
|
58
|
+
# Update the cipher with the raw data, can be supplied directly or in chunks
|
|
59
|
+
enc.update(data)
|
|
60
|
+
# End the encryption
|
|
61
|
+
enc.end()
|
|
62
|
+
# Reset the encryption object to initial state and cleanup the memory in use
|
|
63
|
+
enc.close()
|
|
64
|
+
|
|
65
|
+
# Piecewise Decryption
|
|
66
|
+
# Get your credentials ready
|
|
67
|
+
credentials = OpenStruct.new(
|
|
68
|
+
access_key_id: 'Your access key',
|
|
69
|
+
secret_signing_key: 'Your secret signing key',
|
|
70
|
+
secret_crypto_access_key: 'Your secret crypto access key',
|
|
71
|
+
host: 'Your host'
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Build the decryption object
|
|
75
|
+
dec = SecurityClient::Decryption.new(credentials)
|
|
76
|
+
# Begin the decryption
|
|
77
|
+
dec.begin()
|
|
78
|
+
# Update the cipher with the raw data, can be supplied directly or in chunks
|
|
79
|
+
dec.update(data)
|
|
80
|
+
# End the decryption
|
|
81
|
+
dec.end()
|
|
82
|
+
# Reset the decryption object to initial state and cleanup the memory in use
|
|
83
|
+
dec.close()
|
|
84
|
+
|
|
85
|
+
```
|
|
26
86
|
|
|
27
87
|
## Development
|
|
28
88
|
|
data/lib/security_client.rb
CHANGED
|
@@ -28,7 +28,6 @@ module SecurityClient
|
|
|
28
28
|
enc.close() if enc
|
|
29
29
|
raise
|
|
30
30
|
end
|
|
31
|
-
puts res
|
|
32
31
|
return res
|
|
33
32
|
end
|
|
34
33
|
|
|
@@ -42,7 +41,6 @@ module SecurityClient
|
|
|
42
41
|
dec.close() if dec
|
|
43
42
|
raise
|
|
44
43
|
end
|
|
45
|
-
puts res
|
|
46
44
|
return res
|
|
47
45
|
end
|
|
48
46
|
|
|
@@ -335,7 +333,7 @@ class SecurityClient::Decryption
|
|
|
335
333
|
# Initialize the decryption module object
|
|
336
334
|
# Set the credentials in instance varibales to be used among methods
|
|
337
335
|
# the server to which to make the request
|
|
338
|
-
raise RuntimeError, 'Some of your credentials are missing, please check!' if !validate_creds(creds)
|
|
336
|
+
# raise RuntimeError, 'Some of your credentials are missing, please check!' if !validate_creds(creds)
|
|
339
337
|
@host = creds.host.blank? ? VOLTRON_HOST : creds.host
|
|
340
338
|
|
|
341
339
|
# The client's public API key (used to identify the client to the server
|
|
@@ -350,194 +348,192 @@ class SecurityClient::Decryption
|
|
|
350
348
|
@decryption_ready = true
|
|
351
349
|
@decryption_started = false
|
|
352
350
|
|
|
353
|
-
end
|
|
351
|
+
end
|
|
354
352
|
|
|
355
|
-
def endpoint_base
|
|
356
|
-
|
|
357
|
-
end
|
|
353
|
+
def endpoint_base
|
|
354
|
+
@host + '/api/v0'
|
|
355
|
+
end
|
|
358
356
|
|
|
359
|
-
def endpoint
|
|
360
|
-
|
|
361
|
-
end
|
|
357
|
+
def endpoint
|
|
358
|
+
'/api/v0/decryption/key'
|
|
359
|
+
end
|
|
362
360
|
|
|
363
|
-
def begin
|
|
364
|
-
|
|
361
|
+
def begin
|
|
362
|
+
# Begin the decryption process
|
|
365
363
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
364
|
+
# This interface does not take any cipher text in its arguments
|
|
365
|
+
# in an attempt to maintain an API that corresponds to the
|
|
366
|
+
# encryption object. In doing so, the work that can take place
|
|
367
|
+
# in this function is limited. without any data, there is no
|
|
368
|
+
# way to determine which key is in use or decrypt any data.
|
|
369
|
+
#
|
|
370
|
+
# this function simply throws an error if starting an decryption
|
|
371
|
+
# while one is already in progress, and initializes the internal
|
|
372
|
+
# buffer
|
|
375
373
|
|
|
376
|
-
|
|
374
|
+
raise RuntimeError, 'Decryption is not ready' if !@decryption_ready
|
|
377
375
|
|
|
378
|
-
|
|
376
|
+
raise RuntimeError, 'Decryption Already Started' if @decryption_started
|
|
379
377
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
end
|
|
378
|
+
raise RuntimeError, 'Decryption already in progress' if @key.present? and @key.key?("dec")
|
|
379
|
+
@decryption_started = true
|
|
380
|
+
@data = ''
|
|
381
|
+
end
|
|
384
382
|
|
|
385
|
-
def update(data)
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
383
|
+
def update(data)
|
|
384
|
+
# Decryption of cipher text is performed here
|
|
385
|
+
# Cipher text must be passed to this function in the order in which it was output from the encryption.update function.
|
|
386
|
+
|
|
387
|
+
# Each encryption has a header on it that identifies the algorithm
|
|
388
|
+
# used and an encryption of the data key that was used to encrypt
|
|
389
|
+
# the original plain text. there is no guarantee how much of that
|
|
390
|
+
# data will be passed to this function or how many times this
|
|
391
|
+
# function will be called to process all of the data. to that end,
|
|
392
|
+
# this function buffers data internally, when it is unable to
|
|
393
|
+
# process it.
|
|
394
|
+
#
|
|
395
|
+
# The function buffers data internally until the entire header is
|
|
396
|
+
# received. once the header has been received, the encrypted data
|
|
397
|
+
# key is sent to the server for decryption. after the header has
|
|
398
|
+
# been successfully handled, this function always decrypts all of
|
|
399
|
+
# the data in its internal buffer *except* for however many bytes
|
|
400
|
+
# are specified by the algorithm's tag size. see the end() function
|
|
401
|
+
# for details.
|
|
402
|
+
|
|
403
|
+
raise RuntimeError, 'Decryption is not Started' if !@decryption_started
|
|
404
|
+
|
|
405
|
+
# Append the incoming data in the internal data buffer
|
|
406
|
+
@data = @data + data
|
|
407
|
+
|
|
408
|
+
# if there is no key or 'dec' member of key, then the code is still trying to build a complete header
|
|
409
|
+
if !@key.present? or !@key.key?("dec")
|
|
410
|
+
struct_length = [1,1,1,1,1].pack('CCCCn').length
|
|
411
|
+
packed_struct = @data[0...struct_length]
|
|
412
|
+
|
|
413
|
+
# Does the buffer contain enough of the header to
|
|
414
|
+
# determine the lengths of the initialization vector
|
|
415
|
+
# and the key?
|
|
416
|
+
if @data.length > struct_length
|
|
417
|
+
# Unpack the values packed in encryption
|
|
418
|
+
version, flag_for_later, algorithm_id, iv_length, key_length = packed_struct.unpack('CCCCn')
|
|
419
|
+
|
|
420
|
+
# verify flag and version are 0
|
|
421
|
+
raise RuntimeError, 'invalid encryption header' if version != 0 or flag_for_later != 0
|
|
422
|
+
|
|
423
|
+
# Does the buffer contain the entire header?
|
|
424
|
+
if @data.length > struct_length + iv_length + key_length
|
|
425
|
+
# Extract the initialization vector
|
|
426
|
+
iv = @data[struct_length...iv_length + struct_length]
|
|
427
|
+
# Extract the encryped key
|
|
428
|
+
encrypted_key = @data[struct_length + iv_length...key_length + struct_length + iv_length]
|
|
429
|
+
# Remove the header from the buffer
|
|
430
|
+
@data = @data[struct_length + iv_length + key_length..-1]
|
|
431
|
+
|
|
432
|
+
# generate a local identifier for the key
|
|
433
|
+
hash_sha512 = OpenSSL::Digest::SHA512.new
|
|
434
|
+
hash_sha512 << encrypted_key
|
|
435
|
+
client_id = hash_sha512.digest
|
|
436
|
+
|
|
437
|
+
if @key.present?
|
|
438
|
+
if @key['client_id'] != client_id
|
|
439
|
+
close()
|
|
440
|
+
end
|
|
442
441
|
end
|
|
443
|
-
end
|
|
444
442
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
443
|
+
# IF key object not exists, request a new one from the server
|
|
444
|
+
if !@key.present?
|
|
445
|
+
url = endpoint_base + "/decryption/key"
|
|
446
|
+
query = {encrypted_data_key: Base64.strict_encode64(encrypted_key)}
|
|
447
|
+
headers = Auth.build_headers(@papi, @sapi, endpoint, query, @host, 'post')
|
|
448
|
+
|
|
449
|
+
response = HTTParty.post(
|
|
450
|
+
url,
|
|
451
|
+
body: query.to_json,
|
|
452
|
+
headers: headers
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
# Response status is 200 OK
|
|
456
|
+
if response.code == WEBrick::HTTPStatus::RC_OK
|
|
457
|
+
@key = {}
|
|
458
|
+
@key['finger_print'] = response['key_fingerprint']
|
|
459
|
+
@key['client_id'] = client_id
|
|
460
|
+
@key['session'] = response['encryption_session']
|
|
461
|
+
|
|
462
|
+
@key['algorithm'] = 'aes-256-gcm'
|
|
463
|
+
|
|
464
|
+
encrypted_private_key = response['encrypted_private_key']
|
|
465
|
+
# Decrypt the encryped private key using SRSA
|
|
466
|
+
private_key = OpenSSL::PKey::RSA.new(encrypted_private_key,@srsa)
|
|
467
|
+
|
|
468
|
+
wrapped_data_key = response['wrapped_data_key']
|
|
469
|
+
# Decode WDK from base64 format
|
|
470
|
+
wdk = Base64.strict_decode64(wrapped_data_key)
|
|
471
|
+
# Use private key to decrypt the wrapped data key
|
|
472
|
+
dk = private_key.private_decrypt(wdk,OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
|
|
473
|
+
|
|
474
|
+
@key['raw'] = dk
|
|
475
|
+
@key['uses'] = 0
|
|
476
|
+
else
|
|
477
|
+
# Raise the error if response is not 200
|
|
478
|
+
raise RuntimeError, "HTTPError Response: Expected 201, got #{response.code}"
|
|
479
|
+
end
|
|
481
480
|
end
|
|
482
|
-
end
|
|
483
481
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
482
|
+
# If the key object exists, create a new decryptor
|
|
483
|
+
# with the initialization vector from the header and
|
|
484
|
+
# the decrypted key (which is either new from the
|
|
485
|
+
# server or cached from the previous decryption). in
|
|
486
|
+
# either case, increment the key usage
|
|
489
487
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
488
|
+
if @key.present?
|
|
489
|
+
@algo = Algo.new.get_algo(@key['algorithm'])
|
|
490
|
+
@key['dec'] = Algo.new.decryptor(@algo, @key['raw'], iv)
|
|
491
|
+
@key['uses'] += 1
|
|
492
|
+
end
|
|
494
493
|
end
|
|
495
494
|
end
|
|
496
495
|
end
|
|
497
|
-
end
|
|
498
496
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
497
|
+
# if the object has a key and a decryptor, then decrypt whatever
|
|
498
|
+
# data is in the buffer, less any data that needs to be saved to
|
|
499
|
+
# serve as the tag.
|
|
500
|
+
plain_text = ''
|
|
501
|
+
if @key.present? and @key.key?("dec")
|
|
502
|
+
size = @data.length - @algo[:tag_length]
|
|
503
|
+
if size > 0
|
|
504
|
+
plain_text = @key['dec'].update(@data[0..size-1])
|
|
505
|
+
@data = @data[size..-1]
|
|
506
|
+
end
|
|
507
|
+
return plain_text
|
|
510
508
|
end
|
|
511
|
-
return plain_text
|
|
512
|
-
end
|
|
513
509
|
|
|
514
|
-
end
|
|
510
|
+
end
|
|
515
511
|
|
|
516
|
-
def end
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
512
|
+
def end
|
|
513
|
+
raise RuntimeError, 'Decryption is not Started' if !@decryption_started
|
|
514
|
+
# The update function always maintains tag-size bytes in
|
|
515
|
+
# the buffer because this function provides no data parameter.
|
|
516
|
+
# by the time the caller calls this function, all data must
|
|
517
|
+
# have already been input to the decryption object.
|
|
522
518
|
|
|
523
|
-
|
|
519
|
+
sz = @data.length - @algo[:tag_length]
|
|
524
520
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
521
|
+
raise RuntimeError, 'Invalid Tag!' if sz < 0
|
|
522
|
+
if sz == 0
|
|
523
|
+
@key['dec'].auth_tag = @data
|
|
524
|
+
begin
|
|
525
|
+
pt = @key['dec'].final
|
|
526
|
+
# Delete the decryptor context
|
|
527
|
+
@key.delete('dec')
|
|
528
|
+
# Return the decrypted plain data
|
|
529
|
+
@decryption_started = false
|
|
530
|
+
return pt
|
|
531
|
+
rescue Exception => e
|
|
532
|
+
print 'Invalid cipher data or tag!'
|
|
533
|
+
return ''
|
|
534
|
+
end
|
|
538
535
|
end
|
|
539
536
|
end
|
|
540
|
-
end
|
|
541
537
|
|
|
542
538
|
def close
|
|
543
539
|
raise RuntimeError, 'Decryption currently running' if @decryption_started
|
data/security_client.gemspec
CHANGED
|
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.email = ["vinay.ymca@gmail.com"]
|
|
10
10
|
|
|
11
11
|
spec.summary = %q{Ubiq Security ruby client}
|
|
12
|
-
|
|
12
|
+
spec.homepage = "https://github.com/vinaymehta/security_client"
|
|
13
13
|
# Specify which files should be added to the gem when it is released.
|
|
14
14
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: security_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- vinaymehta
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-08-
|
|
11
|
+
date: 2020-08-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -70,7 +70,7 @@ files:
|
|
|
70
70
|
- lib/security_client.rb
|
|
71
71
|
- lib/security_client/version.rb
|
|
72
72
|
- security_client.gemspec
|
|
73
|
-
homepage:
|
|
73
|
+
homepage: https://github.com/vinaymehta/security_client
|
|
74
74
|
licenses: []
|
|
75
75
|
metadata: {}
|
|
76
76
|
post_install_message:
|