jose 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|