class Cryptograpi::Encryption

Public Class Methods

new(creds, uses) click to toggle source
# File lib/cryptograpi_ruby/encrypt.rb, line 10
def initialize(creds, uses)
  raise 'Some credentials are missing' unless validate_credentials(creds)

  @papi = creds.access_key_id
  @sapi = creds.signing_key
  @srsa = creds.secret_access_key
  @host = creds.host.blank? ? CRYPTOGRAPI_HOST : creds.host
  url = "#{endpoint_base}/encryption/key"
  query = { uses: uses }
  headers = Signature.headers(endpoint, @host, 'post', @papi, query, @sapi)

  @encryption_started = false
  @encryption_ready = true

  # First, ask for a key from the server.
  # If the request fails, raise a HTTPError.

  begin
    response = HTTParty.post(
      url,
      body: query.to_json,
      headers: headers
    )
  rescue HTTParty::Error
    raise 'Server Unreachable'
  end

  if response.code == WEBrick::HTTPStatus::RC_CREATED
    # Builds 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 the encrypted private key from response body
    encrypted_pk = response['encrypted_private_key']
    # Data key from response body
    wrapped_data_key = response['wrapped_data_key']
    # decrypt the encrypted private key using @srsa
    pk = OpenSSL::PKey::RSA.new(encrypted_pk, @srsa)
    # Decode WDK from base64 format
    wdk = Base64.strict_decode64(wrapped_data_key)
    # Use private key to decrypt the wrapped data key
    dk = pk.private_decrypt(wdk, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
    @key['raw'] = dk
    @cipher = Cipher.new.get_algorithm(@key['algorithm'])
  else
    raise "HTTPError Response: Expected 201, got #{response.code}"
  end
end

Public Instance Methods

begin_encryption() click to toggle source
# File lib/cryptograpi_ruby/encrypt.rb, line 65
def begin_encryption
  # Begins the encryption process
  # Each time this function is called, uses increments by 1
  raise 'Encryption not ready' unless @encryption_ready
  # cipher already exists
  raise 'Encryption in progress' if @encryption_started
  # Check for max uses flag
  raise 'Maximum usage exceeded' if @key['uses'] >= @key["max_uses"]

  # Increase the uses counter
  @key['uses'] += 1
  # New context and initialization vector
  @enc, @iv = Cipher.new.encryptor(@cipher, @key['raw'])
  # Pack and create a byte string
  struct = [0, Cipher::CRYPTOFLAG, @cipher[:id], @iv.length, @key['encrypted'].length].pack('CCCCn')

  @enc.auth_data = struct + @iv + @key['encrypted']
  @encryption_started = true

  # Return the encrypted object
  struct + @iv + @key['encrypted']
end
close_encryption() click to toggle source
# File lib/cryptograpi_ruby/encrypt.rb, line 109
def close_encryption
  raise 'Encryption currently running' if @encryption_started

  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 = Signature.headers(query_url, @host, 'patch', @papi, query, @sapi)

    response = HTTParty.patch(
      url,
      body: query.to_json,
      headers: headers
    )
    remove_instance_variable(:@key)
    @encryption_ready = false
  end
end
endpoint() click to toggle source
# File lib/cryptograpi_ruby/encrypt.rb, line 128
def endpoint
  '/api/v0/encryption/key'
end
endpoint_base() click to toggle source
# File lib/cryptograpi_ruby/encrypt.rb, line 132
def endpoint_base
  "#{@host}/api/v0"
end
finish_encryption() click to toggle source
# File lib/cryptograpi_ruby/encrypt.rb, line 94
def finish_encryption
  raise 'Encryption not started' unless @encryption_started

  # Finalizes the encryption and adds any auth info required by the algorithm
  res = @enc.final
  if @cipher[:tag_length] != 0
    # Add the tag to the cipher text
    res += @enc.auth_tag
  end

  @encryption_started = false
  # return the encrypted result
  res
end
update_encryption(data) click to toggle source
# File lib/cryptograpi_ruby/encrypt.rb, line 88
def update_encryption(data)
  raise 'Encryption has not started yet' unless @encryption_started

  @enc.update(data)
end
validate_credentials(credentials) click to toggle source
# File lib/cryptograpi_ruby/encrypt.rb, line 136
def validate_credentials(credentials)
  !credentials.access_key_id.blank? &&
    !credentials.secret_access_key.blank? &&
    !credentials.signing_key.blank?
end