jose 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.editorconfig +20 -0
- data/.gitignore +9 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +373 -0
- data/README.md +41 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/jose.gemspec +36 -0
- data/lib/jose.rb +61 -0
- data/lib/jose/jwa.rb +21 -0
- data/lib/jose/jwa/aes_kw.rb +105 -0
- data/lib/jose/jwa/concat_kdf.rb +50 -0
- data/lib/jose/jwa/pkcs1.rb +269 -0
- data/lib/jose/jwa/pkcs7.rb +23 -0
- data/lib/jose/jwe.rb +290 -0
- data/lib/jose/jwe/alg.rb +12 -0
- data/lib/jose/jwe/alg_aes_gcm_kw.rb +98 -0
- data/lib/jose/jwe/alg_aes_kw.rb +57 -0
- data/lib/jose/jwe/alg_dir.rb +40 -0
- data/lib/jose/jwe/alg_ecdh_es.rb +123 -0
- data/lib/jose/jwe/alg_pbes2.rb +90 -0
- data/lib/jose/jwe/alg_rsa.rb +63 -0
- data/lib/jose/jwe/enc.rb +8 -0
- data/lib/jose/jwe/enc_aes_cbc_hmac.rb +80 -0
- data/lib/jose/jwe/enc_aes_gcm.rb +68 -0
- data/lib/jose/jwe/zip.rb +7 -0
- data/lib/jose/jwe/zip_def.rb +28 -0
- data/lib/jose/jwk.rb +347 -0
- data/lib/jose/jwk/kty.rb +34 -0
- data/lib/jose/jwk/kty_ec.rb +179 -0
- data/lib/jose/jwk/kty_oct.rb +104 -0
- data/lib/jose/jwk/kty_rsa.rb +185 -0
- data/lib/jose/jwk/pem.rb +19 -0
- data/lib/jose/jwk/set.rb +2 -0
- data/lib/jose/jws.rb +242 -0
- data/lib/jose/jws/alg.rb +10 -0
- data/lib/jose/jws/alg_ecdsa.rb +41 -0
- data/lib/jose/jws/alg_hmac.rb +41 -0
- data/lib/jose/jws/alg_rsa_pkcs1_v1_5.rb +41 -0
- data/lib/jose/jws/alg_rsa_pss.rb +41 -0
- data/lib/jose/jwt.rb +145 -0
- data/lib/jose/version.rb +3 -0
- metadata +162 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
class JOSE::JWE::ALG_dir
|
2
|
+
|
3
|
+
# JOSE::JWE callbacks
|
4
|
+
|
5
|
+
def self.from_map(fields)
|
6
|
+
case fields['alg']
|
7
|
+
when 'dir'
|
8
|
+
return new(), fields.delete('alg')
|
9
|
+
else
|
10
|
+
raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_map(fields)
|
15
|
+
return fields.put('alg', 'dir')
|
16
|
+
end
|
17
|
+
|
18
|
+
# JOSE::JWE::ALG callbacks
|
19
|
+
|
20
|
+
def key_decrypt(key, enc, encrypted_key)
|
21
|
+
if key.is_a?(String)
|
22
|
+
return key
|
23
|
+
else
|
24
|
+
return key.kty.derive_key
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def key_encrypt(key, enc, decrypted_key)
|
29
|
+
return '', self
|
30
|
+
end
|
31
|
+
|
32
|
+
def next_cek(key, enc)
|
33
|
+
if key.is_a?(String)
|
34
|
+
return key
|
35
|
+
else
|
36
|
+
return key.kty.derive_key
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
class JOSE::JWE::ALG_ECDH_ES < Struct.new(:bits, :epk, :apu, :apv)
|
2
|
+
|
3
|
+
# JOSE::JWE callbacks
|
4
|
+
|
5
|
+
def self.from_map(fields)
|
6
|
+
bits = nil
|
7
|
+
case fields['alg']
|
8
|
+
when 'ECDH-ES'
|
9
|
+
bits = nil
|
10
|
+
when 'ECDH-ES+A128KW'
|
11
|
+
bits = 128
|
12
|
+
when 'ECDH-ES+A192KW'
|
13
|
+
bits = 192
|
14
|
+
when 'ECDH-ES+A256KW'
|
15
|
+
bits = 256
|
16
|
+
else
|
17
|
+
raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
|
18
|
+
end
|
19
|
+
epk = nil
|
20
|
+
if fields.has_key?('epk')
|
21
|
+
epk = JOSE::JWK.from_map(fields['epk'])
|
22
|
+
end
|
23
|
+
apu = nil
|
24
|
+
if fields.has_key?('apu')
|
25
|
+
apu = JOSE.urlsafe_decode64(fields['apu'])
|
26
|
+
end
|
27
|
+
apv = nil
|
28
|
+
if fields.has_key?('apv')
|
29
|
+
apv = JOSE.urlsafe_decode64(fields['apv'])
|
30
|
+
end
|
31
|
+
return new(bits, epk, apu, apv), fields.except('alg', 'apu', 'apv', 'epk')
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_map(fields)
|
35
|
+
fields = fields.put('alg', algorithm)
|
36
|
+
if epk
|
37
|
+
fields = fields.put('epk', epk.to_map)
|
38
|
+
end
|
39
|
+
if apu
|
40
|
+
fields = fields.put('apu', JOSE.urlsafe_encode64(apu))
|
41
|
+
end
|
42
|
+
if apv
|
43
|
+
fields = fields.put('apv', JOSE.urlsafe_encode64(apv))
|
44
|
+
end
|
45
|
+
return fields
|
46
|
+
end
|
47
|
+
|
48
|
+
# JOSE::JWE::ALG callbacks
|
49
|
+
|
50
|
+
def key_decrypt(box_keys, enc, encrypted_key)
|
51
|
+
other_public_key, my_private_key = box_keys
|
52
|
+
if my_private_key and epk and epk.to_key != other_public_key.to_key
|
53
|
+
raise ArgumentError, "other and ephemeral public key mismatch"
|
54
|
+
elsif epk and my_private_key.nil?
|
55
|
+
my_private_key = other_public_key
|
56
|
+
other_public_key = epk
|
57
|
+
else
|
58
|
+
raise ArgumentError, "missing 'epk' or my_private_key"
|
59
|
+
end
|
60
|
+
z = other_public_key.derive_key(my_private_key)
|
61
|
+
if bits.nil?
|
62
|
+
algorithm_id = enc.algorithm
|
63
|
+
key_data_len = enc.bits
|
64
|
+
supp_pub_info = [key_data_len].pack('N')
|
65
|
+
derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
|
66
|
+
return derived_key
|
67
|
+
else
|
68
|
+
algorithm_id = algorithm
|
69
|
+
key_data_len = bits
|
70
|
+
supp_pub_info = [key_data_len].pack('N')
|
71
|
+
derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
|
72
|
+
decrypted_key = JOSE::JWA::AES_KW.unwrap(encrypted_key, derived_key)
|
73
|
+
return decrypted_key
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def key_encrypt(box_keys, enc, decrypted_key)
|
78
|
+
if bits.nil?
|
79
|
+
return '', self
|
80
|
+
else
|
81
|
+
other_public_key, my_private_key = box_keys
|
82
|
+
z = other_public_key.derive_key(my_private_key)
|
83
|
+
algorithm_id = algorithm
|
84
|
+
key_data_len = bits
|
85
|
+
supp_pub_info = [key_data_len].pack('N')
|
86
|
+
derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
|
87
|
+
encrypted_key = JOSE::JWA::AES_KW.wrap(decrypted_key, derived_key)
|
88
|
+
return encrypted_key, self
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def next_cek(box_keys, enc)
|
93
|
+
if bits.nil?
|
94
|
+
other_public_key, my_private_key = box_keys
|
95
|
+
z = other_public_key.derive_key(my_private_key)
|
96
|
+
algorithm_id = enc.algorithm
|
97
|
+
key_data_len = enc.bits
|
98
|
+
supp_pub_info = [key_data_len].pack('N')
|
99
|
+
derived_key = JOSE::JWA::ConcatKDF.kdf(OpenSSL::Digest::SHA256, z, [algorithm_id, apu, apv, supp_pub_info], key_data_len)
|
100
|
+
return derived_key
|
101
|
+
else
|
102
|
+
return enc.next_cek
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# API functions
|
107
|
+
|
108
|
+
def algorithm
|
109
|
+
case bits
|
110
|
+
when nil
|
111
|
+
return 'ECDH-ES'
|
112
|
+
when 128
|
113
|
+
return 'ECDH-ES+A128KW'
|
114
|
+
when 192
|
115
|
+
return 'ECDH-ES+A192KW'
|
116
|
+
when 256
|
117
|
+
return 'ECDH-ES+A256KW'
|
118
|
+
else
|
119
|
+
raise ArgumentError, "unhandled JOSE::JWE::ALG_ECDH_ES bits: #{bits.inspect}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
class JOSE::JWE::ALG_PBES2 < Struct.new(:hmac, :bits, :salt, :iter)
|
2
|
+
|
3
|
+
# JOSE::JWE callbacks
|
4
|
+
|
5
|
+
def self.from_map(fields)
|
6
|
+
bits = nil
|
7
|
+
hmac = nil
|
8
|
+
case fields['alg']
|
9
|
+
when 'PBES2-HS256+A128KW'
|
10
|
+
bits = 128
|
11
|
+
hmac = OpenSSL::Digest::SHA256
|
12
|
+
when 'PBES2-HS384+A192KW'
|
13
|
+
bits = 192
|
14
|
+
hmac = OpenSSL::Digest::SHA384
|
15
|
+
when 'PBES2-HS512+A256KW'
|
16
|
+
bits = 256
|
17
|
+
hmac = OpenSSL::Digest::SHA512
|
18
|
+
else
|
19
|
+
raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
|
20
|
+
end
|
21
|
+
iter = nil
|
22
|
+
if fields['p2c'].is_a?(Integer) and fields['p2c'] >= 0
|
23
|
+
iter = fields['p2c']
|
24
|
+
else
|
25
|
+
raise ArgumentError, "invalid 'p2c' for JWE: #{fields['p2c'].inspect}"
|
26
|
+
end
|
27
|
+
salt = nil
|
28
|
+
if fields.has_key?('p2s') and fields['p2s'].is_a?(String)
|
29
|
+
salt = wrap_salt(fields['alg'], JOSE.urlsafe_decode64(fields['p2s']))
|
30
|
+
else
|
31
|
+
raise ArgumentError, "invalid 'p2s' for JWE: #{fields['p2s'].inspect}"
|
32
|
+
end
|
33
|
+
return new(hmac, bits, salt, iter), fields.except('alg', 'p2c', 'p2s')
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_map(fields)
|
37
|
+
alg = if hmac == OpenSSL::Digest::SHA256
|
38
|
+
'PBES2-HS256+A128KW'
|
39
|
+
elsif hmac == OpenSSL::Digest::SHA384
|
40
|
+
'PBES2-HS384+A192KW'
|
41
|
+
elsif hmac == OpenSSL::Digest::SHA512
|
42
|
+
'PBES2-HS512+A256KW'
|
43
|
+
else
|
44
|
+
raise ArgumentError, "unhandled JOSE::JWE::ALG_PBES2 hmac: #{hmac.inspect}"
|
45
|
+
end
|
46
|
+
p2c = iter
|
47
|
+
p2s = JOSE.urlsafe_encode64(unwrap_salt(alg, salt))
|
48
|
+
return fields.put('alg', alg).put('p2c', p2c).put('p2s', p2s)
|
49
|
+
end
|
50
|
+
|
51
|
+
# JOSE::JWE::ALG callbacks
|
52
|
+
|
53
|
+
def key_decrypt(key, enc, encrypted_key)
|
54
|
+
if key.is_a?(JOSE::JWK)
|
55
|
+
key = key.kty.derive_key
|
56
|
+
end
|
57
|
+
derived_key = OpenSSL::PKCS5.pbkdf2_hmac(key, salt, iter, bits.div(8) + (bits % 8), hmac.new)
|
58
|
+
decrypted_key = JOSE::JWA::AES_KW.unwrap(encrypted_key, derived_key)
|
59
|
+
return decrypted_key
|
60
|
+
end
|
61
|
+
|
62
|
+
def key_encrypt(key, enc, decrypted_key)
|
63
|
+
if key.is_a?(JOSE::JWK)
|
64
|
+
key = key.kty.derive_key
|
65
|
+
end
|
66
|
+
derived_key = OpenSSL::PKCS5.pbkdf2_hmac(key, salt, iter, bits.div(8) + (bits % 8), hmac.new)
|
67
|
+
encrypted_key = JOSE::JWA::AES_KW.wrap(decrypted_key, derived_key)
|
68
|
+
return encrypted_key, self
|
69
|
+
end
|
70
|
+
|
71
|
+
def next_cek(key, enc)
|
72
|
+
return enc.next_cek
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def unwrap_salt(algorithm, salt)
|
78
|
+
salt_s = StringIO.new(salt)
|
79
|
+
if salt_s.read(algorithm.length) != algorithm or salt_s.getbyte != 0
|
80
|
+
raise ArgumentError, "unrecognized salt value"
|
81
|
+
else
|
82
|
+
return salt_s.read
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.wrap_salt(algorithm, salt_input)
|
87
|
+
return [algorithm, 0x00, salt_input].pack('a*Ca*')
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class JOSE::JWE::ALG_RSA < Struct.new(:rsa_padding, :rsa_oaep_md)
|
2
|
+
|
3
|
+
# JOSE::JWE callbacks
|
4
|
+
|
5
|
+
def self.from_map(fields)
|
6
|
+
rsa_padding = nil
|
7
|
+
rsa_oaep_md = nil
|
8
|
+
case fields['alg']
|
9
|
+
when 'RSA1_5'
|
10
|
+
rsa_padding = :rsa_pkcs1_padding
|
11
|
+
when 'RSA-OAEP'
|
12
|
+
rsa_padding = :rsa_pkcs1_oaep_padding
|
13
|
+
rsa_oaep_md = OpenSSL::Digest::SHA1
|
14
|
+
when 'RSA-OAEP-256'
|
15
|
+
rsa_padding = :rsa_pkcs1_oaep_padding
|
16
|
+
rsa_oaep_md = OpenSSL::Digest::SHA256
|
17
|
+
else
|
18
|
+
raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
|
19
|
+
end
|
20
|
+
return new(rsa_padding, rsa_oaep_md), fields.except('alg')
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_map(fields)
|
24
|
+
alg = nil
|
25
|
+
if rsa_padding == :rsa_pkcs1_padding
|
26
|
+
alg = 'RSA1_5'
|
27
|
+
elsif rsa_padding == :rsa_pkcs1_oaep_padding
|
28
|
+
if rsa_oaep_md == OpenSSL::Digest::SHA1
|
29
|
+
alg = 'RSA-OAEP'
|
30
|
+
elsif rsa_oaep_md == OpenSSL::Digest::SHA256
|
31
|
+
alg = 'RSA-OAEP-256'
|
32
|
+
else
|
33
|
+
raise ArgumentError, "unhandled JOSE::JWE::ALG_RSA rsa_oaep_md: #{rsa_oaep_md.inspect}"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
raise ArgumentError, "unhandled JOSE::JWE::ALG_RSA rsa_padding: #{rsa_padding.inspect}"
|
37
|
+
end
|
38
|
+
return fields.put('alg', alg)
|
39
|
+
end
|
40
|
+
|
41
|
+
# JOSE::JWE::ALG callbacks
|
42
|
+
|
43
|
+
def key_decrypt(key, enc, encrypted_key)
|
44
|
+
if key.is_a?(JOSE::JWK)
|
45
|
+
return key.kty.decrypt_private(encrypted_key, rsa_padding: rsa_padding, rsa_oaep_md: rsa_oaep_md)
|
46
|
+
else
|
47
|
+
raise ArgumentError, "'key' must be a JOSE::JWK"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def key_encrypt(key, enc, decrypted_key)
|
52
|
+
if key.is_a?(JOSE::JWK)
|
53
|
+
return key.kty.encrypt_public(decrypted_key, rsa_padding: rsa_padding, rsa_oaep_md: rsa_oaep_md), self
|
54
|
+
else
|
55
|
+
raise ArgumentError, "'key' must be a JOSE::JWK"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def next_cek(key, enc)
|
60
|
+
return enc.next_cek
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/lib/jose/jwe/enc.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
class JOSE::JWE::ENC_AES_CBC_HMAC < Struct.new(:cipher_name, :bits, :cek_len, :iv_len, :enc_len, :mac_len, :tag_len, :hmac)
|
2
|
+
|
3
|
+
# JOSE::JWE callbacks
|
4
|
+
|
5
|
+
def self.from_map(fields)
|
6
|
+
case fields['enc']
|
7
|
+
when 'A128CBC-HS256'
|
8
|
+
return new('aes-128-cbc', 256, 32, 16, 16, 16, 16, OpenSSL::Digest::SHA256), fields.delete('enc')
|
9
|
+
when 'A192CBC-HS384'
|
10
|
+
return new('aes-192-cbc', 384, 48, 16, 24, 24, 24, OpenSSL::Digest::SHA384), fields.delete('enc')
|
11
|
+
when 'A256CBC-HS512'
|
12
|
+
return new('aes-256-cbc', 512, 64, 16, 32, 32, 32, OpenSSL::Digest::SHA512), fields.delete('enc')
|
13
|
+
else
|
14
|
+
raise ArgumentError, "invalid 'enc' for JWE: #{fields['enc'].inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_map(fields)
|
19
|
+
return fields.put('enc', algorithm)
|
20
|
+
end
|
21
|
+
|
22
|
+
# JOSE::JWE::ENC callbacks
|
23
|
+
|
24
|
+
def algorithm
|
25
|
+
case cipher_name
|
26
|
+
when 'aes-128-cbc'
|
27
|
+
return 'A128CBC-HS256'
|
28
|
+
when 'aes-192-cbc'
|
29
|
+
return 'A192CBC-HS384'
|
30
|
+
when 'aes-256-cbc'
|
31
|
+
return 'A256CBC-HS512'
|
32
|
+
else
|
33
|
+
raise ArgumentError, "unhandled JOSE::JWE::ENC_AES_CBC_HMAC cipher name: #{cipher_name.inspect}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def block_decrypt(aad_cipher_text_cipher_tag, cek, iv)
|
38
|
+
aad, cipher_text, cipher_tag = aad_cipher_text_cipher_tag
|
39
|
+
cek_s = StringIO.new(cek)
|
40
|
+
mac_key = cek_s.read(mac_len)
|
41
|
+
enc_key = cek_s.read(enc_len)
|
42
|
+
aad_len = [(aad.bytesize * 8)].pack('Q>')
|
43
|
+
mac_data = [aad, iv, cipher_text, aad_len].pack('a*a*a*a*')
|
44
|
+
if cipher_tag != OpenSSL::HMAC.digest(hmac.new, mac_key, mac_data)[0..tag_len]
|
45
|
+
raise ArgumentError, "decryption error"
|
46
|
+
else
|
47
|
+
cipher = OpenSSL::Cipher.new(cipher_name)
|
48
|
+
cipher.decrypt
|
49
|
+
cipher.key = cek
|
50
|
+
cipher.iv = iv
|
51
|
+
plain_text = JOSE::JWA::PKCS7.unpad(cipher.update(cipher_text) + cipher.final)
|
52
|
+
return plain_text
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def block_encrypt(aad_plain_text, cek, iv)
|
57
|
+
aad, plain_text = aad_plain_text
|
58
|
+
cek_s = StringIO.new(cek)
|
59
|
+
mac_key = cek_s.read(mac_len)
|
60
|
+
enc_key = cek_s.read(enc_len)
|
61
|
+
cipher = OpenSSL::Cipher.new(cipher_name)
|
62
|
+
cipher.encrypt
|
63
|
+
cipher.key = cek
|
64
|
+
cipher.iv = iv
|
65
|
+
cipher_text = cipher.update(JOSE::JWA::PKCS7.pad(plain_text)) + cipher.final
|
66
|
+
aad_len = [(aad.bytesize * 8)].pack('Q>')
|
67
|
+
mac_data = [aad, iv, cipher_text, aad_len].pack('a*a*a*a*')
|
68
|
+
cipher_tag = OpenSSL::HMAC.digest(hmac.new, mac_key, mac_data)[0..tag_len]
|
69
|
+
return cipher_text, cipher_tag
|
70
|
+
end
|
71
|
+
|
72
|
+
def next_cek
|
73
|
+
return SecureRandom.random_bytes(cek_len)
|
74
|
+
end
|
75
|
+
|
76
|
+
def next_iv
|
77
|
+
return SecureRandom.random_bytes(iv_len)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class JOSE::JWE::ENC_AES_GCM < Struct.new(:cipher_name, :bits, :cek_len, :iv_len)
|
2
|
+
|
3
|
+
# JOSE::JWE callbacks
|
4
|
+
|
5
|
+
def self.from_map(fields)
|
6
|
+
case fields['enc']
|
7
|
+
when 'A128GCM'
|
8
|
+
return new('aes-128-gcm', 128, 16, 12), fields.delete('enc')
|
9
|
+
when 'A192GCM'
|
10
|
+
return new('aes-192-gcm', 192, 24, 12), fields.delete('enc')
|
11
|
+
when 'A256GCM'
|
12
|
+
return new('aes-256-gcm', 256, 32, 12), fields.delete('enc')
|
13
|
+
else
|
14
|
+
raise ArgumentError, "invalid 'enc' for JWE: #{fields['enc'].inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_map(fields)
|
19
|
+
return fields.put('enc', algorithm)
|
20
|
+
end
|
21
|
+
|
22
|
+
# JOSE::JWE::ENC callbacks
|
23
|
+
|
24
|
+
def algorithm
|
25
|
+
case cipher_name
|
26
|
+
when 'aes-128-gcm'
|
27
|
+
return 'A128GCM'
|
28
|
+
when 'aes-192-gcm'
|
29
|
+
return 'A192GCM'
|
30
|
+
when 'aes-256-gcm'
|
31
|
+
return 'A256GCM'
|
32
|
+
else
|
33
|
+
raise ArgumentError, "unhandled JOSE::JWE::ENC_AES_GCM cipher name: #{cipher_name.inspect}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def block_decrypt(aad_cipher_text_cipher_tag, cek, iv)
|
38
|
+
aad, cipher_text, cipher_tag = aad_cipher_text_cipher_tag
|
39
|
+
cipher = OpenSSL::Cipher.new(cipher_name)
|
40
|
+
cipher.decrypt
|
41
|
+
cipher.key = cek
|
42
|
+
cipher.iv = iv
|
43
|
+
cipher.auth_data = aad
|
44
|
+
cipher.auth_tag = cipher_tag
|
45
|
+
plain_text = cipher.update(cipher_text) + cipher.final
|
46
|
+
return plain_text
|
47
|
+
end
|
48
|
+
|
49
|
+
def block_encrypt(aad_plain_text, cek, iv)
|
50
|
+
aad, plain_text = aad_plain_text
|
51
|
+
cipher = OpenSSL::Cipher.new(cipher_name)
|
52
|
+
cipher.encrypt
|
53
|
+
cipher.key = cek
|
54
|
+
cipher.iv = iv
|
55
|
+
cipher.auth_data = aad
|
56
|
+
cipher_text = cipher.update(plain_text) + cipher.final
|
57
|
+
return cipher_text, cipher.auth_tag
|
58
|
+
end
|
59
|
+
|
60
|
+
def next_cek
|
61
|
+
return SecureRandom.random_bytes(cek_len)
|
62
|
+
end
|
63
|
+
|
64
|
+
def next_iv
|
65
|
+
return SecureRandom.random_bytes(iv_len)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|