security_client 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/security_client.rb +164 -164
- data/lib/security_client/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7640165682c873870551c45afd84185c197cfeb8a00ca31b8f52ceabe500168e
|
4
|
+
data.tar.gz: c413c6901b56ff802ea984cec4b36616113254add9c06e96cb1c6235e6ee7787
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3586c80fb88719b618ed1ff4bebb50c3c3fbfb5f87d5b3e7144e8b6ceda8046a4452c339251ed849551480d02a8de1b599f1cb12b673b0b94b89220bee00c33
|
7
|
+
data.tar.gz: 7e5bdd1ef3c9bf4d1e76b1d1503f1a32122891ebfee8250b4db2ce9bda381bd99ec5c84e59b42a98b1dd9c81afaaab685ae04d189a288bce98787ade279a9862
|
data/lib/security_client.rb
CHANGED
@@ -350,194 +350,194 @@ class SecurityClient::Decryption
|
|
350
350
|
@decryption_ready = true
|
351
351
|
@decryption_started = false
|
352
352
|
|
353
|
-
end
|
353
|
+
end
|
354
354
|
|
355
|
-
def endpoint_base
|
356
|
-
|
357
|
-
end
|
355
|
+
def endpoint_base
|
356
|
+
@host + '/api/v0'
|
357
|
+
end
|
358
358
|
|
359
|
-
def endpoint
|
360
|
-
|
361
|
-
end
|
359
|
+
def endpoint
|
360
|
+
'/api/v0/decryption/key'
|
361
|
+
end
|
362
362
|
|
363
|
-
def begin
|
364
|
-
|
363
|
+
def begin
|
364
|
+
# Begin the decryption process
|
365
365
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
366
|
+
# This interface does not take any cipher text in its arguments
|
367
|
+
# in an attempt to maintain an API that corresponds to the
|
368
|
+
# encryption object. In doing so, the work that can take place
|
369
|
+
# in this function is limited. without any data, there is no
|
370
|
+
# way to determine which key is in use or decrypt any data.
|
371
|
+
#
|
372
|
+
# this function simply throws an error if starting an decryption
|
373
|
+
# while one is already in progress, and initializes the internal
|
374
|
+
# buffer
|
375
375
|
|
376
|
-
|
376
|
+
raise RuntimeError, 'Decryption is not ready' if !@decryption_ready
|
377
377
|
|
378
|
-
|
378
|
+
raise RuntimeError, 'Decryption Already Started' if @decryption_started
|
379
379
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
end
|
380
|
+
raise RuntimeError, 'Decryption already in progress' if @key.present? and @key.key?("dec")
|
381
|
+
@decryption_started = true
|
382
|
+
@data = ''
|
383
|
+
end
|
384
384
|
|
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
|
-
|
385
|
+
def update(data)
|
386
|
+
# Decryption of cipher text is performed here
|
387
|
+
# Cipher text must be passed to this function in the order in which it was output from the encryption.update function.
|
388
|
+
|
389
|
+
# Each encryption has a header on it that identifies the algorithm
|
390
|
+
# used and an encryption of the data key that was used to encrypt
|
391
|
+
# the original plain text. there is no guarantee how much of that
|
392
|
+
# data will be passed to this function or how many times this
|
393
|
+
# function will be called to process all of the data. to that end,
|
394
|
+
# this function buffers data internally, when it is unable to
|
395
|
+
# process it.
|
396
|
+
#
|
397
|
+
# The function buffers data internally until the entire header is
|
398
|
+
# received. once the header has been received, the encrypted data
|
399
|
+
# key is sent to the server for decryption. after the header has
|
400
|
+
# been successfully handled, this function always decrypts all of
|
401
|
+
# the data in its internal buffer *except* for however many bytes
|
402
|
+
# are specified by the algorithm's tag size. see the end() function
|
403
|
+
# for details.
|
404
|
+
|
405
|
+
raise RuntimeError, 'Decryption is not Started' if !@decryption_started
|
406
|
+
|
407
|
+
# Append the incoming data in the internal data buffer
|
408
|
+
@data = @data + data
|
409
|
+
|
410
|
+
# if there is no key or 'dec' member of key, then the code is still trying to build a complete header
|
411
|
+
if !@key.present? or !@key.key?("dec")
|
412
|
+
struct_length = [1,1,1,1,1].pack('CCCCn').length
|
413
|
+
packed_struct = @data[0...struct_length]
|
414
|
+
|
415
|
+
# Does the buffer contain enough of the header to
|
416
|
+
# determine the lengths of the initialization vector
|
417
|
+
# and the key?
|
418
|
+
if @data.length > struct_length
|
419
|
+
# Unpack the values packed in encryption
|
420
|
+
version, flag_for_later, algorithm_id, iv_length, key_length = packed_struct.unpack('CCCCn')
|
421
|
+
|
422
|
+
# verify flag and version are 0
|
423
|
+
raise RuntimeError, 'invalid encryption header' if version != 0 or flag_for_later != 0
|
424
|
+
|
425
|
+
# Does the buffer contain the entire header?
|
426
|
+
if @data.length > struct_length + iv_length + key_length
|
427
|
+
# Extract the initialization vector
|
428
|
+
iv = @data[struct_length...iv_length + struct_length]
|
429
|
+
# Extract the encryped key
|
430
|
+
encrypted_key = @data[struct_length + iv_length...key_length + struct_length + iv_length]
|
431
|
+
# Remove the header from the buffer
|
432
|
+
@data = @data[struct_length + iv_length + key_length..-1]
|
433
|
+
|
434
|
+
# generate a local identifier for the key
|
435
|
+
hash_sha512 = OpenSSL::Digest::SHA512.new
|
436
|
+
hash_sha512 << encrypted_key
|
437
|
+
client_id = hash_sha512.digest
|
438
|
+
|
439
|
+
if @key.present?
|
440
|
+
if @key['client_id'] != client_id
|
441
|
+
close()
|
442
|
+
end
|
442
443
|
end
|
443
|
-
end
|
444
444
|
|
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
|
-
|
445
|
+
# IF key object not exists, request a new one from the server
|
446
|
+
if !@key.present?
|
447
|
+
url = endpoint_base + "/decryption/key"
|
448
|
+
query = {encrypted_data_key: Base64.strict_encode64(encrypted_key)}
|
449
|
+
headers = Auth.build_headers(@papi, @sapi, endpoint, query, @host, 'post')
|
450
|
+
|
451
|
+
response = HTTParty.post(
|
452
|
+
url,
|
453
|
+
body: query.to_json,
|
454
|
+
headers: headers
|
455
|
+
)
|
456
|
+
|
457
|
+
# Response status is 200 OK
|
458
|
+
if response.code == WEBrick::HTTPStatus::RC_OK
|
459
|
+
@key = {}
|
460
|
+
@key['finger_print'] = response['key_fingerprint']
|
461
|
+
@key['client_id'] = client_id
|
462
|
+
@key['session'] = response['encryption_session']
|
463
|
+
|
464
|
+
@key['algorithm'] = 'aes-256-gcm'
|
465
|
+
|
466
|
+
encrypted_private_key = response['encrypted_private_key']
|
467
|
+
# Decrypt the encryped private key using SRSA
|
468
|
+
private_key = OpenSSL::PKey::RSA.new(encrypted_private_key,@srsa)
|
469
|
+
|
470
|
+
wrapped_data_key = response['wrapped_data_key']
|
471
|
+
# Decode WDK from base64 format
|
472
|
+
wdk = Base64.strict_decode64(wrapped_data_key)
|
473
|
+
# Use private key to decrypt the wrapped data key
|
474
|
+
dk = private_key.private_decrypt(wdk,OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
|
475
|
+
|
476
|
+
@key['raw'] = dk
|
477
|
+
@key['uses'] = 0
|
478
|
+
else
|
479
|
+
# Raise the error if response is not 200
|
480
|
+
raise RuntimeError, "HTTPError Response: Expected 201, got #{response.code}"
|
481
|
+
end
|
481
482
|
end
|
482
|
-
end
|
483
483
|
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
484
|
+
# If the key object exists, create a new decryptor
|
485
|
+
# with the initialization vector from the header and
|
486
|
+
# the decrypted key (which is either new from the
|
487
|
+
# server or cached from the previous decryption). in
|
488
|
+
# either case, increment the key usage
|
489
489
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
490
|
+
if @key.present?
|
491
|
+
@algo = Algo.new.get_algo(@key['algorithm'])
|
492
|
+
@key['dec'] = Algo.new.decryptor(@algo, @key['raw'], iv)
|
493
|
+
@key['uses'] += 1
|
494
|
+
end
|
494
495
|
end
|
495
496
|
end
|
496
497
|
end
|
497
|
-
end
|
498
498
|
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
499
|
+
# if the object has a key and a decryptor, then decrypt whatever
|
500
|
+
# data is in the buffer, less any data that needs to be saved to
|
501
|
+
# serve as the tag.
|
502
|
+
plain_text = ''
|
503
|
+
if @key.present? and @key.key?("dec")
|
504
|
+
size = @data.length - @algo[:tag_length]
|
505
|
+
if size > 0
|
506
|
+
puts @data[0..size-1]
|
507
|
+
|
508
|
+
plain_text = @key['dec'].update(@data[0..size-1])
|
509
|
+
@data = @data[size..-1]
|
510
|
+
end
|
511
|
+
return plain_text
|
510
512
|
end
|
511
|
-
return plain_text
|
512
|
-
end
|
513
513
|
|
514
|
-
end
|
514
|
+
end
|
515
515
|
|
516
|
-
def end
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
516
|
+
def end
|
517
|
+
raise RuntimeError, 'Decryption is not Started' if !@decryption_started
|
518
|
+
# The update function always maintains tag-size bytes in
|
519
|
+
# the buffer because this function provides no data parameter.
|
520
|
+
# by the time the caller calls this function, all data must
|
521
|
+
# have already been input to the decryption object.
|
522
522
|
|
523
|
-
|
523
|
+
sz = @data.length - @algo[:tag_length]
|
524
524
|
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
525
|
+
raise RuntimeError, 'Invalid Tag!' if sz < 0
|
526
|
+
if sz == 0
|
527
|
+
@key['dec'].auth_tag = @data
|
528
|
+
begin
|
529
|
+
pt = @key['dec'].final
|
530
|
+
# Delete the decryptor context
|
531
|
+
@key.delete('dec')
|
532
|
+
# Return the decrypted plain data
|
533
|
+
@decryption_started = false
|
534
|
+
return pt
|
535
|
+
rescue Exception => e
|
536
|
+
print 'Invalid cipher data or tag!'
|
537
|
+
return ''
|
538
|
+
end
|
538
539
|
end
|
539
540
|
end
|
540
|
-
end
|
541
541
|
|
542
542
|
def close
|
543
543
|
raise RuntimeError, 'Decryption currently running' if @decryption_started
|