Class: Seekrit::Crypto::TokenKey

Inherits:
Object
  • Object
show all
Defined in:
lib/seekrit/crypto.rb

Overview

The P-256 private key recovered from a skt_... service token.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(token_id, ec_key) ⇒ TokenKey

Returns a new instance of TokenKey.



82
83
84
85
# File 'lib/seekrit/crypto.rb', line 82

def initialize(token_id, ec_key)
  @token_id = token_id
  @ec_key = ec_key
end

Instance Attribute Details

#token_idObject (readonly)

Returns the value of attribute token_id.



80
81
82
# File 'lib/seekrit/crypto.rb', line 80

def token_id
  @token_id
end

Class Method Details

.parse(token) ⇒ Object

Raises:



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/seekrit/crypto.rb', line 87

def self.parse(token)
  match = Crypto::TOKEN_RE.match(token)
  raise CryptoError, "not a valid seekrit service token" unless match

  der = Crypto.b64url_decode(match[2])
  ec_key = begin
    key = OpenSSL::PKey.read(der)
    raise CryptoError, "service token key is not an EC private key" unless key.is_a?(OpenSSL::PKey::EC)

    key
  rescue OpenSSL::PKey::PKeyError, ArgumentError
    begin
      OpenSSL::PKey::EC.new(der)
    rescue StandardError
      raise CryptoError, "service token private key is corrupted"
    end
  end
  new(match[1], ec_key)
end

Instance Method Details

#unwrap_dek(wrapped) ⇒ Object

Recover a 32-byte environment DEK from a wd1. blob.

Raises:



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/seekrit/crypto.rb', line 108

def unwrap_dek(wrapped)
  eph_b64, salt_b64, iv_b64, ct_b64 = Crypto.split_blob(wrapped, "wd1", 4)
  eph = Crypto.b64url_decode(eph_b64)
  salt = Crypto.b64url_decode(salt_b64)
  iv = Crypto.b64url_decode(iv_b64)
  ct = Crypto.b64url_decode(ct_b64)

  group = OpenSSL::PKey::EC::Group.new(Crypto::CURVE)
  peer_point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(eph, 2))
  shared = @ec_key.dh_compute_key(peer_point)
  wrapping_key = Crypto.hkdf_sha256(shared, salt, Crypto::HKDF_INFO, 32)

  dek = begin
    Crypto.aes_gcm_decrypt(wrapping_key, iv, ct, "")
  rescue OpenSSL::Cipher::CipherError
    raise CryptoError, "DEK unwrap failed: wrong private key or tampered grant"
  end
  raise CryptoError, "unwrapped DEK has wrong length" unless dek.bytesize == 32

  dek
end