Class: Cryptograpi::Encryption

Inherits:
Object
  • Object
show all
Defined in:
lib/cryptograpi_ruby/encrypt.rb

Instance Method Summary collapse

Constructor Details

#initialize(creds, uses) ⇒ Encryption

Returns a new instance of Encryption.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 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

Instance Method Details

#begin_encryptionObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 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_encryptionObject



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# 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

#endpointObject



128
129
130
# File 'lib/cryptograpi_ruby/encrypt.rb', line 128

def endpoint
  '/api/v0/encryption/key'
end

#endpoint_baseObject



132
133
134
# File 'lib/cryptograpi_ruby/encrypt.rb', line 132

def endpoint_base
  "#{@host}/api/v0"
end

#finish_encryptionObject



94
95
96
97
98
99
100
101
102
103
104
105
106
107
# 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) ⇒ Object



88
89
90
91
92
# 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) ⇒ Object



136
137
138
139
140
# 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