jose 0.3.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,6 +11,8 @@ module JOSE::JWA::ConcatKDF
11
11
  end
12
12
  if other_info.is_a?(Array)
13
13
  algorithm_id, party_u_info, party_v_info, supp_pub_info, supp_priv_info = other_info
14
+ party_u_info ||= ''
15
+ party_v_info ||= ''
14
16
  supp_pub_info ||= ''
15
17
  supp_priv_info ||= ''
16
18
  other_info = [
@@ -3,7 +3,7 @@ module JOSE::JWA::Curve25519_Ruby
3
3
  extend self
4
4
 
5
5
  def __ruby__?; true; end
6
- def __supported__?; JOSE.__crypto_fallback__; end
6
+ def __supported__?; JOSE.crypto_fallback; end
7
7
 
8
8
  def ed25519_keypair(secret = nil)
9
9
  return JOSE::JWA::Ed25519.keypair(secret)
@@ -3,7 +3,7 @@ module JOSE::JWA::Curve448_Ruby
3
3
  extend self
4
4
 
5
5
  def __ruby__?; true; end
6
- def __supported__?; JOSE.__crypto_fallback__; end
6
+ def __supported__?; JOSE.crypto_fallback; end
7
7
 
8
8
  def ed448_keypair(secret = nil)
9
9
  return JOSE::JWA::Ed448.keypair(secret)
@@ -72,10 +72,10 @@ module JOSE::JWA::Ed448
72
72
  curve448_scalar.setbyte(56, 0)
73
73
  a_s = OpenSSL::BN.new(curve448_scalar.reverse, 2).to_i
74
74
  # Calculate r_s and r (r only used in encoded form)
75
- r_s = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, seed, m].pack('A*CCA*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
75
+ r_s = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, seed, m].pack('a*CCa*a*a*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
76
76
  r = (C_B * r_s).encode()
77
77
  # Calculate h.
78
- h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, r, pk, m].pack('A*CCA*A*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
78
+ h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, r, pk, m].pack('a*CCa*a*a*a*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
79
79
  # Calculate s.
80
80
  s = OpenSSL::BN.new((r_s+h*a_s) % JOSE::JWA::Edwards448Point::L).to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse
81
81
  # The final signature is concatenation of r and s.
@@ -86,7 +86,7 @@ module JOSE::JWA::Ed448
86
86
  raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes and sk.bytesize != C_legacysecretkeybytes
87
87
  ctx ||= ''
88
88
  raise ArgumentError, "ctx must be 255 bytes or smaller" if ctx.bytesize > 255
89
- m = JOSE::JWA::SHA3.shake256(['SigEd448', 2, ctx.bytesize, ctx, m].pack('A*CCA*A*'), 64)
89
+ m = JOSE::JWA::SHA3.shake256(['SigEd448', 2, ctx.bytesize, ctx, m].pack('a*CCa*a*'), 64)
90
90
  secret, pk = nil, nil
91
91
  if sk.bytesize == C_secretkeybytes
92
92
  secret, pk = sk[0, 57], sk[57, 114]
@@ -100,10 +100,10 @@ module JOSE::JWA::Ed448
100
100
  curve448_scalar.setbyte(56, 0)
101
101
  a_s = OpenSSL::BN.new(curve448_scalar.reverse, 2).to_i
102
102
  # Calculate r_s and r (r only used in encoded form)
103
- r_s = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, seed, m].pack('A*CCA*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
103
+ r_s = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, seed, m].pack('a*CCa*a*a*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
104
104
  r = (C_B * r_s).encode()
105
105
  # Calculate h.
106
- h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, r, pk, m].pack('A*CCA*A*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
106
+ h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, r, pk, m].pack('a*CCa*a*a*a*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
107
107
  # Calculate s.
108
108
  s = OpenSSL::BN.new((r_s+h*a_s) % JOSE::JWA::Edwards448Point::L).to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse
109
109
  # The final signature is concatenation of r and s.
@@ -124,7 +124,7 @@ module JOSE::JWA::Ed448
124
124
  # Check parse results.
125
125
  return false if r_p.nil? or a_p.nil? or s_s > JOSE::JWA::Edwards448Point::L
126
126
  # Calculate h.
127
- h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, r, pk, m].pack('A*CCA*A*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
127
+ h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 0, ctx.bytesize, ctx, r, pk, m].pack('a*CCa*a*a*a*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
128
128
  # Calculate left and right sides of check eq.
129
129
  rhs = r_p + (a_p * h)
130
130
  lhs = C_B * s_s
@@ -139,7 +139,7 @@ module JOSE::JWA::Ed448
139
139
  def verify_ph(sig, m, pk, ctx = nil)
140
140
  ctx ||= ''
141
141
  raise ArgumentError, "ctx must be 255 bytes or smaller" if ctx.bytesize > 255
142
- m = JOSE::JWA::SHA3.shake256(['SigEd448', 2, ctx.bytesize, ctx, m].pack('A*CCA*A*'), 64)
142
+ m = JOSE::JWA::SHA3.shake256(['SigEd448', 2, ctx.bytesize, ctx, m].pack('a*CCa*a*'), 64)
143
143
  # Sanity-check sizes.
144
144
  return false if sig.bytesize != C_signaturebytes
145
145
  return false if pk.bytesize != C_publickeybytes
@@ -151,7 +151,7 @@ module JOSE::JWA::Ed448
151
151
  # Check parse results.
152
152
  return false if r_p.nil? or a_p.nil? or s_s > JOSE::JWA::Edwards448Point::L
153
153
  # Calculate h.
154
- h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, r, pk, m].pack('A*CCA*A*A*A*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
154
+ h = (OpenSSL::BN.new(JOSE::JWA::SHA3.shake256(['SigEd448', 1, ctx.bytesize, ctx, r, pk, m].pack('a*CCa*a*a*a*'), 114).reverse, 2) % JOSE::JWA::Edwards448Point::L).to_i
155
155
  # Calculate left and right sides of check eq.
156
156
  rhs = r_p + (a_p * h)
157
157
  lhs = C_B * s_s
@@ -1,21 +1,430 @@
1
1
  module JOSE
2
2
 
3
3
  class EncryptedBinary < ::String
4
+ # Expands a compacted encrypted binary or list of encrypted binaries into a map.
5
+ # @see JOSE::JWE.expand
6
+ # @return [JOSE::EncryptedMap]
4
7
  def expand
5
8
  return JOSE::JWE.expand(self)
6
9
  end
10
+
11
+ # Returns the decoded ciphertext portion of a encrypted binary or map without decrypting the ciphertext.
12
+ # @see JOSE::JWE.peek_ciphertext
13
+ # @return [String]
14
+ def peek_ciphertext
15
+ return JOSE::JWE.peek_ciphertext(self)
16
+ end
17
+
18
+ # Returns the decoded encrypted key portion of a encrypted binary or map without decrypting the ciphertext.
19
+ # @see JOSE::JWE.peek_encrypted_key
20
+ # @return [String]
21
+ def peek_encrypted_key
22
+ return JOSE::JWE.peek_encrypted_key(self)
23
+ end
24
+
25
+ # Returns the decoded initialization vector portion of a encrypted binary or map without decrypting the ciphertext.
26
+ # @see JOSE::JWE.peek_iv
27
+ # @return [String]
28
+ def peek_iv
29
+ return JOSE::JWE.peek_iv(self)
30
+ end
31
+
32
+ # Returns the decoded protected portion of a encrypted binary or map without decrypting the ciphertext.
33
+ # @see JOSE::JWE.peek_protected
34
+ # @return [JOSE::Map]
35
+ def peek_protected
36
+ return JOSE::JWE.peek_protected(self)
37
+ end
38
+
39
+ # Returns the decoded tag portion of a encrypted binary or map without decrypting the ciphertext.
40
+ # @see JOSE::JWE.peek_tag
41
+ # @return [String]
42
+ def peek_tag
43
+ return JOSE::JWE.peek_tag(self)
44
+ end
7
45
  end
8
46
 
47
+ # Immutable encrypted Map structure based on {JOSE::Map JOSE::Map}.
9
48
  class EncryptedMap < JOSE::Map
49
+ # Compacts an expanded encrypted map into a binary.
50
+ # @see JOSE::JWE.compact
51
+ # @return [JOSE::EncryptedBinary]
10
52
  def compact
11
53
  return JOSE::JWE.compact(self)
12
54
  end
13
55
  end
14
56
 
57
+ # JWE stands for JSON Web Encryption which is defined in [RFC 7516](https://tools.ietf.org/html/rfc7516).
58
+ #
59
+ # ## Key Derivation Algorithms
60
+ #
61
+ # The following key derivation algorithms for the `"alg"` field are currently supported by {JOSE::JWE JOSE::JWE} (some may need the {JOSE.crypto_fallback= JOSE.crypto_fallback=} option to be enabled):
62
+ #
63
+ # * `"A128GCMKW"`
64
+ # * `"A192GCMKW"`
65
+ # * `"A256GCMKW"`
66
+ # * `"A128KW"`
67
+ # * `"A192KW"`
68
+ # * `"A256KW"`
69
+ # * `"dir"`
70
+ # * `"ECDH-ES"`
71
+ # * `"ECDH-ES+A128KW"`
72
+ # * `"ECDH-ES+A192KW"`
73
+ # * `"ECDH-ES+A256KW"`
74
+ # * `"PBES2-HS256+A128KW"`
75
+ # * `"PBES2-HS384+A192KW"`
76
+ # * `"PBES2-HS512+A256KW"`
77
+ # * `"RSA1_5"`
78
+ # * `"RSA-OAEP"`
79
+ # * `"RSA-OAEP-256"`
80
+ #
81
+ # ## Encryption Algorithms
82
+ #
83
+ # The following encryption algorithms for the `"enc"` field are currently supported by {JOSE::JWE JOSE::JWE} (some may need the {JOSE.crypto_fallback= JOSE.crypto_fallback=} option to be enabled):
84
+ #
85
+ # * `"A128CBC-HS256"`
86
+ # * `"A192CBC-HS384"`
87
+ # * `"A256CBC-HS512"`
88
+ # * `"A128GCM"`
89
+ # * `"A192GCM"`
90
+ # * `"A256GCM"`
91
+ #
92
+ # ## Compression Algorithms
93
+ #
94
+ # The following compression algorithms for the `"zip"` field are currently supported by {JOSE::JWE JOSE::JWE}:
95
+ #
96
+ # * `"DEF"`
97
+ #
98
+ # ## Key Derivation Examples
99
+ #
100
+ # All of the examples below will use `"enc"` set to `"A128GCM"`, `"A192GCM"`, or `"A256GCM"` depending on the derived key size.
101
+ #
102
+ # The octet key used will typically be all zeroes of the required size in the form of `([0]*16).pack('C*')` (for a 128-bit key).
103
+ #
104
+ # All of the example keys generated below can be found here: [https://gist.github.com/potatosalad/dd140560b2bdbdab886d](https://gist.github.com/potatosalad/dd140560b2bdbdab886d)
105
+ #
106
+ # !!!ruby
107
+ # # octet keys we'll use below
108
+ # jwk_oct128 = JOSE::JWK.from_oct(([0]*16).pack('C*'))
109
+ # jwk_oct192 = JOSE::JWK.from_oct(([0]*24).pack('C*'))
110
+ # jwk_oct256 = JOSE::JWK.from_oct(([0]*32).pack('C*'))
111
+ # jwk_secret = JOSE::JWK.from_oct("secret")
112
+ #
113
+ # # EC keypairs we'll use below
114
+ # jwk_ec256_alice_sk = JOSE::JWK.generate_key([:ec, "P-256"])
115
+ # jwk_ec256_alice_pk = JOSE::JWK.to_public(jwk_ec256_alice_sk)
116
+ # jwk_ec256_bob_sk = JOSE::JWK.generate_key([:ec, "P-256"])
117
+ # jwk_ec256_bob_pk = JOSE::JWK.to_public(jwk_ec256_bob_sk)
118
+ #
119
+ # # X25519 keypairs we'll use below
120
+ # jwk_x25519_alice_sk = JOSE::JWK.generate_key([:okp, :X25519])
121
+ # jwk_x25519_alice_pk = JOSE::JWK.to_public(jwk_x25519_alice_sk)
122
+ # jwk_x25519_bob_sk = JOSE::JWK.generate_key([:okp, :X25519])
123
+ # jwk_x25519_bob_pk = JOSE::JWK.to_public(jwk_x25519_bob_sk)
124
+ #
125
+ # # X448 keypairs we'll use below
126
+ # jwk_x448_alice_sk = JOSE::JWK.generate_key([:okp, :X448])
127
+ # jwk_x448_alice_pk = JOSE::JWK.to_public(jwk_x448_alice_sk)
128
+ # jwk_x448_bob_sk = JOSE::JWK.generate_key([:okp, :X448])
129
+ # jwk_x448_bob_pk = JOSE::JWK.to_public(jwk_x448_bob_sk)
130
+ #
131
+ # # RSA keypairs we'll use below
132
+ # jwk_rsa_sk = JOSE::JWK.generate_key([:rsa, 4096])
133
+ # jwk_rsa_pk = JOSE::JWK.to_public(jwk_rsa_sk)
134
+ #
135
+ # ### <a name="AESGCMKW-group">A128GCMKW, A192GCMKW, and A256GCMKW</a>
136
+ #
137
+ # !!!ruby
138
+ # # A128GCMKW
139
+ # encrypted_a128gcmkw = JOSE::JWE.block_encrypt(jwk_oct128, "{}", { "alg" => "A128GCMKW", "enc" => "A128GCM" }).compact
140
+ # # => "eyJhbGciOiJBMTI4R0NNS1ciLCJlbmMiOiJBMTI4R0NNIiwiaXYiOiJzODNFNjhPNjhsWlM5ZVprIiwidGFnIjoieF9Ea2M5dm1LMk5RQV8tU2hvTkFRdyJ9.8B2qX8fVEa-s61RsZXqkCg.J7yJ8sKLbUlzyor6.FRs.BhBwImTv9B14NwVuxmfU6A"
141
+ # JOSE::JWE.block_decrypt(jwk_oct128, encrypted_a128gcmkw).first
142
+ # # => "{}"
143
+ #
144
+ # # A192GCMKW
145
+ # encrypted_a192gcmkw = JOSE::JWE.block_encrypt(jwk_oct192, "{}", { "alg" => "A192GCMKW", "enc" => "A192GCM" }).compact
146
+ # # => "eyJhbGciOiJBMTkyR0NNS1ciLCJlbmMiOiJBMTkyR0NNIiwiaXYiOiIxMkduZWQyTDB6NE5LZG83IiwidGFnIjoiM0thbG9iaER1Wmx5dE1YSjhjcXhZZyJ9.jJC4E1c6augIhvGDp3fquRfO-mnnud4F.S2NkKNGxBKTsCnKo.gZA.MvfhqSTeEN75H8HDyvfzRQ"
147
+ # JOSE::JWE.block_decrypt(jwk_oct192, encrypted_a192gcmkw).first
148
+ # # => "{}"
149
+ #
150
+ # # A256GCMKW
151
+ # encrypted_a256gcmkw = JOSE::JWE.block_encrypt(jwk_oct256, "{}", { "alg" => "A256GCMKW", "enc" => "A256GCM" }).compact
152
+ # # => "eyJhbGciOiJBMjU2R0NNS1ciLCJlbmMiOiJBMjU2R0NNIiwiaXYiOiJHU3lFMTBLQURxZTczNUMzIiwidGFnIjoiR3dVbDJCbXRNWlVseDlXNEMtY0tQZyJ9.sSsbFw9z8WTkzBLvPMywSedTXXygFxfP9g5U2qpzUX8.eiVFfe7iojfK0AXb._v8.YVfk9dNrtS7wxbGqCVge-g"
153
+ # JOSE::JWE.block_decrypt(jwk_oct256, encrypted_a256gcmkw).first
154
+ # # => "{}"
155
+ #
156
+ # ### <a name="AESKW-group">A128KW, A192KW, and A256KW</a>
157
+ #
158
+ # !!!ruby
159
+ # # A128KW
160
+ # encrypted_a128kw = JOSE::JWE.block_encrypt(jwk_oct128, "{}", { "alg" => "A128KW", "enc" => "A128GCM" }).compact
161
+ # # => "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0.t4_Fb4kCl6BcS1cXnR4P4Xgm-jwVNsFl.RerKfWjzqqtLIUrz.JmE.ZDpVlWo-aQYM5la9eshwWw"
162
+ # JOSE::JWE.block_decrypt(jwk_oct128, encrypted_a128kw).first
163
+ # # => "{}"
164
+ #
165
+ # # A192KW
166
+ # encrypted_a192kw = JOSE::JWE.block_encrypt(jwk_oct192, "{}", { "alg" => "A192KW", "enc" => "A192GCM" }).compact
167
+ # # => "eyJhbGciOiJBMTkyS1ciLCJlbmMiOiJBMTkyR0NNIn0.edpvNrztlNADbkwfq5YBJgqFBSH_Znv1Y1uXKNQ_13w.yCkEYTCPOKH6CoxZ.siw.zP_ZM9OEeX1FIdFjqNawtQ"
168
+ # JOSE::JWE.block_decrypt(jwk_oct192, encrypted_a192kw).first
169
+ # # => "{}"
170
+ #
171
+ # # A256KW
172
+ # encrypted_a256kw = JOSE::JWE.block_encrypt(jwk_oct256, "{}", { "alg" => "A256KW", "enc" => "A256GCM" }).compact
173
+ # # => "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2R0NNIn0.OvAhC1a2BoP_2SMIiZXwIHWPoIkD-Cosgp3nlpiTs8ySUBPfPzwG1g.4GeackYJbuBksAWA.HPE.vG0sGC2kuklH5xk8KXhyNA"
174
+ # JOSE::JWE.block_decrypt(jwk_oct256, encrypted_a256kw).first
175
+ # # => "{}"
176
+ #
177
+ # ### <a href="direct-group">dir</a>
178
+ #
179
+ # The `"dir"` key derivation algorithm is essentially just a pass-through to the underlying `"enc"` algorithm.
180
+ #
181
+ # The `"encrypted_key"` is not included in the protected header, so the key must be fully known by both parties.
182
+ #
183
+ # !!!ruby
184
+ # # dir
185
+ # encrypted_dir = JOSE::JWE.block_encrypt(jwk_oct128, "{}", { "alg" => "dir", "enc" => "A128GCM" }).compact
186
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..HdRR8O0kk_SvOjAS.rxo.JTMPGPKZZKVNlWV0RexsmQ"
187
+ # JOSE::JWE.block_decrypt(jwk_oct128, encrypted_dir).first
188
+ # # => "{}"
189
+ #
190
+ # ### <a name="ECDH-ES-group">ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, and ECDH-ES+A256KW</a>
191
+ #
192
+ # The `"ECDH-ES"` key derivation algorithm does not include the `"encrypted_key"` field in the protected header, similar to how `"dir"` functions.
193
+ #
194
+ # The size of the generated key is dependent on the `"enc"` setting (for example, `"A128GCM"` will generate a 128-bit key, `"A256GCM"` a 256-bit key, etc).
195
+ #
196
+ # !!!ruby
197
+ # # ECDH-ES with EC keypairs
198
+ # encrypted_ecdhes_ec256_alice2bob = JOSE::JWE.block_encrypt([jwk_ec256_bob_pk, jwk_ec256_alice_sk], "{}", { "alg" => "ECDH-ES", "enc" => "A128GCM" }).compact
199
+ # # => "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjQ4UVUzUTBDeVN4d0piRXdXckpyWVhscDg4X2RWcEhUeHE0YXZjNjZoNVEiLCJ5IjoiWnpxcklOdE1NeEh4US1RQjcyUk1jZGxtRHNPSXdsS2hNcVZtX2dZV0MxNCJ9fQ..UssNrY5qEeFdluZY.R6g.32nlr0wHF2TwfL1UnBtIow"
200
+ # JOSE::JWE.block_decrypt([jwk_ec256_alice_pk, jwk_ec256_bob_sk], encrypted_ecdhes_ec256_alice2bob).first
201
+ # # => "{}"
202
+ #
203
+ # # ECDH-ES with X25519 keypairs
204
+ # encrypted_ecdhes_x25519_alice2bob = JOSE::JWE.block_encrypt([jwk_x25519_bob_pk, jwk_x25519_alice_sk], "{}", { "alg" => "ECDH-ES", "enc" => "A128GCM" }).compact
205
+ # # => "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJjcnYiOiJYMjU1MTkiLCJrdHkiOiJPS1AiLCJ4IjoiZ0g3TjJwT0duenZfd0tBLUhqREZKTlVSZVhfdG05XzdiMkZSUjI3cXFYcyJ9fQ..T-0q42FPCUy3hlla.MHU.9TNP2jG5bN1vSvaesijdww"
206
+ # JOSE::JWE.block_decrypt([jwk_x25519_alice_pk, jwk_x25519_bob_sk], encrypted_ecdhes_x25519_alice2bob).first
207
+ # # => "{}"
208
+ #
209
+ # # ECDH-ES with X448 keypairs
210
+ # encrypted_ecdhes_x448_alice2bob = JOSE::JWE.block_encrypt([jwk_x448_bob_pk, jwk_x448_alice_sk], "{}", { "alg" => "ECDH-ES", "enc" => "A128GCM" }).compact
211
+ # # => "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJjcnYiOiJYNDQ4Iiwia3R5IjoiT0tQIiwieCI6ImFFaHZISGxFM2V1Y3lsY0RNNzBMd1paY2dDRk9acXExNWM3YXZNMjJkcWZIUEtja1FZNmo3LXFfM19kMGI1cGVWZEFoNVoyQWZIWSJ9fQ..T-UNE-wOApuRH71r.Uj8.l8bIfhC1UPAPVWBV3wkc6A"
212
+ # JOSE::JWE.block_decrypt([jwk_x448_alice_pk, jwk_x448_bob_sk], encrypted_ecdhes_x448_alice2bob).first
213
+ # # => "{}"
214
+ #
215
+ # When decrypting with any of the `"ECDH-ES"` related algorithms, the other party's public key is recommended, but not required for decryption (the embedded Ephemeral Public Key will be used instead):
216
+ #
217
+ # !!!ruby
218
+ # # decrypting the X448 example with and without the public key specified
219
+ # JOSE::JWE.block_decrypt([jwk_x448_alice_pk, jwk_x448_bob_sk], encrypted_ecdhes_x448_alice2bob).first
220
+ # # => "{}"
221
+ # JOSE::JWE.block_decrypt(jwk_x448_bob_sk, encrypted_ecdhes_x448_alice2bob).first
222
+ # # => "{}"
223
+ #
224
+ # The `"ECDH-ES+A128KW"`, `"ECDH-ES+A192KW"`, and `"ECDH-ES+A256KW"` key derivation algorithms do include the `"encrypted_key"` and the suffix after `"ECDH-ES+"` determines the key size (so `"ECDH-ES+A128KW"` computes a 128-bit key).
225
+ #
226
+ # !!!ruby
227
+ # # ECDH-ES+A128KW with EC keypairs
228
+ # encrypted_ecdhesa128kw_alice2bob = JOSE::JWE.block_encrypt([jwk_ec256_bob_pk, jwk_ec256_alice_sk], "{}", { "alg" => "ECDH-ES+A128KW", "enc" => "A128GCM" }).compact
229
+ # # => "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhHQ00iLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiI0OFFVM1EwQ3lTeHdKYkV3V3JKcllYbHA4OF9kVnBIVHhxNGF2YzY2aDVRIiwieSI6Ilp6cXJJTnRNTXhIeFEtUUI3MlJNY2RsbURzT0l3bEtoTXFWbV9nWVdDMTQifX0.ZwuqXf7svd3SH0M-XYLjWz5JsN6xX03C.l8tt83EJjy86IovL.i5A.nw05dPUA0a18xdtvmHbhHA"
230
+ # JOSE::JWE::block_decrypt([jwk_ec256_alice_pk, jwk_ec256_bob_sk], encrypted_ecdhesa128kw_alice2bob).first
231
+ # # => "{}"
232
+ #
233
+ # # ECDH-ES+A192KW with EC keypairs
234
+ # encrypted_ecdhesa192kw_alice2bob = JOSE::JWE.block_encrypt({jwk_ec256_bob_pk, jwk_ec256_alice_sk}, "{}", { "alg" => "ECDH-ES+A192KW", "enc" => "A192GCM" }).compact
235
+ # # => "eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExOTJHQ00iLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiI0OFFVM1EwQ3lTeHdKYkV3V3JKcllYbHA4OF9kVnBIVHhxNGF2YzY2aDVRIiwieSI6Ilp6cXJJTnRNTXhIeFEtUUI3MlJNY2RsbURzT0l3bEtoTXFWbV9nWVdDMTQifX0.S9LZ1i_Lua_if4I83WcaCQ9yT5qqPI_NhCFR7tMiZDQ.kG3taKEjGeKDRTzs.H1s.oVGBFP63z4gd3e-R2d1cmA"
236
+ # JOSE::JWE.block_decrypt({jwk_ec256_alice_pk, jwk_ec256_bob_sk}, encrypted_ecdhesa192kw_alice2bob).first
237
+ # # => "{}"
238
+ #
239
+ # # ECDH-ES+A256KW with EC keypairs
240
+ # encrypted_ecdhesa256kw_alice2bob = JOSE::JWE.block_encrypt({jwk_ec256_bob_pk, jwk_ec256_alice_sk}, "{}", { "alg" => "ECDH-ES+A256KW", "enc" => "A256GCM" }).compact
241
+ # # => "eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkEyNTZHQ00iLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiI0OFFVM1EwQ3lTeHdKYkV3V3JKcllYbHA4OF9kVnBIVHhxNGF2YzY2aDVRIiwieSI6Ilp6cXJJTnRNTXhIeFEtUUI3MlJNY2RsbURzT0l3bEtoTXFWbV9nWVdDMTQifX0.4KWy1-vRiJyNINF6mWYbUPPTVNG9ADfvvfpSDbddPTftz7GmUHUsuQ.IkRhtGH23R-9dFF3.9yk.RnALhnqWMHWCZFxqc-DU4A"
242
+ # JOSE::JWE.block_decrypt({jwk_ec256_alice_pk, jwk_ec256_bob_sk}, encrypted_ecdhesa256kw_alice2bob).first
243
+ # # => "{}"
244
+ #
245
+ # See {JOSE::JWK.box_encrypt JOSE::JWK.box_encrypt} for generating an Ephemeral Public Key based on the same curve as the supplied other party key in the same step.
246
+ #
247
+ # ### <a name="PBES2-group">PBES2-HS256+A128KW, PBES2-HS384+A192KW, and PBES2-HS512+A256KW</a>
248
+ #
249
+ # !!!ruby
250
+ # # PBES2-HS256+A128KW
251
+ # encrypted_pbes2hs256a128kw = JOSE::JWE.block_encrypt(jwk_secret, "{}", { "alg" => "PBES2-HS256+A128KW", "enc" => "A128GCM" }).compact
252
+ # # => "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjo0MDk2LCJwMnMiOiJRR0laNTlzbjRnQThySHBWYjFrSkd3In0.8WMQ0fysLiHU8AjpjkcqJGpYe53VRf2s.vVEb2ZtKmtPIw8M-.Cmg.GCjDtdKV6khqEuyZy2gUxw"
253
+ # JOSE::JWE.block_decrypt(jwk_secret, encrypted_pbes2hs256a128kw).first
254
+ # # => "{}"
255
+ #
256
+ # # PBES2-HS384+A192KW
257
+ # encrypted_pbes2hs384a192kw = JOSE::JWE.block_encrypt(jwk_secret, "{}", { "alg" => "PBES2-HS384+A192KW", "enc" => "A192GCM" }).compact
258
+ # # => "eyJhbGciOiJQQkVTMi1IUzM4NCtBMTkyS1ciLCJlbmMiOiJBMTkyR0NNIiwicDJjIjo2MTQ0LCJwMnMiOiJKSDRjZ0hlNTZiU0prZ1d6VktpWWJCb0FzWEJBY1A1NiJ9.Ck5GvgXxmyac3jzs0lRavoRh6tI9nEs3lYkx8sdDzGw.IdxaPATMkQ8FYiYQ.uHk.rDU6ltWsTsw9vuvA73bgJQ"
259
+ # JOSE::JWE.block_decrypt(jwk_secret, encrypted_pbes2hs384a192kw).first
260
+ # # => "{}"
261
+ #
262
+ # # PBES2-HS512+A256KW
263
+ # encrypted_pbes2hs512a256kw = JOSE::JWE.block_encrypt(jwk_secret, "{}", { "alg" => "PBES2-HS512+A256KW", "enc" => "A256GCM" }).compact
264
+ # # => "eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJlbmMiOiJBMjU2R0NNIiwicDJjIjo4MTkyLCJwMnMiOiJ6YWRiMVNmT1F4V1gyTHJrSVgwWDFGM2QzNlBIdUdxRVFzUDVhbWVnTk00In0.6SUVO9sSevqZrZ5yPX-JvJNJrzfIQeTTzrkWBHEqHra1_AITtwEe0A.0AaF_3ZlJOkRlqgb.W8I.jFWob73QTn52IFSIPEWHFA"
265
+ # JOSE::JWE.block_decrypt(jwk_secret, encrypted_pbes2hs512a256kw).first
266
+ # # => "{}"
267
+ #
268
+ # The `"p2s"` and `"p2i"` fields may also be specified to control the Salt and Iterations of the PBES2 Key Derivation Function, respectively.
269
+ #
270
+ # The default Salt is a randomly generated binary the same length of bytes as the key wrap (for example, `"PBES2-HS256+A128KW"` will generate a 16-byte Salt).
271
+ #
272
+ # The default Iterations is 32 times the number of bits specified by the key wrap (for example, `"PBES2-HS256+A128KW"` will have 4096 Iterations).
273
+ #
274
+ # !!!ruby
275
+ # # let's setup the JWE header
276
+ # iterations = 8192
277
+ # salt = ([0]*32).pack('C*') # all zero 256-bit salt, for example usage only
278
+ # jwe = {
279
+ # "alg" => "PBES2-HS256+A128KW",
280
+ # "enc" => "A128GCM",
281
+ # "p2i" => iterations,
282
+ # "p2s" => JOSE.urlsafe_encode64(salt)
283
+ # }
284
+ # # PBES2-HS256+A128KW
285
+ # encrypted_pbes2 = JOSE::JWE.block_encrypt(jwk_secret, "{}", jwe).compact
286
+ # # => "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjo0MDk2LCJwMmkiOjgxOTIsInAycyI6IkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEifQ.I7wcBmg7O_rOWpg1aak7wQWX84YtED6k.Rgh3f6Kzl5SZ1z7x.FNo.eyK1ySx4SGR-xC2EYNySQA"
287
+ # JOSE::JWE.block_decrypt(jwk_secret, encrypted_pbes2).first
288
+ # # => "{}"
289
+ #
290
+ # ### <a name="RSA-group">RSA1_5, RSA-OAEP, and RSA-OAEP-256</a>
291
+ #
292
+ # !!!ruby
293
+ # # RSA1_5
294
+ # encrypted_rsa1_5 = JOSE::JWE.block_encrypt(jwk_rsa_pk, "{}", { "alg" => "RSA1_5", "enc" => "A128GCM" }).compact
295
+ # # => "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4R0NNIn0.NlndPTqULN1vArshEzfEXY0nHCf4ubsTK9iHAeIxL85fReYrYG8EDB2_IirUneavvHSa-hsVLXNzBu0F9OY3TRFAIuJ8Jt1tqZZEhHZ97vzTEIjdlPNctGNI11-mhNCJ0doSvx9T4ByngaAFtJnRoR2cqbJkJFGja60fHtO0CfKLW5XzPf0NAhr8Tof-5IJfbNpMcC_LdCItJ6i8cuj4i5pG_CikOKDrNzbaBP72200_kl_-YaLDMA4tVb2YjWksY5Vau0Hz16QvI9QwDIcIDLYPAlTlDrU7s_FfmO_89S9Z69-lc_OBG7x2CYzIhB-0wzx753nZRl_WNJKi1Ya_AV552FEqVUhR-SuKcyrTA9OwkKC2JoL3lFqsCL9jkZkBrVREQlT0cxNI_AInyx5FHNLBbdtkz0JQbvzMJ854RP0V_eTlI5u8DZ42aOTRMBLHPi-4gP0J_CGWyKDQreXEEF6LSuLJb1cGk-NX1Vd85aARstQPuOoy7pWJjPvBEKEib70fjkUuMA0Atid-5BusQLKc1H-D6c5HIFH0DgYtXhN6AtQ_fmqw1F_X1JrGnYiYGzJCD2hh0Yt2UJZoCuHlPKk8aM5L3lNU3AISb1soSQl3hfX8Skb817ffC7jYezdhZc12cRNzOPAYqJYjN2eDlQhx-gpFjVzc-W1bFG8Yijo.grliT3M1iZ48aSY9.F4Y.pBRqIGZ4Q_fI1kmeAggvRg"
296
+ # JOSE::JWE.block_decrypt(jwk_rsa_sk, encrypted_rsa1_5).first
297
+ # # => "{}"
298
+ #
299
+ # # RSA-OAEP
300
+ # encrypted_rsaoaep = JOSE::JWE.block_encrypt(jwk_rsa_pk, "{}", { "alg" => "RSA-OAEP", "enc" => "A128GCM" }).compact
301
+ # # => "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.YZfGKTTU2KuvwIMpSYadbNmGzWIbLrwRYD8JvZAWkvcnFeky09S04VadRNPXmCBSl4EF1K7oBm0fiYXuvNbLFNKYT_Jo_y6Lb-XsP--BZKaEcq6wIdZ4-xTJ7YYX5dfco_cMknZLG8W2sQRwtWopisn9NyzSpfGNlYqeJqjpoJy0qnO8yZeEYeadwoVF9-XZfYwvMjEt7HORqBIPF1JIaOYTQ-LQBvya6XYhOR7dkSnuCZ_ITGW5ZbPvzOILSMW_3Ixe78ncfO2gxF6AiLh02oTLsOSrF9xDlJvuU0k1TdkNWtGroeP_WVbXEO7O_GI5LVW-cDzoVm5ZCQs2Df0018-qDxFyY9xhKS9aNDi_btiarstXMSz3EkOfPhWR_IzlVyUkYnzs3GS993gKLQ0Tk-ipvOT9Bcw9VTLLK3-f5YSkf51IA---hPFlxVlboH9bmTXlT4JzSbErQEYp3JuXjOP7FQn0OPko5Utqbbm41XBEJhUpBNhjrBGDspsMxML_eJdyzBgA5UyNfdCEQ2vM1pCegxG_hSKAhCKVNn71wW4O_y_eqUcoyhjB7HtVxiF29jzNUKF-y14171L4-mxsIpixaM1ofnayWMiherVP0Wz2MXkzWB0AUv8c3kNEJIh3oeyrczWwzpmeCh1Bq7-J4D6aaFjyGFcm-03_QZmfwho.ymxveKBeRuaZ8HzD.3H4.6oKLh2NouhPGpO1dmA-tTg"
302
+ # JOSE::JWE.block_decrypt(jwk_rsa_sk, encrypted_rsaoaep).first
303
+ # # => "{}"
304
+ #
305
+ # # RSA-OAEP-256
306
+ # encrypted_rsaoaep256 = JOSE::JWE.block_encrypt(jwk_rsa_pk, "{}", { "alg" => "RSA-OAEP-256", "enc" => "A128GCM" }).compact
307
+ # # => "eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIn0.OW9Hy9qpOIgVueODQXcWIUw_-Sm3UFGtxosyOAaI6JUQFt8q-iEtKkUp4NHrOlczO6tP5t8zRKdNXFfCm9QZk6F9PsSO-NzE2-DV1ANAMck-CDfGTK0mwG5U_KZwlObSgU0gxf87K49Wuno1rWlHWzJb__C_hCJXi_aQW17tLmbuTpJMkB0NTCKX3y6QaxvynP98jqwMJT6uGmE3AeuZYhPGzAOWbltbWyw-TqWqyLJirAUY_fvDNsKt1TDrTd9216TK5y7RQeUtdGfbuYK9lt2TIwfh9ycAHd7SANH_YJc2cKYa3e6CgqnQAjVpbhpogBz5sz5HaK95XYbXOdnYyHQ00gS44YquiQCvX331UgEWnthtmYwDZfnCxTkPydafGOBsjaagGvV2tQtxUKW3JmVChF97bNj5lQZ7rAkyooxx-k3IMT0005x6_74O5tXGN5fb7oyT3Mx_NZ5dKzlYAA_V8oOpNslaFhV5K5Q_-hRkUsEPWdaD5s2uS9Z7l7ot39CzzTKDj65f2eCTWFReFKOjhabCL4ZiFXbElB3dA3y5FdxXPAfe6N31G9ynalx1JIcrEaRb8sdqk6U6uC3s3DpkoRSnp3osBJOxxuk_Lgb-ZM9d8UuRVj4W78-qjfX_lcG1RlRmlYoDIU03ly0UfRWi-7HmpPECrGTsGZEfULg.J-txckmMXEi-bZVh.Rbw.D7UpSkticmDCGiNyLVggLg"
308
+ # JOSE::JWE.block_decrypt(jwk_rsa_sk, encrypted_rsaoaep256).first
309
+ # # => "{}"
310
+ #
311
+ # ## Encryption Examples
312
+ #
313
+ # All of the examples below will use `"alg"` set to `"dir"` passing the key directly to the Encryption Algorithm.
314
+ #
315
+ # The octet key used will typically be all zeroes of the required size in the form of `([0]*16).pack('C*')` (for a 128-bit key).
316
+ #
317
+ # All of the example keys generated below can be found here: [https://gist.github.com/potatosalad/dd140560b2bdbdab886d](https://gist.github.com/potatosalad/dd140560b2bdbdab886d)
318
+ #
319
+ # !!!ruby
320
+ # # octet keys we'll use below
321
+ # jwk_oct128 = JOSE::JWK.from_oct(([0]*16).pack('C*'))
322
+ # jwk_oct192 = JOSE::JWK.from_oct(([0]*24).pack('C*'))
323
+ # jwk_oct256 = JOSE::JWK.from_oct(([0]*32).pack('C*'))
324
+ # jwk_oct384 = JOSE::JWK.from_oct(([0]*48).pack('C*'))
325
+ # jwk_oct512 = JOSE::JWK.from_oct(([0]*64).pack('C*'))
326
+ #
327
+ # ### <a name="AESCBC-group">A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512</a>
328
+ #
329
+ # !!!ruby
330
+ # # A128CBC-HS256
331
+ # encrypted_a128cbchs256 = JOSE::JWE.block_encrypt(jwk_oct256, "{}", { "alg" => "dir", "enc" => "A128CBC-HS256" }).compact
332
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..bxps64-UIQoFvhkjr05e9A.HrtJ3AqrqJ4f5PHjGseHYw.kopJoTDxk34IVhheoToLSA"
333
+ # JOSE::JWE.block_decrypt(jwk_oct256, encrypted_a128cbchs256).first
334
+ # # => "{}"
335
+ #
336
+ # # A192CBC-HS384
337
+ # encrypted_a192cbchs384 = JOSE::JWE.block_encrypt(jwk_oct384, "{}", { "alg" => "dir", "enc" => "A192CBC-HS384" }).compact
338
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0In0..3zSCHwvHrcxsNyssIgEBRA.XB70tUoQZlnOgY5ygMxfKA.Avl7Z8jCpShh3_iTcPcU3Woh6E9ykNyB"
339
+ # JOSE::JWE.block_decrypt(jwk_oct384, encrypted_a192cbchs384).first
340
+ # # => "{}"
341
+ #
342
+ # # A256CBC-HS512
343
+ # encrypted_a256cbchs512 = JOSE::JWE.block_encrypt(jwk_oct512, "{}", { "alg" => "dir", "enc" => "A256CBC-HS512" }).compact
344
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0..mqMhkWAMF7HmW_Nu1ERUzQ.bzd-tmykuru0Lu_rsNZ2ow.mlOFO8JcC_UJ35TsZgiUeEwAjRDs6cwfN7Umyzm7mmY"
345
+ # JOSE::JWE.block_decrypt(jwk_oct512, encrypted_a256cbchs512).first
346
+ # # => "{}"
347
+ #
348
+ # ### <a name="AESGCM-group">A128GCM, A192GCM, and A256GCM</a>
349
+ #
350
+ # !!!ruby
351
+ # # A128GCM
352
+ # encrypted_a128gcm = JOSE::JWE.block_encrypt(jwk_oct128, "{}", { "alg" => "dir", "enc" => "A128GCM" }).compact
353
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..pPF4SbzGZwxS1J-M.Ic0.qkHuC-hOO44HPlykBJLSsA"
354
+ # JOSE::JWE.block_decrypt(jwk_oct128, encrypted_a128gcm).first
355
+ # # => "{}"
356
+ #
357
+ # # A192GCM
358
+ # encrypted_a192gcm = JOSE::JWE.block_encrypt(jwk_oct192, "{}", { "alg" => "dir", "enc" => "A192GCM" }).compact
359
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTkyR0NNIn0..muNgk2GFW9ATwqqZ.bvE.gYvC0G6DAodJdyrUqLw7Iw"
360
+ # JOSE::JWE.block_decrypt(jwk_oct192, encrypted_a192gcm).first
361
+ # # => "{}"
362
+ #
363
+ # # A256GCM
364
+ # encrypted_a256gcm = JOSE::JWE.block_encrypt(jwk_oct256, "{}", { "alg" => "dir", "enc" => "A256GCM" }).compact
365
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..rDTJhd5ja5pDAYtn.PrM.MQdLgiVXQsG_cLas93ZEHw"
366
+ # JOSE::JWE.block_decrypt(jwk_oct256, encrypted_a256gcm).first
367
+ # # => "{}"
368
+ #
369
+ # ## Compression Examples
370
+ #
371
+ # All of the examples below will use `"alg"` set to `"dir"` passing the key directly to the Encryption Algorithm (`"enc"` is set to `"A128GCM"`).
372
+ #
373
+ # The octet key used will typically be all zeroes of the required size in the form of `([0]*16).pack('C*')` (for a 128-bit key).
374
+ #
375
+ # All of the example keys generated below can be found here: [https://gist.github.com/potatosalad/dd140560b2bdbdab886d](https://gist.github.com/potatosalad/dd140560b2bdbdab886d)
376
+ #
377
+ # !!!ruby
378
+ # # octet keys we'll use below
379
+ # jwk_oct128 = JOSE::JWK.from_oct(([0]*16).pack('C*'))
380
+ #
381
+ # ### <a name="DEF-group">DEF</a>
382
+ #
383
+ # !!!ruby
384
+ # # DEF
385
+ # encrypted_def = JOSE::JWE.block_encrypt(jwk_oct128, "{}", { "alg" => "dir", "enc" => "A128GCM", "zip" => "DEF" }).compact
386
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0..Vvr0vlKWE9rAJ8CR.UpOz7w10Uc9pMg.Pctxzz0ijPSOY8zyRcbjww"
387
+ # JOSE::JWE.block_decrypt(jwk_oct128, encrypted_def).first
388
+ # # => "{}"
15
389
  class JWE < Struct.new(:alg, :enc, :zip, :fields)
16
390
 
17
391
  # Decode API
18
392
 
393
+ # Converts a binary or map into a {JOSE::JWE JOSE::JWE}.
394
+ #
395
+ # !!!ruby
396
+ # JOSE::JWE.from({ "alg" => "dir" })
397
+ # # => #<struct JOSE::JWE
398
+ # # alg=#<struct JOSE::JWE::ALG_dir direct=true>,
399
+ # # enc=nil,
400
+ # # zip=nil,
401
+ # # fields=JOSE::Map[]>
402
+ # JOSE::JWE.from("{\"alg\":\"dir\"}")
403
+ # # => #<struct JOSE::JWE
404
+ # # alg=#<struct JOSE::JWE::ALG_dir direct=true>,
405
+ # # enc=nil,
406
+ # # zip=nil,
407
+ # # fields=JOSE::Map[]>
408
+ #
409
+ # There are 3 keys which can have custom modules defined for them:
410
+ #
411
+ # * `"alg"` - must implement {JOSE::JWE::ALG JOSE::JWE::ALG}
412
+ # * `"enc"` - must implement {JOSE::JWE::ENC JOSE::JWE::ENC}
413
+ # * `"zip"` - must implement {JOSE::JWE::ZIP JOSE::JWE::ZIP}
414
+ #
415
+ # For example:
416
+ #
417
+ # !!!ruby
418
+ # JOSE::JWE.from({ "alg" => "dir", "zip" => "custom" }, { zip: MyCustomCompress })
419
+ # # => #<struct JOSE::JWE
420
+ # # alg=#<struct JOSE::JWE::ALG_dir direct=true>,
421
+ # # enc=nil,
422
+ # # zip=#<MyCustomAlgorithm:0x007f8c5419ff68>,
423
+ # # fields=JOSE::Map[]>
424
+ #
425
+ # @param [JOSE::Map, Hash, String, JOSE::JWE, Array<JOSE::Map, Hash, String, JOSE::JWE>] object
426
+ # @param [Hash] modules
427
+ # @return [JOSE::JWE, Array<JOSE::JWE>]
19
428
  def self.from(object, modules = {})
20
429
  case object
21
430
  when JOSE::Map, Hash
@@ -24,55 +433,98 @@ module JOSE
24
433
  return from_binary(object, modules)
25
434
  when JOSE::JWE
26
435
  return object
436
+ when Array
437
+ return object.map { |obj| from(obj, modules) }
27
438
  else
28
- raise ArgumentError, "'object' must be a Hash, String, or JOSE::JWE"
439
+ raise ArgumentError, "'object' must be a Hash, String, JOSE::JWE, or Array"
29
440
  end
30
441
  end
31
442
 
443
+ # Converts a binary into a {JOSE::JWE JOSE::JWE}.
444
+ # @param [String, Array<String>] object
445
+ # @param [Hash] modules
446
+ # @return [JOSE::JWE, Array<JOSE::JWE>]
32
447
  def self.from_binary(object, modules = {})
33
448
  case object
34
449
  when String
35
450
  return from_map(JOSE.decode(object), modules)
451
+ when Array
452
+ return object.map { |obj| from_binary(obj, modules) }
36
453
  else
37
- raise ArgumentError, "'object' must be a String"
454
+ raise ArgumentError, "'object' must be a String or Array"
38
455
  end
39
456
  end
40
457
 
458
+ # Reads file and calls {.from_binary} to convert into a {JOSE::JWE JOSE::JWE}.
459
+ # @param [String] file
460
+ # @param [Hash] modules
461
+ # @return [JOSE::JWE]
41
462
  def self.from_file(file, modules = {})
42
463
  return from_binary(File.binread(file), modules)
43
464
  end
44
465
 
466
+ # Converts a map into a {JOSE::JWE JOSE::JWE}.
467
+ # @param [JOSE::Map, Hash, Array<JOSE::Map, Hash>] object
468
+ # @param [Hash] modules
469
+ # @return [JOSE::JWE, Array<JOSE::JWE>]
45
470
  def self.from_map(object, modules = {})
46
471
  case object
47
472
  when JOSE::Map, Hash
48
473
  return from_fields(JOSE::JWE.new(nil, nil, nil, JOSE::Map.new(object)), modules)
474
+ when Array
475
+ return object.map { |obj| from_map(obj, modules) }
49
476
  else
50
- raise ArgumentError, "'object' must be a Hash"
477
+ raise ArgumentError, "'object' must be a Hash or Array"
51
478
  end
52
479
  end
53
480
 
54
481
  # Encode API
55
482
 
483
+ # Converts a {JOSE::JWE JOSE::JWE} into a binary.
484
+ # @param [JOSE::Map, Hash, String, JOSE::JWE, Array<JOSE::Map, Hash, String, JOSE::JWE>] jwe
485
+ # @return [String, Array<String>]
56
486
  def self.to_binary(jwe)
57
- return from(jwe).to_binary
487
+ if jwe.is_a?(Array)
488
+ return from(jwe).map { |obj| obj.to_binary }
489
+ else
490
+ return from(jwe).to_binary
491
+ end
58
492
  end
59
493
 
494
+ # Converts a {JOSE::JWE JOSE::JWE} into a binary.
495
+ # @return [String]
60
496
  def to_binary
61
497
  return JOSE.encode(to_map)
62
498
  end
63
499
 
500
+ # Calls {.to_binary} on a {JOSE::JWE JOSE::JWE} and then writes the binary to `file`.
501
+ # @param [JOSE::Map, Hash, String, JOSE::JWE] jwe
502
+ # @param [String] file
503
+ # @return [Fixnum] bytes written
64
504
  def self.to_file(jwe, file)
65
505
  return from(jwe).to_file(file)
66
506
  end
67
507
 
508
+ # Calls {#to_binary} on a {JOSE::JWE JOSE::JWE} and then writes the binary to `file`.
509
+ # @param [String] file
510
+ # @return [Fixnum] bytes written
68
511
  def to_file(file)
69
512
  return File.binwrite(file, to_binary)
70
513
  end
71
514
 
515
+ # Converts a {JOSE::JWE JOSE::JWE} into a map.
516
+ # @param [JOSE::Map, Hash, String, JOSE::JWE, Array<JOSE::Map, Hash, String, JOSE::JWE>] jwe
517
+ # @return [JOSE::Map, Array<JOSE::Map>]
72
518
  def self.to_map(jwe)
73
- return from(jwe).to_map
519
+ if jwe.is_a?(Array)
520
+ return from(jwe).map { |obj| obj.to_map }
521
+ else
522
+ return from(jwe).to_map
523
+ end
74
524
  end
75
525
 
526
+ # Converts a {JOSE::JWE JOSE::JWE} into a map.
527
+ # @return [JOSE::Map]
76
528
  def to_map
77
529
  if zip.nil?
78
530
  return alg.to_map(enc.to_map(fields))
@@ -83,6 +535,35 @@ module JOSE
83
535
 
84
536
  # API
85
537
 
538
+ # Decrypts the `encrypted` binary or map using the `key`.
539
+ #
540
+ # !!!ruby
541
+ # jwk = JOSE::JWK.from({"k" => "STlqtIOhWJjoVnYjUjxFLZ6oN1oB70QARGSTWQ_5XgM", "kty" => "oct"})
542
+ # # => #<struct JOSE::JWK
543
+ # # keys=nil,
544
+ # # kty=#<struct JOSE::JWK::KTY_oct oct="I9j\xB4\x83\xA1X\x98\xE8Vv#R<E-\x9E\xA87Z\x01\xEFD\x00Dd\x93Y\x0F\xF9^\x03">,
545
+ # # fields=JOSE::Map[]>
546
+ # JOSE::JWE.block_decrypt(jwk, "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..jBt5tTa1Q0N3uFPEkf30MQ.Ei49MvTLLje7bsZ5EZCZMA.gMWOAmhZSq9ksHCZm6VSoA")
547
+ # # => ["{}",
548
+ # # #<struct JOSE::JWE
549
+ # # alg=#<struct JOSE::JWE::ALG_dir direct=true>,
550
+ # # enc=
551
+ # # #<struct JOSE::JWE::ENC_AES_CBC_HMAC
552
+ # # cipher_name="aes-128-cbc",
553
+ # # bits=256,
554
+ # # cek_len=32,
555
+ # # iv_len=16,
556
+ # # enc_len=16,
557
+ # # mac_len=16,
558
+ # # tag_len=16,
559
+ # # hmac=OpenSSL::Digest::SHA256>,
560
+ # # zip=nil,
561
+ # # fields=JOSE::Map[]>]
562
+ #
563
+ # @see JOSE::JWE.block_encrypt
564
+ # @param [JOSE::JWK, [JOSE::JWK, JOSE::JWK]] key
565
+ # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap, Hash, String] encrypted
566
+ # @return [[String, JOSE::JWE]]
86
567
  def self.block_decrypt(key, encrypted)
87
568
  if encrypted.is_a?(String)
88
569
  encrypted = JOSE::JWE.expand(encrypted)
@@ -107,24 +588,66 @@ module JOSE
107
588
  end
108
589
  end
109
590
 
591
+ # Decrypts the `cipher_text` binary using the `key`, `aad`, `cipher_tag`, `encrypted_key`, and `iv`.
592
+ # @see JOSE::JWE.block_decrypt
593
+ # @param [JOSE::JWK, [JOSE::JWK, JOSE::JWK]] key
594
+ # @param [String] aad
595
+ # @param [String] cipher_text
596
+ # @param [String] cipher_tag
597
+ # @param [String] encrypted_key
598
+ # @param [String] iv
599
+ # @return [[String, JOSE::JWE]]
110
600
  def block_decrypt(key, aad, cipher_text, cipher_tag, encrypted_key, iv)
111
601
  cek = key_decrypt(key, encrypted_key)
112
602
  return uncompress(enc.block_decrypt([aad, cipher_text, cipher_tag], cek, iv))
113
603
  end
114
604
 
605
+ # Encrypts the `block` using the `key`, `cek`, `iv`, and algorithm specified by the `jwe`.
606
+ #
607
+ # !!!ruby
608
+ # jwk = JOSE::JWK.from({"k" => "STlqtIOhWJjoVnYjUjxFLZ6oN1oB70QARGSTWQ_5XgM", "kty" => "oct"})
609
+ # # => #<struct JOSE::JWK
610
+ # # keys=nil,
611
+ # # kty=#<struct JOSE::JWK::KTY_oct oct="I9j\xB4\x83\xA1X\x98\xE8Vv#R<E-\x9E\xA87Z\x01\xEFD\x00Dd\x93Y\x0F\xF9^\x03">,
612
+ # # fields=JOSE::Map[]>
613
+ # JOSE::JWE.block_encrypt(jwk, "{}", { "alg" => "dir", "enc" => "A128CBC-HS256" })
614
+ # # => JOSE::EncryptedMap[
615
+ # # "tag" => "tSGaAlI2xiMThBZ9XTW2AQ",
616
+ # # "ciphertext" => "c2T5O6WafTCKEX5R_9D-LQ",
617
+ # # "encrypted_key" => "",
618
+ # # "iv" => "U56zV4sW4bOovxeXcz7fUg",
619
+ # # "protected" => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0"]
620
+ #
621
+ # @see JOSE::JWE.block_decrypt
622
+ # @param [JOSE::JWK, [JOSE::JWK, JOSE::JWK]] key
623
+ # @param [String, [String, String]] block
624
+ # @param [JOSE::JWE] jwe
625
+ # @param [String] cek
626
+ # @param [String] iv
627
+ # @return [JOSE::EncryptedMap]
115
628
  def self.block_encrypt(key, block, jwe, cek = nil, iv = nil)
116
629
  return from(jwe).block_encrypt(key, block, cek, iv)
117
630
  end
118
631
 
632
+ # Encrypts the `block` binary using the `key`, `cek`, and `iv`.
633
+ # @see JOSE::JWE.block_encrypt
634
+ # @param [JOSE::JWK, [JOSE::JWK, JOSE::JWK]] key
635
+ # @param [String, [String, String]] block
636
+ # @param [String] cek
637
+ # @param [String] iv
638
+ # @return [JOSE::EncryptedMap]
119
639
  def block_encrypt(key, block, cek = nil, iv = nil)
120
- cek ||= next_cek(key)
121
- iv ||= next_iv
640
+ jwe = self
641
+ if cek.nil?
642
+ cek, jwe = next_cek(key)
643
+ end
644
+ iv ||= jwe.next_iv
122
645
  aad, plain_text = block
123
646
  if plain_text.nil?
124
647
  plain_text = aad
125
648
  aad = nil
126
649
  end
127
- encrypted_key, jwe = key_encrypt(key, cek)
650
+ encrypted_key, jwe = jwe.key_encrypt(key, cek)
128
651
  protected_binary = JOSE.urlsafe_encode64(jwe.to_binary)
129
652
  if aad.nil?
130
653
  cipher_text, cipher_tag = enc.block_encrypt([protected_binary, jwe.compress(plain_text)], cek, iv)
@@ -150,6 +673,21 @@ module JOSE
150
673
  end
151
674
  end
152
675
 
676
+ # Compacts an expanded encrypted map into a binary.
677
+ #
678
+ # !!!ruby
679
+ # JOSE::JWE.compact({
680
+ # "ciphertext" => "Ei49MvTLLje7bsZ5EZCZMA",
681
+ # "encrypted_key" => "",
682
+ # "iv" => "jBt5tTa1Q0N3uFPEkf30MQ",
683
+ # "protected" => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
684
+ # "tag" => "gMWOAmhZSq9ksHCZm6VSoA"
685
+ # })
686
+ # # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..jBt5tTa1Q0N3uFPEkf30MQ.Ei49MvTLLje7bsZ5EZCZMA.gMWOAmhZSq9ksHCZm6VSoA"
687
+ #
688
+ # @see JOSE::JWE.expand
689
+ # @param [JOSE::EncryptedMap, JOSE::Map, Hash] map
690
+ # @return [JOSE::EncryptedBinary]
153
691
  def self.compact(map)
154
692
  if map.is_a?(Hash) or map.is_a?(JOSE::Map)
155
693
  if map.has_key?('aad')
@@ -171,6 +709,23 @@ module JOSE
171
709
  end
172
710
  end
173
711
 
712
+ # Compresses the `plain_text` using the `"zip"` algorithm specified by the `jwe`.
713
+ #
714
+ # !!!ruby
715
+ # JOSE::JWE.compress("{}", { "alg" => "dir", "zip" => "DEF" })
716
+ # # => "x\x9C\xAB\xAE\x05\x00\x01u\x00\xF9"
717
+ #
718
+ # @param [String] plain_text
719
+ # @param [JOSE::JWE] jwe
720
+ # @return [String]
721
+ def self.compress(plain_text, jwe)
722
+ return from(jwe).compress(plain_text)
723
+ end
724
+
725
+ # Compresses the `plain_text` using the `"zip"` algorithm specified by the `jwe`.
726
+ # @see JOSE::JWE.compress
727
+ # @param [String] plain_text
728
+ # @return [String]
174
729
  def compress(plain_text)
175
730
  if zip.nil?
176
731
  return plain_text
@@ -179,6 +734,20 @@ module JOSE
179
734
  end
180
735
  end
181
736
 
737
+ # Expands a compacted encrypted binary into a map.
738
+ #
739
+ # !!!ruby
740
+ # JOSE::JWE.expand("eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..jBt5tTa1Q0N3uFPEkf30MQ.Ei49MvTLLje7bsZ5EZCZMA.gMWOAmhZSq9ksHCZm6VSoA")
741
+ # # => JOSE::EncryptedMap[
742
+ # # "tag" => "gMWOAmhZSq9ksHCZm6VSoA",
743
+ # # "ciphertext" => "Ei49MvTLLje7bsZ5EZCZMA",
744
+ # # "encrypted_key" => "",
745
+ # # "iv" => "jBt5tTa1Q0N3uFPEkf30MQ",
746
+ # # "protected" => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0"]
747
+ #
748
+ # @see JOSE::JWE.compact
749
+ # @param [JOSE::EncryptedBinary, String] binary
750
+ # @return [JOSE::EncryptedMap]
182
751
  def self.expand(binary)
183
752
  if binary.is_a?(String)
184
753
  parts = binary.split('.')
@@ -199,18 +768,100 @@ module JOSE
199
768
  end
200
769
  end
201
770
 
202
- def self.generate_key(object, modules = {})
203
- return from(object, modules).generate_key
771
+ # Generates a new {JOSE::JWK JOSE::JWK} based on the algorithms of the specified {JOSE::JWE JOSE::JWE}.
772
+ #
773
+ # !!!ruby
774
+ # JOSE::JWE.generate_key({"alg" => "dir", "enc" => "A128GCM"})
775
+ # # => #<struct JOSE::JWK
776
+ # # keys=nil,
777
+ # # kty=#<struct JOSE::JWK::KTY_oct oct="\xED4\x19\x14\xA1\xDB\xB5\xCF*\xAE\xEE7\xDA\xDE\xA9\xCB">,
778
+ # # fields=JOSE::Map["alg" => "dir", "enc" => "A128GCM", "use" => "enc"]>
779
+ #
780
+ # @param [JOSE::Map, Hash, String, JOSE::JWE, Array<JOSE::Map, Hash, String, JOSE::JWE>] jwe
781
+ # @param [Hash] modules
782
+ # @return [JOSE::JWK, Array<JOSE::JWK>]
783
+ def self.generate_key(jwe, modules = {})
784
+ if jwe.is_a?(Array)
785
+ return from(jwe, modules).map { |obj| obj.generate_key }
786
+ else
787
+ return from(jwe, modules).generate_key
788
+ end
204
789
  end
205
790
 
791
+ # Generates a new {JOSE::JWK JOSE::JWK} based on the algorithms of the specified {JOSE::JWE JOSE::JWE}.
792
+ #
793
+ # @see JOSE::JWE.generate_key
794
+ # @return [JOSE::JWK]
206
795
  def generate_key
207
796
  return alg.generate_key(fields, enc)
208
797
  end
209
798
 
799
+ # Decrypts the `encrypted_key` using the `key` and the `"alg"` and `"enc"` specified by the `jwe`.
800
+ #
801
+ # !!!ruby
802
+ # # let's define our jwk and encrypted_key
803
+ # jwk = JOSE::JWK.from({"k" => "idN_YyeYZqEE7BkpexhA2Q", "kty" => "oct"})
804
+ # enc = [27,123,126,121,56,105,105,81,140,76,30,2,14,92,231,174,203,196,110,204,57,238,248,73].pack('C*')
805
+ #
806
+ # JOSE::JWE.key_decrypt(jwk, enc, { "alg" => "A128KW", "enc" => "A128CBC-HS256" })
807
+ # # => "\x86R\x0F\xB0\xB5s\xAD\x13\r,\xBD\xB9\xBB}\x1C\xF0"
808
+ #
809
+ # @see JOSE::JWE.key_encrypt
810
+ # @param [JOSE::JWK, [JOSE::JWK]] key
811
+ # @param [String] encrypted_key
812
+ # @param [JOSE::JWE] jwe
813
+ # @return [String]
814
+ def self.key_decrypt(key, encrypted_key, jwe)
815
+ return from(jwe).key_decrypt(key, encrypted_key)
816
+ end
817
+
818
+ # Decrypts the `encrypted_key` using the `key` and the `"alg"` and `"enc"` specified by the `jwe`.
819
+ #
820
+ # @param [JOSE::JWK, [JOSE::JWK]] key
821
+ # @param [String] encrypted_key
822
+ # @return [String]
210
823
  def key_decrypt(key, encrypted_key)
211
824
  return alg.key_decrypt(key, enc, encrypted_key)
212
825
  end
213
826
 
827
+ # Encrypts the `decrypted_key` using the `key` and the `"alg"` and `"enc"` specified by the `jwe`.
828
+ #
829
+ # !!!ruby
830
+ # # let's define our jwk and encrypted_key
831
+ # jwk = JOSE::JWK.from({"k" => "idN_YyeYZqEE7BkpexhA2Q", "kty" => "oct"})
832
+ # cek = [134,82,15,176,181,115,173,19,13,44,189,185,187,125,28,240].pack('C*')
833
+ #
834
+ # JOSE::JWE.key_encrypt(jwk, cek, { "alg" => "A128KW", "enc" => "A128CBC-HS256" })
835
+ # # => ["\e{~y8iiQ\x8CL\x1E\x02\x0E\\\xE7\xAE\xCB\xC4n\xCC9\xEE\xF8I",
836
+ # # #<struct JOSE::JWE
837
+ # # alg=#<struct JOSE::JWE::ALG_AES_KW bits=128>,
838
+ # # enc=
839
+ # # #<struct JOSE::JWE::ENC_AES_CBC_HMAC
840
+ # # cipher_name="aes-128-cbc",
841
+ # # bits=256,
842
+ # # cek_len=32,
843
+ # # iv_len=16,
844
+ # # enc_len=16,
845
+ # # mac_len=16,
846
+ # # tag_len=16,
847
+ # # hmac=OpenSSL::Digest::SHA256>,
848
+ # # zip=nil,
849
+ # # fields=JOSE::Map[]>]
850
+ #
851
+ # @see JOSE::JWE.key_decrypt
852
+ # @param [JOSE::JWK, [JOSE::JWK]] key
853
+ # @param [String] decrypted_key
854
+ # @param [JOSE::JWE] jwe
855
+ # @return [[String, JOSE::JWE]]
856
+ def self.key_encrypt(key, decrypted_key, jwe)
857
+ return from(jwe).key_encrypt(key, decrypted_key)
858
+ end
859
+
860
+ # Encrypts the `decrypted_key` using the `key` and the `"alg"` and `"enc"` specified by the `jwe`.
861
+ #
862
+ # @param [JOSE::JWK, [JOSE::JWK]] key
863
+ # @param [String] decrypted_key
864
+ # @return [[String, JOSE::JWE]]
214
865
  def key_encrypt(key, decrypted_key)
215
866
  encrypted_key, new_alg = alg.key_encrypt(key, enc, decrypted_key)
216
867
  new_jwe = JOSE::JWE.from_map(to_map)
@@ -218,10 +869,17 @@ module JOSE
218
869
  return encrypted_key, new_jwe
219
870
  end
220
871
 
872
+ # Merges map on right into map on left.
873
+ # @param [JOSE::Map, Hash, String, JOSE::JWE] left
874
+ # @param [JOSE::Map, Hash, String, JOSE::JWE] right
875
+ # @return [JOSE::JWE]
221
876
  def self.merge(left, right)
222
877
  return from(left).merge(right)
223
878
  end
224
879
 
880
+ # Merges object into current map.
881
+ # @param [JOSE::Map, Hash, String, JOSE::JWE] object
882
+ # @return [JOSE::JWE]
225
883
  def merge(object)
226
884
  object = case object
227
885
  when JOSE::Map, Hash
@@ -236,14 +894,131 @@ module JOSE
236
894
  return JOSE::JWE.from_map(self.to_map.merge(object))
237
895
  end
238
896
 
897
+ # Returns the next `cek` using the `jwk` and the `"alg"` and `"enc"` specified by the `jwe`.
898
+ #
899
+ # !!!ruby
900
+ # # let's define our jwk
901
+ # jwk = JOSE::JWK.from({"k" => "idN_YyeYZqEE7BkpexhA2Q", "kty" => "oct"}) # JOSE::JWK.generate_key([:oct, 16])
902
+ #
903
+ # JOSE::JWE.next_cek(jwk, { "alg" => "A128KW", "enc" => "A128CBC-HS256" })
904
+ # # => ["%S\x8B\xA5,\x17\xA3\xBA\xFF\x9B\xB7\x11\xDC\xD3P\xF7\xEF\x95\xC25\x86)\xFE\xB0\x00\xF7B&\xD9\xFCR\xE9",
905
+ # # #<struct JOSE::JWE
906
+ # # alg=#<struct JOSE::JWE::ALG_AES_KW bits=128>,
907
+ # # enc=
908
+ # # #<struct JOSE::JWE::ENC_AES_CBC_HMAC
909
+ # # cipher_name="aes-128-cbc",
910
+ # # bits=256,
911
+ # # cek_len=32,
912
+ # # iv_len=16,
913
+ # # enc_len=16,
914
+ # # mac_len=16,
915
+ # # tag_len=16,
916
+ # # hmac=OpenSSL::Digest::SHA256>,
917
+ # # zip=nil,
918
+ # # fields=JOSE::Map[]>]
919
+ #
920
+ # # when using the "dir" algorithm, the jwk itself will be used
921
+ # JOSE::JWE.next_cek(jwk, { "alg" => "dir", "enc" => "A128GCM" })
922
+ # # => ["\x89\xD3\x7Fc'\x98f\xA1\x04\xEC\x19){\x18@\xD9",
923
+ # # #<struct JOSE::JWE
924
+ # # alg=#<struct JOSE::JWE::ALG_dir direct=true>,
925
+ # # enc=#<struct JOSE::JWE::ENC_AES_GCM cipher_name="aes-128-gcm", bits=128, cek_len=16, iv_len=12>,
926
+ # # zip=nil,
927
+ # # fields=JOSE::Map[]>]
928
+ #
929
+ # @param [JOSE::JWK, [JOSE::JWK, JOSE::JWK]] key
930
+ # @param [JOSE::JWE] jwe
931
+ # @return [[String, JOSE::JWE]]
932
+ def self.next_cek(key, jwe)
933
+ return from(jwe).next_cek(key)
934
+ end
935
+
936
+ # Returns the next `cek` using the `jwk` and the `"alg"` and `"enc"` specified by the `jwe`.
937
+ #
938
+ # @param [JOSE::JWK, [JOSE::JWK, JOSE::JWK]] key
939
+ # @return [[String, JOSE::JWE]]
239
940
  def next_cek(key)
240
- return alg.next_cek(key, enc)
941
+ decrypted_key, new_alg = alg.next_cek(key, enc)
942
+ new_jwe = JOSE::JWE.from_map(to_map)
943
+ new_jwe.alg = new_alg
944
+ return decrypted_key, new_jwe
945
+ end
946
+
947
+ # Returns the next `iv` the `"alg"` and `"enc"` specified by the `jwe`.
948
+ #
949
+ # !!!ruby
950
+ # # typically just returns random bytes for the specified "enc" algorithm
951
+ # JOSE::JWE.next_iv({ "alg" => "dir", "enc" => "A128CBC-HS256" }).bytesize * 8
952
+ # # => 128
953
+ # JOSE::JWE.next_iv({ "alg" => "dir", "enc" => "A128GCM" }).bytesize * 8
954
+ # # => 96
955
+ #
956
+ # @param [JOSE::JWE] jwe
957
+ # @return [String]
958
+ def self.next_iv(jwe)
959
+ return from(jwe).next_iv
241
960
  end
242
961
 
962
+ # Returns the next `iv` the `"alg"` and `"enc"` specified by the `jwe`.
963
+ #
964
+ # @return [String]
243
965
  def next_iv
244
966
  return enc.next_iv
245
967
  end
246
968
 
969
+ # Returns the decoded ciphertext portion of a encrypted binary or map without decrypting the ciphertext.
970
+ #
971
+ # !!!ruby
972
+ # JOSE::JWE.peek_ciphertext("eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0.t4_Fb4kCl6BcS1cXnR4P4Xgm-jwVNsFl.RerKfWjzqqtLIUrz.JmE.ZDpVlWo-aQYM5la9eshwWw")
973
+ # # => "&a"
974
+ #
975
+ # @param [JOSE::EncryptedBinary, String] encrypted
976
+ # @return [String]
977
+ def self.peek_ciphertext(encrypted)
978
+ if encrypted.is_a?(String)
979
+ encrypted = expand(encrypted)
980
+ end
981
+ return JOSE.urlsafe_decode64(encrypted['ciphertext'])
982
+ end
983
+
984
+ # Returns the decoded encrypted key portion of a encrypted binary or map without decrypting the ciphertext.
985
+ #
986
+ # !!!ruby
987
+ # JOSE::JWE.peek_encrypted_key("eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0.t4_Fb4kCl6BcS1cXnR4P4Xgm-jwVNsFl.RerKfWjzqqtLIUrz.JmE.ZDpVlWo-aQYM5la9eshwWw")
988
+ # # => "\xB7\x8F\xC5o\x89\x02\x97\xA0\\KW\x17\x9D\x1E\x0F\xE1x&\xFA<\x156\xC1e"
989
+ #
990
+ # @param [JOSE::EncryptedBinary, String] encrypted
991
+ # @return [String]
992
+ def self.peek_encrypted_key(encrypted)
993
+ if encrypted.is_a?(String)
994
+ encrypted = expand(encrypted)
995
+ end
996
+ return JOSE.urlsafe_decode64(encrypted['encrypted_key'])
997
+ end
998
+
999
+ # Returns the decoded initialization vector portion of a encrypted binary or map without decrypting the ciphertext.
1000
+ #
1001
+ # !!!ruby
1002
+ # JOSE::JWE.peek_iv("eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0.t4_Fb4kCl6BcS1cXnR4P4Xgm-jwVNsFl.RerKfWjzqqtLIUrz.JmE.ZDpVlWo-aQYM5la9eshwWw")
1003
+ # # => "E\xEA\xCA}h\xF3\xAA\xABK!J\xF3"
1004
+ #
1005
+ # @param [JOSE::EncryptedBinary, String] encrypted
1006
+ # @return [String]
1007
+ def self.peek_iv(encrypted)
1008
+ if encrypted.is_a?(String)
1009
+ encrypted = expand(encrypted)
1010
+ end
1011
+ return JOSE.urlsafe_decode64(encrypted['iv'])
1012
+ end
1013
+
1014
+ # Returns the decoded protected portion of a encrypted binary or map without decrypting the ciphertext.
1015
+ #
1016
+ # !!!ruby
1017
+ # JOSE::JWE.peek_protected("eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0.t4_Fb4kCl6BcS1cXnR4P4Xgm-jwVNsFl.RerKfWjzqqtLIUrz.JmE.ZDpVlWo-aQYM5la9eshwWw")
1018
+ # # => JOSE::Map["enc" => "A128GCM", "alg" => "A128KW"]
1019
+ #
1020
+ # @param [JOSE::EncryptedBinary, String] encrypted
1021
+ # @return [JOSE::Map]
247
1022
  def self.peek_protected(encrypted)
248
1023
  if encrypted.is_a?(String)
249
1024
  encrypted = expand(encrypted)
@@ -251,6 +1026,39 @@ module JOSE
251
1026
  return JOSE::Map.new(JOSE.decode(JOSE.urlsafe_decode64(encrypted['protected'])))
252
1027
  end
253
1028
 
1029
+ # Returns the decoded tag portion of a encrypted binary or map without decrypting the ciphertext.
1030
+ #
1031
+ # !!!ruby
1032
+ # JOSE::JWE.peek_tag("eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0.t4_Fb4kCl6BcS1cXnR4P4Xgm-jwVNsFl.RerKfWjzqqtLIUrz.JmE.ZDpVlWo-aQYM5la9eshwWw")
1033
+ # # => "d:U\x95j>i\x06\f\xE6V\xBDz\xC8p["
1034
+ #
1035
+ # @param [JOSE::EncryptedBinary, String] encrypted
1036
+ # @return [String]
1037
+ def self.peek_tag(encrypted)
1038
+ if encrypted.is_a?(String)
1039
+ encrypted = expand(encrypted)
1040
+ end
1041
+ return JOSE.urlsafe_decode64(encrypted['tag'])
1042
+ end
1043
+
1044
+ # Uncompresses the `cipher_text` using the `"zip"` algorithm specified by the `jwe`.
1045
+ #
1046
+ # !!!ruby
1047
+ # JOSE::JWE.uncompress([120,156,171,174,5,0,1,117,0,249].pack('C*'), { "alg" => "dir", "zip" => "DEF" })
1048
+ # # => "{}"
1049
+ #
1050
+ # @see JOSE::JWE.compress
1051
+ # @param [String] cipher_text
1052
+ # @param [JOSE::JWE] jwe
1053
+ # @return [String]
1054
+ def self.uncompress(cipher_text, jwe)
1055
+ return from(jwe).uncompress(cipher_text)
1056
+ end
1057
+
1058
+ # Uncompresses the `cipher_text` using the `"zip"` algorithm specified by the `jwe`.
1059
+ #
1060
+ # @param [String] cipher_text
1061
+ # @return [String]
254
1062
  def uncompress(cipher_text)
255
1063
  if zip.nil?
256
1064
  return cipher_text