Module: Aws::Sigv4::AsymmetricCredentials Private

Defined in:
lib/aws-sigv4/asymmetric_credentials.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

To make it easier to support mixed mode, we have created an asymmetric key derivation mechanism. This module derives asymmetric keys from the current secret for use with Asymmetric signatures.

Constant Summary collapse

N_MINUS_2 =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 - 2

Class Method Summary collapse

Class Method Details

.derive_asymmetric_key(access_key_id, secret_access_key) ⇒ OpenSSL::PKey::EC, Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (OpenSSL::PKey::EC, Hash)


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
# File 'lib/aws-sigv4/asymmetric_credentials.rb', line 15

def self.derive_asymmetric_key(access_key_id, secret_access_key)
  check_openssl_support!
  label = 'AWS4-ECDSA-P256-SHA256'
  bit_len = 256
  counter = 0x1
  input_key = "AWS4A#{secret_access_key}"
  d = 0 # d will end up being the private key
  while true do

    kdf_context = access_key_id.unpack('C*') + [counter].pack('C').unpack('C') #1 byte for counter
    input = label.unpack('C*') + [0x00] + kdf_context + [bit_len].pack('L>').unpack('CCCC') # 4 bytes (change endianess)
    k0 = OpenSSL::HMAC.digest("SHA256", input_key, ([0, 0, 0, 0x01] + input).pack('C*'))
    c = be_bytes_to_num( k0.unpack('C*') )
    if c <= N_MINUS_2
      d = c + 1
      break
    elsif counter > 0xFF
      raise 'Counter exceeded 1 byte - unable to get asym creds'
    else
      counter += 1
    end
  end

  # compute the public key
  group = OpenSSL::PKey::EC::Group.new('prime256v1')
  public_key = group.generator.mul(d)

  ec = generate_ec(public_key, d)

  # pk_x and pk_y are not needed for signature, but useful in verification/testing
  pk_b = public_key.to_octet_string(:uncompressed).unpack('C*') # 0x04 byte followed by 2 32-byte integers
  pk_x = be_bytes_to_num(pk_b[1,32])
  pk_y = be_bytes_to_num(pk_b[33,32])
  [ec, {ec: ec, public_key: public_key, pk_x: pk_x, pk_y: pk_y, d: d}]
end