Class: JWT::PQ::JWK

Inherits:
Object
  • Object
show all
Defined in:
lib/jwt/pq/jwk.rb

Overview

JWK (JSON Web Key) support for ML-DSA keys.

Follows the draft-ietf-cose-dilithium conventions:

kty: "AKP" (Algorithm Key Pair)
alg: "ML-DSA-44", "ML-DSA-65", or "ML-DSA-87"
pub: base64url-encoded public key
priv: base64url-encoded private key (optional)

Constant Summary collapse

ALGORITHMS =
MlDsa::ALGORITHMS.keys.freeze
KTY =
"AKP"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key) ⇒ JWK

Returns a new instance of JWK.

Raises:



21
22
23
24
25
# File 'lib/jwt/pq/jwk.rb', line 21

def initialize(key)
  raise KeyError, "Expected a JWT::PQ::Key, got #{key.class}" unless key.is_a?(JWT::PQ::Key)

  @key = key
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.



19
20
21
# File 'lib/jwt/pq/jwk.rb', line 19

def key
  @key
end

Class Method Details

.import(jwk_hash) ⇒ Object

Import a Key from a JWK hash.

Raises:



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/jwt/pq/jwk.rb', line 42

def self.import(jwk_hash)
  jwk = normalize_keys(jwk_hash)

  validate_kty!(jwk)
  alg = validate_alg!(jwk)
  raise KeyError, "Missing 'pub' in JWK" unless jwk.key?("pub")

  pub_bytes = decode_field(jwk, "pub")

  if jwk.key?("priv")
    priv_bytes = decode_field(jwk, "priv")
    Key.new(algorithm: alg, public_key: pub_bytes, private_key: priv_bytes)
  else
    Key.new(algorithm: alg, public_key: pub_bytes)
  end
end

Instance Method Details

#export(include_private: false) ⇒ Object

Export the key as a JWK hash.



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/jwt/pq/jwk.rb', line 28

def export(include_private: false)
  jwk = {
    kty: KTY,
    alg: @key.algorithm,
    pub: base64url_encode(@key.public_key),
    kid: thumbprint
  }

  jwk[:priv] = base64url_encode(@key.private_key) if include_private && @key.private?

  jwk
end

#thumbprintObject

JWK Thumbprint (RFC 7638) for key identification. Uses the required members: alg, kty, pub.



61
62
63
64
65
# File 'lib/jwt/pq/jwk.rb', line 61

def thumbprint
  canonical = "{\"alg\":\"#{@key.algorithm}\",\"kty\":\"#{KTY}\",\"pub\":\"#{base64url_encode(@key.public_key)}\"}"
  digest = OpenSSL::Digest::SHA256.digest(canonical)
  base64url_encode(digest)
end