jose 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8804406a3e47d37b89da4315eb021d33d447ecf7
4
- data.tar.gz: 9409c19e851ef2036b1fc843eeeaa3667c64ed40
3
+ metadata.gz: d1a9a636263c7a8b720c8f54649b22a02d3afd4e
4
+ data.tar.gz: f5a8c4e5ed511dc60a7df47ed4239eeff3437513
5
5
  SHA512:
6
- metadata.gz: ade14cfd65ca8cab5f24b5329448db0e0ee19d04fa71ec43fda67300197563c361c20f2229dba79f0b6b4b01cf9440482cae460324ce069fa782c66e3430b284
7
- data.tar.gz: 391d322825bf7905f41800ae0ed77f7d29b0c27018ac06e65bcf3d04288fe579191a4278beac44e5a2f09e2e9350c22da4cab0189c126fef258888d4e1f53516
6
+ metadata.gz: 89419348db067439802b64b2018ba3706e904be1f164255e046d3a39879b874e88b6772ebd6777b6634b2447ef4daae8300c710a59b637b809019774561b2968
7
+ data.tar.gz: 6e5c379c6de44614898d587aa09e810a968b163121859627e5f9f8dfcfa4bf5a31720af2300f9671272515a7c92528a84a6d74e8a959b5b6d6978546039a1bab
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  /.bundle/
2
+ /.minitest-perf.db
2
3
  /.yardoc
3
4
  /Gemfile.lock
4
5
  /_yardoc/
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0 (2016-05-10)
4
+
5
+ * Enhancements
6
+ * Test coverage is now slightly above 90%.
7
+ * Removed legacy support for 32-byte Ed448 and Ed448ph secret keys.
8
+ * Improved behavior of ECDH-ES encryption.
9
+
10
+ * Fixes
11
+ * X25519 uses RbNaCl when available.
12
+ * Various argument order fixes.
13
+
3
14
  ## 1.0.0 (2016-05-07)
4
15
 
5
16
  * Enhancements
data/Gemfile CHANGED
@@ -2,15 +2,18 @@ source 'https://rubygems.org'
2
2
 
3
3
  platforms :ruby do
4
4
  group :development do
5
- gem "pry"
6
- gem "pry-doc"
7
- # gem "redcarpet"
8
- # gem "yard"
5
+ gem 'pry'
6
+ gem 'pry-doc'
7
+ # gem 'redcarpet'
8
+ gem 'yard'
9
9
  end
10
10
  end
11
11
 
12
12
  group :test do
13
- gem "simplecov", require: false
13
+ gem 'minitest-focus', require: false
14
+ gem 'minitest-perf', require: false
15
+ gem 'rantly', github: 'abargnesi/rantly', ref: '4d219ea3eb340a5153a43d051b2e22ccb2bce274', require: false
16
+ gem 'simplecov', require: false
14
17
  if ENV['CI']
15
18
  gem 'coveralls', require: false
16
19
  end
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # JOSE
2
2
 
