class Ubiq::Encryption
Ubiq
Encryption
object This object represents a single data encryption key and can be used to encrypt several separate plain texts using the same key
Public Class Methods
new(creds, uses)
click to toggle source
# File lib/ubiq/encrypt.rb, line 16 def initialize(creds, uses) raise 'Some of your credentials are missing, please check!' unless validate_creds(creds) # Set host, either the default or the one given by caller @host = creds.host.blank? ? UBIQ_HOST : creds.host # Set the credentials in instance varibales to be used among methods # The client's public API key (used to identify the client to the server @papi = creds.access_key_id # The client's secret API key (used to authenticate HTTP requests) @sapi = creds.secret_signing_key # 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. @srsa = creds.secret_crypto_access_key # Build the endpoint URL url = endpoint_base + '/encryption/key' # Build the Request Body with the number of uses of key query = { uses: uses } # Retrieve the necessary headers to make the request using Auth Object headers = Auth.build_headers(@papi, @sapi, endpoint, query, @host, 'post') @encryption_started = false @encryption_ready = true # Request a new encryption key from the server. if the request # fails, the function raises a HTTPError indicating # the status code returned by the server. this exception is # propagated back to the caller begin response = HTTParty.post( url, body: query.to_json, headers: headers ) rescue HTTParty::Error raise 'Cant reach server' end # Response status is 201 Created if response.code == WEBrick::HTTPStatus::RC_CREATED # The code below largely assumes that the server returns # a json object that contains the members and is formatted # according to the Ubiq REST specification. # Build the key object @key = {} @key['id'] = response['key_fingerprint'] @key['session'] = response['encryption_session'] @key['security_model'] = response['security_model'] @key['algorithm'] = response['security_model']['algorithm'].downcase @key['max_uses'] = response['max_uses'] @key['uses'] = 0 @key['encrypted'] = Base64.strict_decode64(response['encrypted_data_key']) # Get encrypted private key from response body encrypted_private_key = response['encrypted_private_key'] # Get wrapped data key from response body wrapped_data_key = response['wrapped_data_key'] # Decrypt the encryped private key using @srsa supplied private_key = OpenSSL::PKey::RSA.new(encrypted_private_key, @srsa) # Decode WDK from base64 format wdk = Base64.strict_decode64(wrapped_data_key) # Use private key to decrypt the wrapped data key dk = private_key.private_decrypt(wdk, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING) @key['raw'] = dk # Build the algorithm object @algo = Algo.new.get_algo(@key['algorithm']) else # Raise the error if response is not 201 raise "HTTPError Response: Expected 201, got #{response.code}" end end
Public Instance Methods
begin()
click to toggle source
# File lib/ubiq/encrypt.rb, line 95 def begin # Begin the encryption process # When this function is called, the encryption object increments # the number of uses of the key and creates a new internal context # to be used to encrypt the data. # If the encryption object is not yet ready to be used, throw an error raise 'Encryption not ready' unless @encryption_ready # if Encryption cipher context already exists raise 'Encryption already in progress' if @encryption_started # If max uses > uses raise 'Maximum key uses exceeded' if @key['uses'] >= @key['max_uses'] @key['uses'] += 1 # create a new Encryption context and initialization vector @enc, @iv = Algo.new.encryptor(@algo, @key['raw']) # Pack the result into bytes to get a byte string struct = [0, Algo::UBIQ_HEADER_V0_FLAG_AAD, @algo[:id], @iv.length, @key['encrypted'].length].pack('CCCCn') @enc.auth_data = struct + @iv + @key['encrypted'] @encryption_started = true return struct + @iv + @key['encrypted'] end
close()
click to toggle source
# File lib/ubiq/encrypt.rb, line 148 def close raise 'Encryption currently running' if @encryption_started # If the key was used less times than was requested, send an update to the server if @key['uses'] < @key['max_uses'] query_url = "#{endpoint}/#{@key['id']}/#{@key['session']}" url = "#{endpoint_base}/encryption/key/#{@key['id']}/#{@key['session']}" query = { actual: @key['uses'], requested: @key['max_uses'] } headers = Auth.build_headers(@papi, @sapi, query_url, query, @host, 'patch') response = HTTParty.patch( url, body: query.to_json, headers: headers ) remove_instance_variable(:@key) @encryption_ready = false end end
end()
click to toggle source
# File lib/ubiq/encrypt.rb, line 129 def end raise 'Encryption is not Started' unless @encryption_started # This function finalizes the encryption (producing the final # cipher text for the encryption, if necessary) and adds any # authentication information (if required by the algorithm). # Any data produced is returned by the function. # Finalize an encryption res = @enc.final if @algo[:tag_length] != 0 # Add the tag to the cipher text res += @enc.auth_tag end @encryption_started = false # Return the encrypted result return res end
endpoint()
click to toggle source
# File lib/ubiq/encrypt.rb, line 171 def endpoint '/api/v0/encryption/key' end
endpoint_base()
click to toggle source
# File lib/ubiq/encrypt.rb, line 167 def endpoint_base @host + '/api/v0' end
update(data)
click to toggle source
# File lib/ubiq/encrypt.rb, line 121 def update(data) raise 'Encryption is not Started' unless @encryption_started # Encryption of some plain text is perfomed here # Any cipher text produced by the operation is returned @enc.update(data) end
validate_creds(credentials)
click to toggle source
# File lib/ubiq/encrypt.rb, line 175 def validate_creds(credentials) # This method checks for the presence of the credentials !credentials.access_key_id.blank? && !credentials.secret_signing_key.blank? && !credentials.secret_crypto_access_key.blank? end