Class: JOSE::JWK::KTY_OKP_Ed25519

Inherits:
Struct
  • Object
show all
Defined in:
lib/jose/jwk/kty_okp_ed25519.rb

Constant Summary collapse

SECRET_BYTES =
32
PK_BYTES =
32
SK_BYTES =
SECRET_BYTES + PK_BYTES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#okpObject

Returns the value of attribute okp


1
2
3
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 1

def okp
  @okp
end

Class Method Details

.from_map(fields) ⇒ Object

JOSE::JWK callbacks

Raises:

  • (ArgumentError)

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 9

def self.from_map(fields)
  if fields['kty'] == 'OKP' and fields['crv'] == 'Ed25519' and fields['x'].is_a?(String)
    pk = JOSE.urlsafe_decode64(fields['x'])
    secret = nil
    if fields['d'].is_a?(String)
      secret = JOSE.urlsafe_decode64(fields['d'])
    end
    if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES)
      if secret.nil?
        return JOSE::JWK::KTY_OKP_Ed25519.new(pk), fields.except('kty', 'crv', 'x')
      else
        return JOSE::JWK::KTY_OKP_Ed25519.new(secret + pk), fields.except('kty', 'crv', 'x', 'd')
      end
    end
  end
  raise ArgumentError, "invalid 'OKP' crv 'Ed25519' JWK"
end

.from_okp(okp) ⇒ Object

API functions


106
107
108
109
110
111
112
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 106

def self.from_okp(okp)
  if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed25519 and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES)
    return JOSE::JWK::KTY_OKP_Ed25519.new(okp[1]), JOSE::Map[]
  else
    raise ArgumentError, "'okp' must be an Array in the form of [:Ed25519, String]"
  end
end

.from_openssh_key(key) ⇒ Object


114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 114

def self.from_openssh_key(key)
  type, _, sk, comment = key
  if type and sk and type == 'ssh-ed25519' and sk.bytesize == SK_BYTES
    if comment == '' or comment.nil?
      return from_okp([:Ed25519, sk])
    else
      kty, fields = from_okp([:Ed25519, sk])
      return kty, fields.merge('kid' => comment)
    end
  else
    raise ArgumentError, "unrecognized openssh key type: #{type.inspect}"
  end
end

.generate_key(okp_params) ⇒ Object

JOSE::JWK::KTY callbacks


58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 58

def self.generate_key(okp_params)
  secret = nil
  if okp_params.is_a?(Array) and (okp_params.length == 2 or okp_params.length == 3) and okp_params[0] == :okp and okp_params[1] == :Ed25519
    secret = okp_params[2] if okp_params.length == 3
  elsif okp_params.is_a?(String)
    secret = okp_params
  end
  if secret.nil? or (secret.is_a?(String) and secret.bytesize == SECRET_BYTES)
    return from_okp([:Ed25519, JOSE::JWA::Curve25519.ed25519_keypair(secret)[1]])
  else
    raise ArgumentError, "'secret' must be nil or a String of #{SECRET_BYTES} bytes"
  end
end

Instance Method Details

#generate_key(fields) ⇒ Object


72
73
74
75
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 72

def generate_key(fields)
  kty, other_fields = JOSE::JWK::KTY_OKP_Ed25519.generate_key([:okp, :Ed25519])
  return kty, fields.delete('kid').merge(other_fields)
end

#key_encryptor(fields, key) ⇒ Object


77
78
79
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 77

def key_encryptor(fields, key)
  return JOSE::JWK::KTY.key_encryptor(self, fields, key)
end

#sign(message, digest_type) ⇒ Object

Raises:

  • (ArgumentError)

81
82
83
84
85
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 81

def sign(message, digest_type)
  raise ArgumentError, "'digest_type' must be :Ed25519" if digest_type != :Ed25519
  raise NotImplementedError, "Ed25519 public key cannot be used for signing" if okp.bytesize != SK_BYTES
  return JOSE::JWA::Curve25519.ed25519_sign(message, okp)
end

#signer(fields = nil) ⇒ Object


87
88
89
90
91
92
93
94
95
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 87

def signer(fields = nil)
  if okp.bytesize == SK_BYTES and fields and fields['use'] == 'sig' and not fields['alg'].nil?
    return JOSE::Map['alg' => fields['alg']]
  elsif okp.bytesize == SK_BYTES
    return JOSE::Map['alg' => 'Ed25519']
  else
    raise ArgumentError, "signing not supported for public keys"
  end
end

#to_keyObject


27
28
29
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 27

def to_key
  return okp
end

#to_map(fields) ⇒ Object


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 31

def to_map(fields)
  if okp.bytesize == SK_BYTES
    secret, pk = okp[0, SECRET_BYTES], okp[SECRET_BYTES, SK_BYTES]
    return fields.
      put('crv', 'Ed25519').
      put('d',   JOSE.urlsafe_encode64(secret)).
      put('kty', 'OKP').
      put('x',   JOSE.urlsafe_encode64(pk))
  else
    pk = okp
    return fields.
      put('crv', 'Ed25519').
      put('kty', 'OKP').
      put('x',   JOSE.urlsafe_encode64(pk))
  end
end

#to_okpObject


128
129
130
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 128

def to_okp
  return [:Ed25519, okp]
end

#to_openssh_key(fields) ⇒ Object


132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 132

def to_openssh_key(fields)
  comment = fields['kid'] || ''
  pk = JOSE::JWA::Curve25519.ed25519_secret_to_public(okp)
  sk = okp
  return JOSE::JWK::OpenSSHKey.to_binary([
    [
      [
        ['ssh-ed25519', pk],
        ['ssh-ed25519', pk, sk, comment]
      ]
    ]
  ])
end

#to_public_map(fields) ⇒ Object


48
49
50
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 48

def to_public_map(fields)
  return to_map(fields).except('d')
end

#to_thumbprint_map(fields) ⇒ Object


52
53
54
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 52

def to_thumbprint_map(fields)
  return to_public_map(fields).slice('crv', 'kty', 'x')
end

#verify(message, digest_type, signature) ⇒ Object

Raises:

  • (ArgumentError)

97
98
99
100
101
102
# File 'lib/jose/jwk/kty_okp_ed25519.rb', line 97

def verify(message, digest_type, signature)
  raise ArgumentError, "'digest_type' must be :Ed25519" if digest_type != :Ed25519
  pk = okp
  pk = JOSE::JWA::Curve25519.ed25519_secret_to_public(okp) if okp.bytesize == SK_BYTES
  return JOSE::JWA::Curve25519.ed25519_verify(signature, message, pk)
end