3
- [![Travis](https://img.shields.io/travis/potatosalad/ruby-jose.svg?maxAge=2592000)](https://travis-ci.org/potatosalad/ruby-jose) [![Gem](https://img.shields.io/gem/v/jose.svg?maxAge=2592000)](https://rubygems.org/gems/jose) [![Docs](https://img.shields.io/badge/yard-docs-blue.svg?maxAge=2592000)](http://www.rubydoc.info/gems/jose) [![Inline docs](http://inch-ci.org/github/potatosalad/ruby-jose.svg?branch=master&style=shields)](http://inch-ci.org/github/potatosalad/ruby-jose)
3
+ [![Travis](https://img.shields.io/travis/potatosalad/ruby-jose.svg?maxAge=86400)](https://travis-ci.org/potatosalad/ruby-jose) [![Coverage Status](https://coveralls.io/repos/github/potatosalad/ruby-jose/badge.svg?branch=master)](https://coveralls.io/github/potatosalad/ruby-jose?branch=master) [![Gem](https://img.shields.io/gem/v/jose.svg?maxAge=86400)](https://rubygems.org/gems/jose) [![Docs](https://img.shields.io/badge/yard-docs-blue.svg?maxAge=86400)](http://www.rubydoc.info/gems/jose) [![Inline docs](http://inch-ci.org/github/potatosalad/ruby-jose.svg?branch=master&style=shields)](http://inch-ci.org/github/potatosalad/ruby-jose)
4
4
 
5
5
  JSON Object Signing and Encryption (JOSE) for Ruby.
6
6
 
@@ -45,6 +45,7 @@ verified, message, = jwk.verify(signed)
45
45
  ```
46
46
 
47
47
  More details and examples:
48
+
48
49
  - [Getting Started](http://www.rubydoc.info/gems/jose/file/docs/GettingStarted.md)
49
50
  - [Key Generation](http://www.rubydoc.info/gems/jose/file/docs/KeyGeneration.md)
50
51
  - [Encryption Algorithms](http://www.rubydoc.info/gems/jose/file/docs/EncryptionAlgorithms.md)
@@ -4,6 +4,7 @@ require 'base64'
4
4
  require 'hamster/hash'
5
5
  require 'json'
6
6
  require 'openssl'
7
+ require 'securerandom'
7
8
  require 'thread'
8
9
 
9
10
  # JOSE stands for JSON Object Signing and Encryption which is a is a set of
@@ -129,20 +130,21 @@ module JOSE
129
130
  # @param [String] binary
130
131
  # @return [String]
131
132
  def self.urlsafe_decode64(binary)
133
+ binary = binary.tr('-_', '+/')
132
134
  case binary.bytesize % 4
133
135
  when 2
134
136
  binary += '=='
135
137
  when 3
136
138
  binary += '='
137
139
  end
138
- return Base64.urlsafe_decode64(binary)
140
+ return Base64.decode64(binary)
139
141
  end
140
142
 
141
143
  # Returns the Base64Url encoded version of `binary` without padding.
142
144
  # @param [String] binary
143
145
  # @return [String]
144
146
  def self.urlsafe_encode64(binary)
145
- return Base64.urlsafe_encode64(binary).tr('=', '')
147
+ return Base64.strict_encode64(binary).tr('+/', '-_').delete('=')
146
148
  end
147
149
 
148
150
  private
@@ -51,15 +51,15 @@ module JOSE::JWA::Curve25519_RbNaCl
51
51
  end
52
52
 
53
53
  def x25519_keypair(secret = nil)
54
- return JOSE::JWA::X25519.keypair(secret)
54
+ return JOSE::JWA::X25519_RbNaCl.keypair(secret)
55
55
  end
56
56
 
57
57
  def x25519_secret_to_public(sk)
58
- return JOSE::JWA::X25519.sk_to_pk(sk)
58
+ return JOSE::JWA::X25519_RbNaCl.sk_to_pk(sk)
59
59
  end
60
60
 
61
61
  def x25519_shared_secret(pk, sk)
62
- return JOSE::JWA::X25519.shared_secret(pk, sk)
62
+ return JOSE::JWA::X25519_RbNaCl.shared_secret(pk, sk)
63
63
  end
64
64
 
65
65
  end
@@ -5,15 +5,13 @@ module JOSE::JWA::Ed448
5
5
  C_bits = 456
6
6
  C_bytes = (C_bits + 7) / 8
7
7
  C_secretbytes = C_bytes
8
- C_legacysecretbytes = 32
9
8
  C_publickeybytes = C_bytes
10
9
  C_secretkeybytes = C_secretbytes + C_publickeybytes
11
- C_legacysecretkeybytes = C_legacysecretbytes + C_publickeybytes
12
10
  C_signaturebytes = C_bytes + C_bytes
13
11
  C_B = JOSE::JWA::Edwards448Point.stdbase.freeze
14
12
 
15
13
  def secret_to_curve448(secret)
16
- raise ArgumentError, "secret must be #{C_secretbytes} bytes" if secret.bytesize != C_secretbytes and secret.bytesize != C_legacysecretbytes
14
+ raise ArgumentError, "secret must be #{C_secretbytes} bytes" if secret.bytesize != C_secretbytes
17
15
  curve448_scalar = JOSE::JWA::SHA3.shake256(secret, 114)[0, 56]
18
16
  curve448_scalar.setbyte(0, curve448_scalar.getbyte(0) & 252)
19
17
  curve448_scalar.setbyte(55, curve448_scalar.getbyte(55) | 128)
@@ -21,7 +19,7 @@ module JOSE::JWA::Ed448
21
19
  end
22
20
 
23
21
  def secret_to_pk(secret)
24
- raise ArgumentError, "secret must be #{C_secretbytes} bytes" if secret.bytesize != C_secretbytes and secret.bytesize != C_legacysecretbytes
22
+ raise ArgumentError, "secret must be #{C_secretbytes} bytes" if secret.bytesize != C_secretbytes
25
23
  return (C_B * OpenSSL::BN.new(secret_to_curve448(secret).reverse, 2).to_i).encode()
26
24
  end
27
25
 
@@ -34,13 +32,11 @@ module JOSE::JWA::Ed448
34
32
 
35
33
  def sk_to_secret(sk)
36
34
  return sk[0, C_secretbytes] if sk.bytesize == C_secretkeybytes
37
- return sk[0, C_legacysecretbytes] if sk.bytesize == C_legacysecretkeybytes
38
35
  raise ArgumentError, "sk must be #{C_secretkeybytes} bytes"
39
36
  end
40
37
 
41
38
  def sk_to_pk(sk)
42
39
  return sk[C_secretbytes, C_secretkeybytes] if sk.bytesize == C_secretkeybytes
43
- return sk[C_legacysecretbytes, C_legacysecretkeybytes] if sk.bytesize == C_legacysecretkeybytes
44
40
  raise ArgumentError, "sk must be #{C_secretkeybytes} bytes"
45
41
  end
46
42
 
@@ -56,14 +52,12 @@ module JOSE::JWA::Ed448
56
52
  end
57
53
 
58
54
  def sign(m, sk, ctx = nil)
59
- raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes and sk.bytesize != C_legacysecretkeybytes
55
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes
60
56
  ctx ||= ''
61
57
  raise ArgumentError, "ctx must be 255 bytes or smaller" if ctx.bytesize > 255
62
58
  secret, pk = nil, nil
63
59
  if sk.bytesize == C_secretkeybytes
64
60
  secret, pk = sk[0, 57], sk[57, 114]
65
- elsif sk.bytesize == C_legacysecretkeybytes
66
- secret, pk = sk[0, 32], sk[32, 89]
67
61
  end
68
62
  khash = JOSE::JWA::SHA3.shake256(secret, 114)
69
63
  curve448_scalar, seed = khash[0, 57], khash[57, 114]
@@ -83,15 +77,13 @@ module JOSE::JWA::Ed448
83
77
  end
84
78
 
85
79
  def sign_ph(m, sk, ctx = nil)
86
- raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes and sk.bytesize != C_legacysecretkeybytes
80
+ raise ArgumentError, "sk must be #{C_secretkeybytes} bytes" if sk.bytesize != C_secretkeybytes
87
81
  ctx ||= ''
88
82
  raise ArgumentError, "ctx must be 255 bytes or smaller" if ctx.bytesize > 255
89
83
  m = JOSE::JWA::SHA3.shake256(['SigEd448', 2, ctx.bytesize, ctx, m].pack('a*CCa*a*'), 64)
90
84
  secret, pk = nil, nil
91
85
  if sk.bytesize == C_secretkeybytes
92
86
  secret, pk = sk[0, 57], sk[57, 114]
93
- elsif sk.bytesize == C_legacysecretkeybytes
94
- secret, pk = sk[0, 32], sk[32, 89]
95
87
  end
96
88
  khash = JOSE::JWA::SHA3.shake256(secret, 114)
97
89
  curve448_scalar, seed = khash[0, 57], khash[57, 114]
@@ -106,7 +106,7 @@ class JOSE::JWA::FieldElement
106
106
  end
107
107
 
108
108
  def sign
109
- return @x%2
109
+ return @x % 2.to_bn
110
110
  end
111
111
 
112
112
  def value
@@ -231,15 +231,15 @@ module JOSE
231
231
  # # => "{}"
232
232
  #
233
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
234
+ # encrypted_ecdhesa192kw_alice2bob = JOSE::JWE.block_encrypt([jwk_ec256_bob_pk, jwk_ec256_alice_sk], "{}", { "alg" => "ECDH-ES+A192KW", "enc" => "A192GCM" }).compact
235
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
236
+ # JOSE::JWE.block_decrypt([jwk_ec256_alice_pk, jwk_ec256_bob_sk], encrypted_ecdhesa192kw_alice2bob).first
237
237
  # # => "{}"
238
238
  #
239
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
240
+ # encrypted_ecdhesa256kw_alice2bob = JOSE::JWE.block_encrypt([jwk_ec256_bob_pk, jwk_ec256_alice_sk], "{}", { "alg" => "ECDH-ES+A256KW", "enc" => "A256GCM" }).compact
241
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
242
+ # JOSE::JWE.block_decrypt([jwk_ec256_alice_pk, jwk_ec256_bob_sk], encrypted_ecdhesa256kw_alice2bob).first
243
243
  # # => "{}"
244
244
  #
245
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.
@@ -1,8 +1,13 @@
1
1
  module JOSE::JWE::ALG
2
2
 
3
- extend self
4
-
5
- def generate_key(parameters, algorithm, encryption)
3
+ # Generates a new {JOSE::JWK JOSE::JWK} based on the `parameters`, `algorithm`, and `encryption`.
4
+ #
5
+ # @see JOSE::JWK.generate_key
6
+ # @param [Array] parameters
7
+ # @param [String] algorithm
8
+ # @param [String] encryption
9
+ # @return [JOSE::JWK]
10
+ def self.generate_key(parameters, algorithm, encryption)
6
11
  return JOSE::JWK.generate_key(parameters).merge({
7
12
  'alg' => algorithm,
8
13
  'enc' => encryption,
@@ -597,7 +597,16 @@ module JOSE
597
597
  # @param [JOSE::EncryptedBinary, JOSE::EncryptedMap] encrypted
598
598
  # @return [[String, JOSE::JWE]]
599
599
  def self.block_decrypt(jwk, encrypted)
600
- return from(jwk).block_decrypt(encrypted)
600
+ if jwk.is_a?(Array)
601
+ public_jwk, secret_jwk = from(jwk)
602
+ if secret_jwk.nil?
603
+ secret_jwk = public_jwk
604
+ public_jwk = nil
605
+ end
606
+ return box_decrypt(secret_jwk, encrypted, public_jwk)
607
+ else
608
+ return from(jwk).block_decrypt(encrypted)
609
+ end
601
610
  end
602
611
 
603
612
  # Decrypts the `encrypted` binary or map using the `jwk`.
@@ -617,7 +626,11 @@ module JOSE
617
626
  # @param [JOSE::JWE] jwe
618
627
  # @return [JOSE::EncryptedMap]
619
628
  def self.block_encrypt(jwk, plain_text, jwe = nil)
620
- return from(jwk).block_encrypt(plain_text, jwe)
629
+ if jwk.is_a?(Array)
630
+ return box_encrypt(plain_text, from(jwk), jwe)
631
+ else
632
+ return from(jwk).block_encrypt(plain_text, jwe)
633
+ end
621
634
  end
622
635
 
623
636
  # Encrypts the `plain_text` using the `jwk` and algorithms specified by the `jwe`.
@@ -688,8 +701,8 @@ module JOSE
688
701
  # @param [JOSE::JWE] jwe
689
702
  # @return [JOSE::EncryptedMap, [JOSE::EncryptedMap, JOSE::JWK]]
690
703
  def self.box_encrypt(plain_text, box_keys, jwe = nil)
691
- other_public_key, my_private_key = box_keys
692
- return from(other_public_key).box_encrypt(plain_text, my_private_jwk, jwe)
704
+ jwk_public, jwk_secret = from(box_keys)
705
+ return jwk_public.box_encrypt(plain_text, jwk_secret, jwe)
693
706
  end
694
707
 
695
708
  # Key Agreement encryption of `plain_text` by generating an ephemeral private key based on `other_public_jwk` curve.
@@ -699,42 +712,51 @@ module JOSE
699
712
  # @see JOSE::JWK.box_decrypt
700
713
  # @see JOSE::JWE.block_encrypt
701
714
  # @param [String] plain_text
702
- # @param [JOSE::JWK] my_private_jwk
715
+ # @param [JOSE::JWK] jwk_secret
703
716
  # @param [JOSE::JWE] jwe
704
717
  # @return [JOSE::EncryptedMap, [JOSE::EncryptedMap, JOSE::JWK]]
705
- def box_encrypt(plain_text, my_private_jwk = nil, jwe = nil)
706
- generated_jwk = nil
707
- other_public_jwk = self
708
- if my_private_jwk.nil?
709
- generated_jwk = my_private_jwk = other_public_jwk.generate_key
718
+ def box_encrypt(plain_text, jwk_secret = nil, jwe = nil)
719
+ epk_secret = nil
720
+ jwk_public = self
721
+ if jwk_secret.nil?
722
+ epk_secret = jwk_secret = jwk_public.generate_key
710
723
  end
711
- if not my_private_jwk.is_a?(JOSE::JWK)
712
- my_private_jwk = JOSE::JWK.from(my_private_jwk)
724
+ if not jwk_secret.is_a?(JOSE::JWK)
725
+ jwk_secret = JOSE::JWK.from(jwk_secret)
713
726
  end
714
727
  if jwe.nil?
715
- jwe = other_public_jwk.block_encryptor
728
+ jwe = jwk_public.block_encryptor
716
729
  end
717
730
  if jwe.is_a?(Hash)
718
731
  jwe = JOSE::Map.new(jwe)
719
732
  end
720
733
  if jwe.is_a?(JOSE::Map)
721
734
  if jwe['apu'].nil?
722
- jwe = jwe.put('apu', my_private_jwk.fields['kid'] || my_private_jwk.thumbprint)
735
+ jwe = jwe.put('apu', jwk_secret.fields['kid'] || jwk_secret.thumbprint)
723
736
  end
724
737
  if jwe['apv'].nil?
725
- jwe = jwe.put('apv', other_public_jwk.fields['kid'] || other_public_jwk.thumbprint)
738
+ jwe = jwe.put('apv', jwk_public.fields['kid'] || jwk_public.thumbprint)
726
739
  end
727
740
  if jwe['epk'].nil?
728
- jwe = jwe.put('epk', my_private_jwk.to_public_map)
741
+ jwe = jwe.put('epk', jwk_secret.to_public_map)
729
742
  end
730
743
  end
731
- if generated_jwk
732
- return JOSE::JWE.block_encrypt([other_public_jwk, my_private_jwk], plain_text, jwe), generated_jwk
744
+ if epk_secret
745
+ return JOSE::JWE.block_encrypt([jwk_public, jwk_secret], plain_text, jwe), epk_secret
733
746
  else
734
- return JOSE::JWE.block_encrypt([other_public_jwk, my_private_jwk], plain_text, jwe)
747
+ return JOSE::JWE.block_encrypt([jwk_public, jwk_secret], plain_text, jwe)
735
748
  end
736
749
  end
737
750
 
751
+ # Derives a key (typically just returns a binary representation of the key).
752
+ #
753
+ # @param [JOSE::JWK] jwk
754
+ # @param [*Object] args
755
+ # @return [String]
756
+ def self.derive_key(jwk, *args)
757
+ return from(jwk).derive_key(*args)
758
+ end
759
+
738
760
  # Derives a key (typically just returns a binary representation of the key).
739
761
  #
740
762
  # @param [*Object] args
@@ -858,12 +880,16 @@ module JOSE
858
880
  # Signs the `plain_text` using the `jwk` and the default signer algorithm `jws` for the key type.
859
881
  #
860
882
  # @see JOSE::JWS.sign
861
- # @param [JOSE::JWK] jwk
862
883
  # @param [String] plain_text
863
884
  # @param [JOSE::JWS] jws
885
+ # @param [JOSE::JWK] jwk
864
886
  # @param [JOSE::Map] header
865
887
  # @return [JOSE::SignedMap]
866
- def self.sign(jwk, plain_text, jws = nil, header = nil)
888
+ def self.sign(plain_text, jws, jwk = nil, header = nil)
889
+ if jwk.nil?
890
+ jwk = jws
891
+ jws = nil
892
+ end
867
893
  return from(jwk).sign(plain_text, jws, header)
868
894
  end
869
895
 
@@ -3,6 +3,7 @@ module JOSE::JWK::KTY
3
3
  extend self
4
4
 
5
5
  def from_key(object)
6
+ object = object.__getobj__ if object.is_a?(JOSE::JWK::PKeyProxy)
6
7
  case object
7
8
  when OpenSSL::PKey::EC
8
9
  return JOSE::JWK::KTY_EC.from_key(object)
@@ -29,6 +30,8 @@ module JOSE::JWK::KTY
29
30
 
30
31
  end
31
32
 
33
+ require 'jose/jwk/pkey_proxy'
34
+
32
35
  require 'jose/jwk/kty_ec'
33
36
  require 'jose/jwk/kty_oct'
34
37
  require 'jose/jwk/kty_okp_ed25519'
@@ -24,14 +24,14 @@ class JOSE::JWK::KTY_EC < Struct.new(:key)
24
24
  if fields['d'].is_a?(String)
25
25
  ec.private_key = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
26
26
  end
27
- return JOSE::JWK::KTY_EC.new(ec), fields.except('kty', 'crv', 'd', 'x', 'y')
27
+ return JOSE::JWK::KTY_EC.new(JOSE::JWK::PKeyProxy.new(ec)), fields.except('kty', 'crv', 'd', 'x', 'y')
28
28
  else
29
29
  raise ArgumentError, "invalid 'EC' JWK"
30
30
  end
31
31
  end
32
32
 
33
33
  def to_key
34
- return key
34
+ return key.__getobj__
35
35
  end
36
36
 
37
37
  def to_map(fields)
@@ -211,9 +211,10 @@ class JOSE::JWK::KTY_EC < Struct.new(:key)
211
211
  # API functions
212
212
 
213
213
  def self.from_key(key)
214
+ key = key.__getobj__ if key.is_a?(JOSE::JWK::PKeyProxy)
214
215
  case key
215
216
  when OpenSSL::PKey::EC
216
- return JOSE::JWK::KTY_EC.new(key), JOSE::Map[]
217
+ return JOSE::JWK::KTY_EC.new(JOSE::JWK::PKeyProxy.new(key)), JOSE::Map[]
217
218
  else
218
219
  raise ArgumentError, "'key' must be a OpenSSL::PKey::EC"
219
220
  end
@@ -134,7 +134,7 @@ class JOSE::JWK::KTY_OKP_Ed25519ph < Struct.new(:okp)
134
134
  end
135
135
 
136
136
  def to_okp
137
- return [:Ed25519, okp]
137
+ return [:Ed25519ph, okp]
138
138
  end
139
139
 
140
140
  def to_openssh_key(fields)
@@ -1,10 +1,8 @@
1
1
  class JOSE::JWK::KTY_OKP_Ed448 < Struct.new(:okp)
2
2
 
3
3
  SECRET_BYTES = 57
4
- LEGACY_SECRET_BYTES = 32
5
4
  PK_BYTES = 57
6
5
  SK_BYTES = SECRET_BYTES + PK_BYTES
7
- LEGACY_SK_BYTES = LEGACY_SECRET_BYTES + PK_BYTES
8
6
 
9
7
  # JOSE::JWK callbacks
10
8
 
@@ -15,7 +13,7 @@ class JOSE::JWK::KTY_OKP_Ed448 < Struct.new(:okp)
15
13
  if fields['d'].is_a?(String)
16
14
  secret = JOSE.urlsafe_decode64(fields['d'])
17
15
  end
18
- if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES or secret.bytesize == LEGACY_SECRET_BYTES)
16
+ if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES)
19
17
  if secret.nil?
20
18
  return JOSE::JWK::KTY_OKP_Ed448.new(pk), fields.except('kty', 'crv', 'x')
21
19
  else
@@ -38,13 +36,6 @@ class JOSE::JWK::KTY_OKP_Ed448 < Struct.new(:okp)
38
36
  put('d', JOSE.urlsafe_encode64(secret)).
39
37
  put('kty', 'OKP').
40
38
  put('x', JOSE.urlsafe_encode64(pk))
41
- elsif okp.bytesize == LEGACY_SK_BYTES
42
- secret, pk = okp[0, LEGACY_SECRET_BYTES], okp[LEGACY_SECRET_BYTES, LEGACY_SK_BYTES]
43
- return fields.
44
- put('crv', 'Ed448').
45
- put('d', JOSE.urlsafe_encode64(secret)).
46
- put('kty', 'OKP').
47
- put('x', JOSE.urlsafe_encode64(pk))
48
39
  else
49
40
  pk = okp
50
41
  return fields.
@@ -71,7 +62,7 @@ class JOSE::JWK::KTY_OKP_Ed448 < Struct.new(:okp)
71
62
  elsif okp_params.is_a?(String)
72
63
  secret = okp_params
73
64
  end
74
- if secret.nil? or (secret.is_a?(String) and (secret.bytesize == SECRET_BYTES or secret.bytesize == LEGACY_SECRET_BYTES))
65
+ if secret.nil? or (secret.is_a?(String) and (secret.bytesize == SECRET_BYTES))
75
66
  return from_okp([:Ed448, JOSE::JWA::Curve448.ed448_keypair(secret)[1]])
76
67
  else
77
68
  raise ArgumentError, "'secret' must be nil or a String of #{SECRET_BYTES} bytes"
@@ -89,14 +80,14 @@ class JOSE::JWK::KTY_OKP_Ed448 < Struct.new(:okp)
89
80
 
90
81
  def sign(message, digest_type)
91
82
  raise ArgumentError, "'digest_type' must be :Ed448" if digest_type != :Ed448
92
- raise NotImplementedError, "Ed448 public key cannot be used for signing" if okp.bytesize != SK_BYTES and okp.bytesize != LEGACY_SK_BYTES
83
+ raise NotImplementedError, "Ed448 public key cannot be used for signing" if okp.bytesize != SK_BYTES
93
84
  return JOSE::JWA::Curve448.ed448_sign(message, okp)
94
85
  end
95
86
 
96
87
  def signer(fields = nil)
97
- if (okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES) and fields and fields['use'] == 'sig' and not fields['alg'].nil?
88
+ if okp.bytesize == SK_BYTES and fields and fields['use'] == 'sig' and not fields['alg'].nil?
98
89
  return JOSE::Map['alg' => fields['alg']]
99
- elsif (okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES)
90
+ elsif okp.bytesize == SK_BYTES
100
91
  return JOSE::Map['alg' => 'Ed448']
101
92
  else
102
93
  raise ArgumentError, "signing not supported for public keys"
@@ -114,14 +105,14 @@ class JOSE::JWK::KTY_OKP_Ed448 < Struct.new(:okp)
114
105
  def verify(message, digest_type, signature)
115
106
  raise ArgumentError, "'digest_type' must be :Ed448" if digest_type != :Ed448
116
107
  pk = okp
117
- pk = JOSE::JWA::Curve448.ed448_secret_to_public(okp) if okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES
108
+ pk = JOSE::JWA::Curve448.ed448_secret_to_public(okp) if okp.bytesize == SK_BYTES
118
109
  return JOSE::JWA::Curve448.ed448_verify(signature, message, pk)
119
110
  end
120
111
 
121
112
  # API functions
122
113
 
123
114
  def self.from_okp(okp)
124
- if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed448 and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES or okp[1].bytesize == LEGACY_SK_BYTES)
115
+ if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed448 and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES)
125
116
  return JOSE::JWK::KTY_OKP_Ed448.new(okp[1]), JOSE::Map[]
126
117
  else
127
118
  raise ArgumentError, "'okp' must be an Array in the form of [:Ed448, String]"
@@ -1,10 +1,8 @@
1
1
  class JOSE::JWK::KTY_OKP_Ed448ph < Struct.new(:okp)
2
2
 
3
3
  SECRET_BYTES = 57
4
- LEGACY_SECRET_BYTES = 32
5
4
  PK_BYTES = 57
6
5
  SK_BYTES = SECRET_BYTES + PK_BYTES
7
- LEGACY_SK_BYTES = LEGACY_SECRET_BYTES + PK_BYTES
8
6
 
9
7
  # JOSE::JWK callbacks
10
8
 
@@ -15,7 +13,7 @@ class JOSE::JWK::KTY_OKP_Ed448ph < Struct.new(:okp)
15
13
  if fields['d'].is_a?(String)
16
14
  secret = JOSE.urlsafe_decode64(fields['d'])
17
15
  end
18
- if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES or secret.bytesize == LEGACY_SECRET_BYTES)
16
+ if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES)
19
17
  if secret.nil?
20
18
  return JOSE::JWK::KTY_OKP_Ed448ph.new(pk), fields.except('kty', 'crv', 'x')
21
19
  else
@@ -38,13 +36,6 @@ class JOSE::JWK::KTY_OKP_Ed448ph < Struct.new(:okp)
38
36
  put('d', JOSE.urlsafe_encode64(secret)).
39
37
  put('kty', 'OKP').
40
38
  put('x', JOSE.urlsafe_encode64(pk))
41
- elsif okp.bytesize == LEGACY_SK_BYTES
42
- secret, pk = okp[0, LEGACY_SECRET_BYTES], okp[LEGACY_SECRET_BYTES, LEGACY_SK_BYTES]
43
- return fields.
44
- put('crv', 'Ed448ph').
45
- put('d', JOSE.urlsafe_encode64(secret)).
46
- put('kty', 'OKP').
47
- put('x', JOSE.urlsafe_encode64(pk))
48
39
  else
49
40
  pk = okp
50
41
  return fields.
@@ -71,7 +62,7 @@ class JOSE::JWK::KTY_OKP_Ed448ph < Struct.new(:okp)
71
62
  elsif okp_params.is_a?(String)
72
63
  secret = okp_params
73
64
  end
74
- if secret.nil? or (secret.is_a?(String) and (secret.bytesize == SECRET_BYTES or secret.bytesize == LEGACY_SECRET_BYTES))
65
+ if secret.nil? or (secret.is_a?(String) and (secret.bytesize == SECRET_BYTES))
75
66
  return from_okp([:Ed448ph, JOSE::JWA::Curve448.ed448ph_keypair(secret)[1]])
76
67
  else
77
68
  raise ArgumentError, "'secret' must be nil or a String of #{SECRET_BYTES} bytes"
@@ -89,14 +80,14 @@ class JOSE::JWK::KTY_OKP_Ed448ph < Struct.new(:okp)
89
80
 
90
81
  def sign(message, digest_type)
91
82
  raise ArgumentError, "'digest_type' must be :Ed448ph" if digest_type != :Ed448ph
92
- raise NotImplementedError, "Ed448ph public key cannot be used for signing" if okp.bytesize != SK_BYTES and okp.bytesize != LEGACY_SK_BYTES
83
+ raise NotImplementedError, "Ed448ph public key cannot be used for signing" if okp.bytesize != SK_BYTES
93
84
  return JOSE::JWA::Curve448.ed448ph_sign(message, okp)
94
85
  end
95
86
 
96
87
  def signer(fields = nil)
97
- if (okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES) and fields and fields['use'] == 'sig' and not fields['alg'].nil?
88
+ if okp.bytesize == SK_BYTES and fields and fields['use'] == 'sig' and not fields['alg'].nil?
98
89
  return JOSE::Map['alg' => fields['alg']]
99
- elsif (okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES)
90
+ elsif okp.bytesize == SK_BYTES
100
91
  return JOSE::Map['alg' => 'Ed448ph']
101
92
  else
102
93
  raise ArgumentError, "signing not supported for public keys"
@@ -114,14 +105,14 @@ class JOSE::JWK::KTY_OKP_Ed448ph < Struct.new(:okp)
114
105
  def verify(message, digest_type, signature)
115
106
  raise ArgumentError, "'digest_type' must be :Ed448ph" if digest_type != :Ed448ph
116
107
  pk = okp
117
- pk = JOSE::JWA::Curve448.ed448ph_secret_to_public(okp) if okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES
108
+ pk = JOSE::JWA::Curve448.ed448ph_secret_to_public(okp) if okp.bytesize == SK_BYTES
118
109
  return JOSE::JWA::Curve448.ed448ph_verify(signature, message, pk)
119
110
  end
120
111
 
121
112
  # API functions
122
113
 
123
114
  def self.from_okp(okp)
124
- if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed448ph and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES or okp[1].bytesize == LEGACY_SK_BYTES)
115
+ if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed448ph and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES)
125
116
  return JOSE::JWK::KTY_OKP_Ed448ph.new(okp[1]), JOSE::Map[]
126
117
  else
127
118
  raise ArgumentError, "'okp' must be an Array in the form of [:Ed448ph, String]"
@@ -17,7 +17,7 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
17
17
  rsa.p = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['p']), 2)
18
18
  rsa.q = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['q']), 2)
19
19
  rsa.iqmp = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['qi']), 2)
20
- return JOSE::JWK::KTY_RSA.new(rsa), fields.except('kty', 'd', 'dp', 'dq', 'e', 'n', 'p', 'q', 'qi')
20
+ return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(rsa)), fields.except('kty', 'd', 'dp', 'dq', 'e', 'n', 'p', 'q', 'qi')
21
21
  else
22
22
  raise ArgumentError, "invalid 'RSA' JWK"
23
23
  end
@@ -25,7 +25,7 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
25
25
  rsa = OpenSSL::PKey::RSA.new
26
26
  rsa.e = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2)
27
27
  rsa.n = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)
28
- return JOSE::JWK::KTY_RSA.new(rsa), fields.except('kty', 'e', 'n')
28
+ return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(rsa)), fields.except('kty', 'e', 'n')
29
29
  end
30
30
  else
31
31
  raise ArgumentError, "invalid 'RSA' JWK"
@@ -33,7 +33,7 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
33
33
  end
34
34
 
35
35
  def to_key
36
- return key
36
+ return key.__getobj__
37
37
  end
38
38
 
39
39
  def to_map(fields)
@@ -187,9 +187,10 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key)
187
187
  # API functions
188
188
 
189
189
  def self.from_key(key)
190
+ key = key.__getobj__ if key.is_a?(JOSE::JWK::PKeyProxy)
190
191
  case key
191
192
  when OpenSSL::PKey::RSA
192
- return JOSE::JWK::KTY_RSA.new(key), JOSE::Map[]
193
+ return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(key)), JOSE::Map[]
193
194
  else
194
195
  raise ArgumentError, "'key' must be a OpenSSL::PKey::RSA"
195
196
  end
@@ -0,0 +1,7 @@
1
+ require 'delegate'
2
+
3
+ class JOSE::JWK::PKeyProxy < SimpleDelegator
4
+ def ==(other)
5
+ __getobj__.export == other.export
6
+ end
7
+ end
@@ -1,8 +1,12 @@
1
1
  module JOSE::JWS::ALG
2
2
 
3
- extend self
4
-
5
- def generate_key(parameters, algorithm)
3
+ # Generates a new {JOSE::JWK JOSE::JWK} based on the `parameters` and `algorithm`.
4
+ #
5
+ # @see JOSE::JWK.generate_key
6
+ # @param [Array] parameters
7
+ # @param [String] algorithm
8
+ # @return [JOSE::JWK]
9
+ def self.generate_key(parameters, algorithm)
6
10
  return JOSE::JWK.generate_key(parameters).merge({
7
11
  'alg' => algorithm,
8
12
  'use' => 'sig'
@@ -218,7 +218,7 @@ module JOSE
218
218
  plain_text = to_binary
219
219
  if jwe.nil?
220
220
  jwk = JOSE::JWK.from(jwk)
221
- jwe = jwk.block_encryptor
221
+ jwe = (jwk.is_a?(Array) ? jwk.last : jwk).block_encryptor
222
222
  end
223
223
  if jwe.is_a?(Hash)
224
224
  jwe = JOSE::Map.new(jwe)
@@ -316,7 +316,7 @@ module JOSE
316
316
  if not jws.has_key?('typ')
317
317
  jws = jws.put('typ', 'JWT')
318
318
  end
319
- return JOSE::JWK.sign(jwk, plain_text, jws, header)
319
+ return JOSE::JWK.sign(plain_text, jws, jwk, header)
320
320
  end
321
321
 
322
322
  # Verifies the `signed` using the `jwk` and calls {JOSE::JWT.from JOST::JWT.from} on the payload.
@@ -1,3 +1,3 @@
1
1
  module JOSE
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jose
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Bennett
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-05-07 00:00:00.000000000 Z
11
+ date: 2016-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hamster
@@ -168,6 +168,7 @@ files:
168
168
  - lib/jose/jwk/kty_rsa.rb
169
169
  - lib/jose/jwk/openssh_key.rb
170
170
  - lib/jose/jwk/pem.rb
171
+ - lib/jose/jwk/pkey_proxy.rb
171
172
  - lib/jose/jwk/set.rb
172
173
  - lib/jose/jws.rb
173
174
  - lib/jose/jws/alg.rb