Class: Clarion::Key

Inherits:
Object
  • Object
show all
Defined in:
lib/clarion/key.rb

Constant Summary collapse

CIPHER_ALGO =
'aes-256-gcm'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(handle:, type: 'fido-legacy', name: nil, public_key: nil, counter: nil, user_handle: nil) ⇒ Key

Returns a new instance of Key.



29
30
31
32
33
34
35
36
# File 'lib/clarion/key.rb', line 29

def initialize(handle:, type: 'fido-legacy', name: nil, public_key: nil, counter: nil, user_handle: nil)
  @type = type
  @handle = handle
  @user_handle = user_handle
  @name = name
  @public_key = public_key
  @counter = counter
end

Instance Attribute Details

#counterObject

Returns the value of attribute counter.



39
40
41
# File 'lib/clarion/key.rb', line 39

def counter
  @counter
end

#handleObject (readonly)

Returns the value of attribute handle.



38
39
40
# File 'lib/clarion/key.rb', line 38

def handle
  @handle
end

#nameObject

Returns the value of attribute name.



39
40
41
# File 'lib/clarion/key.rb', line 39

def name
  @name
end

#public_keyObject (readonly)

Returns the value of attribute public_key.



38
39
40
# File 'lib/clarion/key.rb', line 38

def public_key
  @public_key
end

#typeObject (readonly)

Returns the value of attribute type.



38
39
40
# File 'lib/clarion/key.rb', line 38

def type
  @type
end

#user_handleObject (readonly)

Returns the value of attribute user_handle.



38
39
40
# File 'lib/clarion/key.rb', line 38

def user_handle
  @user_handle
end

Class Method Details

.from_encrypted_json(private_key, json) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/clarion/key.rb', line 4

def self.from_encrypted_json(private_key, json)
  payload = JSON.parse(json, symbolize_names: true)
  encrypted_data = payload.fetch(:data).unpack('m*')[0]
  encrypted_shared_key = payload.fetch(:key).unpack('m*')[0]

  shared_key_json = private_key.private_decrypt(encrypted_shared_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
  shared_key_info = JSON.parse(shared_key_json, symbolize_names: true)
  iv = shared_key_info.fetch(:iv).unpack('m*')[0]
  shared_key = shared_key_info.fetch(:key).unpack('m*')[0]
  tag = shared_key_info.fetch(:tag).unpack('m*')[0]

  cipher = OpenSSL::Cipher.new(CIPHER_ALGO).tap do |c|
      c.decrypt
      c.key = shared_key
      c.iv = iv
      c.auth_data = ''
      c.auth_tag = tag
  end

  key_json = cipher.update(encrypted_data)
  key_json << cipher.final
  key = JSON.parse(key_json, symbolize_names: true)
  new(**key)
end

Instance Method Details

#public_key_bytesObject



54
55
56
# File 'lib/clarion/key.rb', line 54

def public_key_bytes
  public_key.unpack('m*')[0]
end

#to_encrypted_json(public_key, *args) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/clarion/key.rb', line 62

def to_encrypted_json(public_key, *args)
  cipher = OpenSSL::Cipher.new(CIPHER_ALGO)
  shared_key = OpenSSL::Random.random_bytes(cipher.key_len)
  cipher.encrypt
  cipher.key = shared_key
  cipher.iv = iv = cipher.random_iv
  cipher.auth_data = ''

  json = to_json(*args)

  ciphertext = cipher.update(json)
  ciphertext << cipher.final

  encrypted_key = public_key.public_encrypt({
    iv: [iv].pack('m*').gsub(/\r?\n/,''),
    tag: [cipher.auth_tag].pack('m*').gsub(/\r?\n/,''),
    key: [shared_key].pack('m*').gsub(/\r?\n/,''),
  }.to_json, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
  {data: [ciphertext].pack('m*'), key: [encrypted_key].pack('m*')}.to_json
end

#to_h(all = false) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/clarion/key.rb', line 41

def to_h(all=false)
  {
    type: type,
    handle: handle,
  }.tap do |h|
    h[:name] = name if name
    h[:counter] = counter if counter
    if all
      h[:public_key] = public_key if public_key
    end
  end
end

#to_json(*args) ⇒ Object



58
59
60
# File 'lib/clarion/key.rb', line 58

def to_json(*args)
  to_h(*args).to_json
end