jose 1.1.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +27 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +11 -0
- data/Gemfile +9 -2
- data/LICENSE.md +22 -373
- data/README.md +2 -2
- data/Rakefile +1 -0
- data/jose.gemspec +6 -5
- data/lib/jose/jwa/curve25519_rbnacl.rb +0 -4
- data/lib/jose/jwa/ed25519_rbnacl.rb +18 -1
- data/lib/jose/jwa/pkcs1.rb +2 -2
- data/lib/jose/jwa/xchacha20poly1305.rb +61 -0
- data/lib/jose/jwa/xchacha20poly1305_rbnacl.rb +35 -0
- data/lib/jose/jwa/xchacha20poly1305_unsupported.rb +16 -0
- data/lib/jose/jwa.rb +9 -4
- data/lib/jose/jwe/alg.rb +2 -0
- data/lib/jose/jwe/alg_aes_gcm_kw.rb +1 -1
- data/lib/jose/jwe/alg_c20p_kw.rb +100 -0
- data/lib/jose/jwe/alg_xc20p_kw.rb +86 -0
- data/lib/jose/jwe/enc.rb +2 -0
- data/lib/jose/jwe/enc_c20p.rb +62 -0
- data/lib/jose/jwe/enc_xc20p.rb +49 -0
- data/lib/jose/jwe.rb +8 -0
- data/lib/jose/jwk/kty_ec.rb +20 -5
- data/lib/jose/jwk/kty_rsa.rb +46 -32
- data/lib/jose/jwk/openssh_key.rb +0 -1
- data/lib/jose/jwk/set.rb +3 -3
- data/lib/jose/jwk.rb +1 -1
- data/lib/jose/version.rb +1 -1
- data/lib/jose.rb +23 -3
- metadata +35 -15
- data/.travis.yml +0 -18
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            module JOSE::JWA::XChaCha20Poly1305_RbNaCl
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              extend self
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def __ruby__?; false; end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              def __supported__?
         | 
| 8 | 
            +
                return @supported ||= begin
         | 
| 9 | 
            +
                  begin
         | 
| 10 | 
            +
                    require 'rbnacl/libsodium'
         | 
| 11 | 
            +
                  rescue LoadError
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                  begin
         | 
| 14 | 
            +
                    require 'rbnacl'
         | 
| 15 | 
            +
                  rescue LoadError
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  !!(defined?(RbNaCl::AEAD::XChaCha20Poly1305IETF))
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def xchacha20poly1305_aead_encrypt(key, nonce, aad, plaintext)
         | 
| 22 | 
            +
                cipher = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(key)
         | 
| 23 | 
            +
                ciphertext_with_tag = cipher.encrypt(nonce, plaintext, aad)
         | 
| 24 | 
            +
                return [ciphertext_with_tag[0..-17], ciphertext_with_tag[-16..-1]]
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def xchacha20poly1305_aead_decrypt(key, nonce, aad, ciphertext, tag)
         | 
| 28 | 
            +
                cipher = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(key)
         | 
| 29 | 
            +
                ciphertext_with_tag = [ciphertext, tag].join()
         | 
| 30 | 
            +
                return cipher.decrypt(nonce, ciphertext_with_tag, aad)
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            JOSE::JWA::XChaCha20Poly1305.__register__(JOSE::JWA::XChaCha20Poly1305_RbNaCl)
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            module JOSE::JWA::XChaCha20Poly1305_Unsupported
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              extend self
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def __ruby__?; true; end
         | 
| 6 | 
            +
              def __supported__?; false; end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def xchacha20poly1305_aead_encrypt(key, nonce, aad, plaintext)
         | 
| 9 | 
            +
                raise NotImplementedError
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def xchacha20poly1305_aead_decrypt(key, nonce, aad, ciphertext, tag)
         | 
| 13 | 
            +
                raise NotImplementedError
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            end
         | 
    
        data/lib/jose/jwa.rb
    CHANGED
    
    | @@ -127,7 +127,9 @@ module JOSE | |
| 127 127 | 
             
                    'A256GCM',
         | 
| 128 128 | 
             
                    'A128CBC-HS256',
         | 
| 129 129 | 
             
                    'A192CBC-HS384',
         | 
| 130 | 
            -
                    'A256CBC-HS512'
         | 
| 130 | 
            +
                    'A256CBC-HS512',
         | 
| 131 | 
            +
                    'C20P',
         | 
| 132 | 
            +
                    'XC20P'
         | 
| 131 133 | 
             
                  ])
         | 
| 132 134 | 
             
                  jwe_alg = __jwe_alg_support_check__([
         | 
| 133 135 | 
             
                    ['A128GCMKW', :block],
         | 
| @@ -136,6 +138,7 @@ module JOSE | |
| 136 138 | 
             
                    ['A128KW', :block],
         | 
| 137 139 | 
             
                    ['A192KW', :block],
         | 
| 138 140 | 
             
                    ['A256KW', :block],
         | 
| 141 | 
            +
                    ['C20PKW', :block],
         | 
| 139 142 | 
             
                    ['ECDH-ES', :box],
         | 
| 140 143 | 
             
                    ['ECDH-ES+A128KW', :box],
         | 
| 141 144 | 
             
                    ['ECDH-ES+A192KW', :box],
         | 
| @@ -146,6 +149,7 @@ module JOSE | |
| 146 149 | 
             
                    ['RSA1_5', :rsa],
         | 
| 147 150 | 
             
                    ['RSA-OAEP', :rsa],
         | 
| 148 151 | 
             
                    ['RSA-OAEP-256', :rsa],
         | 
| 152 | 
            +
                    ['XC20PKW', :block],
         | 
| 149 153 | 
             
                    ['dir', :direct]
         | 
| 150 154 | 
             
                  ], jwe_enc)
         | 
| 151 155 | 
             
                  jwe_zip = __jwe_zip_support_check__([
         | 
| @@ -231,7 +235,7 @@ module JOSE | |
| 231 235 | 
             
                        cipher_text = recv_jwk.box_encrypt(plain_text, send_jwk).compact
         | 
| 232 236 | 
             
                        next recv_jwk.box_decrypt(cipher_text).first == plain_text
         | 
| 233 237 | 
             
                      elsif strategy == :rsa
         | 
| 234 | 
            -
                        rsa ||= JOSE::JWK.generate_key([:rsa,  | 
| 238 | 
            +
                        rsa ||= JOSE::JWK.generate_key([:rsa, 2048])
         | 
| 235 239 | 
             
                        cipher_text = rsa.block_encrypt(plain_text, { 'alg' => alg, 'enc' => enc }).compact
         | 
| 236 240 | 
             
                        next rsa.block_decrypt(cipher_text).first == plain_text
         | 
| 237 241 | 
             
                      elsif strategy == :direct
         | 
| @@ -290,7 +294,7 @@ module JOSE | |
| 290 294 | 
             
                      kty.push(key_type) if not kty_OKP_crv.empty?
         | 
| 291 295 | 
             
                    when 'RSA'
         | 
| 292 296 | 
             
                      begin
         | 
| 293 | 
            -
                        JOSE::JWK.generate_key([:rsa,  | 
| 297 | 
            +
                        JOSE::JWK.generate_key([:rsa, 1024])
         | 
| 294 298 | 
             
                        kty.push(key_type)
         | 
| 295 299 | 
             
                      rescue StandardError, NotImplementedError
         | 
| 296 300 | 
             
                        # do nothing
         | 
| @@ -314,7 +318,7 @@ module JOSE | |
| 314 318 | 
             
                    begin
         | 
| 315 319 | 
             
                      jwk = nil
         | 
| 316 320 | 
             
                      jwk ||= JOSE::JWK.generate_key([:oct, 0]).merge({ 'alg' => alg, 'use' => 'sig' }) if alg == 'none'
         | 
| 317 | 
            -
                      jwk ||= (rsa ||= JOSE::JWK.generate_key([:rsa,  | 
| 321 | 
            +
                      jwk ||= (rsa ||= JOSE::JWK.generate_key([:rsa, 2048])).merge({ 'alg' => alg, 'use' => 'sig' }) if alg.start_with?('RS') or alg.start_with?('PS')
         | 
| 318 322 | 
             
                      jwk ||= JOSE::JWS.generate_key({ 'alg' => alg })
         | 
| 319 323 | 
             
                      signed_text = jwk.sign(plain_text).compact
         | 
| 320 324 | 
             
                      next jwk.verify_strict(signed_text, [alg]).first
         | 
| @@ -337,3 +341,4 @@ require 'jose/jwa/curve25519' | |
| 337 341 | 
             
            require 'jose/jwa/curve448'
         | 
| 338 342 | 
             
            require 'jose/jwa/pkcs1'
         | 
| 339 343 | 
             
            require 'jose/jwa/pkcs7'
         | 
| 344 | 
            +
            require 'jose/jwa/xchacha20poly1305'
         | 
    
        data/lib/jose/jwe/alg.rb
    CHANGED
    
    | @@ -19,7 +19,9 @@ end | |
| 19 19 |  | 
| 20 20 | 
             
            require 'jose/jwe/alg_aes_gcm_kw'
         | 
| 21 21 | 
             
            require 'jose/jwe/alg_aes_kw'
         | 
| 22 | 
            +
            require 'jose/jwe/alg_c20p_kw'
         | 
| 22 23 | 
             
            require 'jose/jwe/alg_dir'
         | 
| 23 24 | 
             
            require 'jose/jwe/alg_ecdh_es'
         | 
| 24 25 | 
             
            require 'jose/jwe/alg_pbes2'
         | 
| 25 26 | 
             
            require 'jose/jwe/alg_rsa'
         | 
| 27 | 
            +
            require 'jose/jwe/alg_xc20p_kw'
         | 
| @@ -103,7 +103,7 @@ class JOSE::JWE::ALG_AES_GCM_KW < Struct.new(:cipher_name, :bits, :iv, :tag) | |
| 103 103 | 
             
                when 256
         | 
| 104 104 | 
             
                  'A256GCMKW'
         | 
| 105 105 | 
             
                else
         | 
| 106 | 
            -
                  raise ArgumentError, "unhandled JOSE::JWE:: | 
| 106 | 
            +
                  raise ArgumentError, "unhandled JOSE::JWE::ALG_AES_GCM_KW bits: #{bits.inspect}"
         | 
| 107 107 | 
             
                end
         | 
| 108 108 | 
             
              end
         | 
| 109 109 |  | 
| @@ -0,0 +1,100 @@ | |
| 1 | 
            +
            class JOSE::JWE::ALG_C20P_KW < Struct.new(:cipher_name, :bits, :iv, :tag)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              # JOSE::JWE callbacks
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def self.from_map(fields)
         | 
| 6 | 
            +
                bits = nil
         | 
| 7 | 
            +
                cipher_name = nil
         | 
| 8 | 
            +
                case fields['alg']
         | 
| 9 | 
            +
                when 'C20PKW'
         | 
| 10 | 
            +
                  bits = 256
         | 
| 11 | 
            +
                  cipher_name = 'chacha20-poly1305'
         | 
| 12 | 
            +
                else
         | 
| 13 | 
            +
                  raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
                iv = nil
         | 
| 16 | 
            +
                if fields.has_key?('iv')
         | 
| 17 | 
            +
                  iv = JOSE.urlsafe_decode64(fields['iv'])
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                tag = nil
         | 
| 20 | 
            +
                if fields.has_key?('tag')
         | 
| 21 | 
            +
                  tag = JOSE.urlsafe_decode64(fields['tag'])
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                return new(cipher_name, bits, iv, tag), fields.except('alg', 'iv', 'tag')
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              def to_map(fields)
         | 
| 27 | 
            +
                alg = algorithm
         | 
| 28 | 
            +
                fields = fields.put('alg', alg)
         | 
| 29 | 
            +
                if iv
         | 
| 30 | 
            +
                  fields = fields.put('iv', JOSE.urlsafe_encode64(iv))
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                if tag
         | 
| 33 | 
            +
                  fields = fields.put('tag', JOSE.urlsafe_encode64(tag))
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                return fields
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              # JOSE::JWE::ALG callbacks
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def generate_key(fields, enc)
         | 
| 41 | 
            +
                return JOSE::JWE::ALG.generate_key([:oct, bits.div(8)], algorithm, enc.algorithm)
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def key_decrypt(key, enc, encrypted_key)
         | 
| 45 | 
            +
                if iv.nil? or tag.nil?
         | 
| 46 | 
            +
                  raise ArgumentError, "missing required fields for decryption: 'iv' and 'tag'"
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
                if key.is_a?(JOSE::JWK)
         | 
| 49 | 
            +
                  key = key.kty.derive_key
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
                derived_key = key
         | 
| 52 | 
            +
                aad = ''
         | 
| 53 | 
            +
                cipher_text = encrypted_key
         | 
| 54 | 
            +
                cipher_tag = tag
         | 
| 55 | 
            +
                cipher = OpenSSL::Cipher.new(cipher_name)
         | 
| 56 | 
            +
                cipher.decrypt
         | 
| 57 | 
            +
                cipher.key = derived_key
         | 
| 58 | 
            +
                cipher.iv = iv
         | 
| 59 | 
            +
                cipher.padding = 0
         | 
| 60 | 
            +
                cipher.auth_data = aad
         | 
| 61 | 
            +
                cipher.auth_tag = cipher_tag
         | 
| 62 | 
            +
                plain_text = cipher.update(cipher_text) + cipher.final
         | 
| 63 | 
            +
                return plain_text
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              def key_encrypt(key, enc, decrypted_key)
         | 
| 67 | 
            +
                if key.is_a?(JOSE::JWK)
         | 
| 68 | 
            +
                  key = key.kty.derive_key
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
                new_alg = JOSE::JWE::ALG_C20P_KW.new(cipher_name, bits, iv || SecureRandom.random_bytes(12))
         | 
| 71 | 
            +
                derived_key = key
         | 
| 72 | 
            +
                aad = ''
         | 
| 73 | 
            +
                plain_text = decrypted_key
         | 
| 74 | 
            +
                cipher = OpenSSL::Cipher.new(new_alg.cipher_name)
         | 
| 75 | 
            +
                cipher.encrypt
         | 
| 76 | 
            +
                cipher.key = derived_key
         | 
| 77 | 
            +
                cipher.iv = new_alg.iv
         | 
| 78 | 
            +
                cipher.padding = 0
         | 
| 79 | 
            +
                cipher.auth_data = aad
         | 
| 80 | 
            +
                cipher_text = cipher.update(plain_text) + cipher.final
         | 
| 81 | 
            +
                new_alg.tag = cipher.auth_tag
         | 
| 82 | 
            +
                return cipher_text, new_alg
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              def next_cek(key, enc)
         | 
| 86 | 
            +
                return enc.next_cek, self
         | 
| 87 | 
            +
              end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
              # API functions
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              def algorithm
         | 
| 92 | 
            +
                case bits
         | 
| 93 | 
            +
                when 256
         | 
| 94 | 
            +
                  'C20PKW'
         | 
| 95 | 
            +
                else
         | 
| 96 | 
            +
                  raise ArgumentError, "unhandled JOSE::JWE::ALG_C20P_KW bits: #{bits.inspect}"
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            end
         | 
| @@ -0,0 +1,86 @@ | |
| 1 | 
            +
            class JOSE::JWE::ALG_XC20P_KW < Struct.new(:cipher_name, :bits, :iv, :tag)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              # JOSE::JWE callbacks
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def self.from_map(fields)
         | 
| 6 | 
            +
                bits = nil
         | 
| 7 | 
            +
                cipher_name = nil
         | 
| 8 | 
            +
                case fields['alg']
         | 
| 9 | 
            +
                when 'XC20PKW'
         | 
| 10 | 
            +
                  bits = 256
         | 
| 11 | 
            +
                  cipher_name = 'xchacha20-poly1305'
         | 
| 12 | 
            +
                else
         | 
| 13 | 
            +
                  raise ArgumentError, "invalid 'alg' for JWE: #{fields['alg'].inspect}"
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
                iv = nil
         | 
| 16 | 
            +
                if fields.has_key?('iv')
         | 
| 17 | 
            +
                  iv = JOSE.urlsafe_decode64(fields['iv'])
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                tag = nil
         | 
| 20 | 
            +
                if fields.has_key?('tag')
         | 
| 21 | 
            +
                  tag = JOSE.urlsafe_decode64(fields['tag'])
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                return new(cipher_name, bits, iv, tag), fields.except('alg', 'iv', 'tag')
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              def to_map(fields)
         | 
| 27 | 
            +
                alg = algorithm
         | 
| 28 | 
            +
                fields = fields.put('alg', alg)
         | 
| 29 | 
            +
                if iv
         | 
| 30 | 
            +
                  fields = fields.put('iv', JOSE.urlsafe_encode64(iv))
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                if tag
         | 
| 33 | 
            +
                  fields = fields.put('tag', JOSE.urlsafe_encode64(tag))
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                return fields
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              # JOSE::JWE::ALG callbacks
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def generate_key(fields, enc)
         | 
| 41 | 
            +
                return JOSE::JWE::ALG.generate_key([:oct, bits.div(8)], algorithm, enc.algorithm)
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              def key_decrypt(key, enc, encrypted_key)
         | 
| 45 | 
            +
                if iv.nil? or tag.nil?
         | 
| 46 | 
            +
                  raise ArgumentError, "missing required fields for decryption: 'iv' and 'tag'"
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
                if key.is_a?(JOSE::JWK)
         | 
| 49 | 
            +
                  key = key.kty.derive_key
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
                derived_key = key
         | 
| 52 | 
            +
                aad = ''
         | 
| 53 | 
            +
                cipher_text = encrypted_key
         | 
| 54 | 
            +
                cipher_tag = tag
         | 
| 55 | 
            +
                plain_text = JOSE.xchacha20poly1305_module().xchacha20poly1305_aead_decrypt(derived_key, iv, aad, cipher_text, cipher_tag)
         | 
| 56 | 
            +
                return plain_text
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              def key_encrypt(key, enc, decrypted_key)
         | 
| 60 | 
            +
                if key.is_a?(JOSE::JWK)
         | 
| 61 | 
            +
                  key = key.kty.derive_key
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
                new_alg = JOSE::JWE::ALG_XC20P_KW.new(cipher_name, bits, iv || SecureRandom.random_bytes(24))
         | 
| 64 | 
            +
                derived_key = key
         | 
| 65 | 
            +
                aad = ''
         | 
| 66 | 
            +
                plain_text = decrypted_key
         | 
| 67 | 
            +
                cipher_text, new_alg.tag = JOSE.xchacha20poly1305_module().xchacha20poly1305_aead_encrypt(key, new_alg.iv, aad, plain_text)
         | 
| 68 | 
            +
                return cipher_text, new_alg
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def next_cek(key, enc)
         | 
| 72 | 
            +
                return enc.next_cek, self
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              # API functions
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              def algorithm
         | 
| 78 | 
            +
                case bits
         | 
| 79 | 
            +
                when 256
         | 
| 80 | 
            +
                  'XC20PKW'
         | 
| 81 | 
            +
                else
         | 
| 82 | 
            +
                  raise ArgumentError, "unhandled JOSE::JWE::ALG_XC20P_KW bits: #{bits.inspect}"
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            end
         | 
    
        data/lib/jose/jwe/enc.rb
    CHANGED
    
    
| @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            class JOSE::JWE::ENC_C20P < 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 'C20P'
         | 
| 8 | 
            +
                  return new('chacha20-poly1305', 256, 32, 12), fields.delete('enc')
         | 
| 9 | 
            +
                else
         | 
| 10 | 
            +
                  raise ArgumentError, "invalid 'enc' for JWE: #{fields['enc'].inspect}"
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def to_map(fields)
         | 
| 15 | 
            +
                return fields.put('enc', algorithm)
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              # JOSE::JWE::ENC callbacks
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def algorithm
         | 
| 21 | 
            +
                case cipher_name
         | 
| 22 | 
            +
                when 'chacha20-poly1305'
         | 
| 23 | 
            +
                  return 'C20P'
         | 
| 24 | 
            +
                else
         | 
| 25 | 
            +
                  raise ArgumentError, "unhandled JOSE::JWE::ENC_C20P cipher name: #{cipher_name.inspect}"
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def block_decrypt(aad_cipher_text_cipher_tag, cek, iv)
         | 
| 30 | 
            +
                aad, cipher_text, cipher_tag = aad_cipher_text_cipher_tag
         | 
| 31 | 
            +
                cipher = OpenSSL::Cipher.new(cipher_name)
         | 
| 32 | 
            +
                cipher.decrypt
         | 
| 33 | 
            +
                cipher.key = cek
         | 
| 34 | 
            +
                cipher.iv = iv
         | 
| 35 | 
            +
                cipher.padding = 0
         | 
| 36 | 
            +
                cipher.auth_data = aad
         | 
| 37 | 
            +
                cipher.auth_tag = cipher_tag
         | 
| 38 | 
            +
                plain_text = cipher.update(cipher_text) + cipher.final
         | 
| 39 | 
            +
                return plain_text
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              def block_encrypt(aad_plain_text, cek, iv)
         | 
| 43 | 
            +
                aad, plain_text = aad_plain_text
         | 
| 44 | 
            +
                cipher = OpenSSL::Cipher.new(cipher_name)
         | 
| 45 | 
            +
                cipher.encrypt
         | 
| 46 | 
            +
                cipher.key = cek
         | 
| 47 | 
            +
                cipher.iv = iv
         | 
| 48 | 
            +
                cipher.padding = 0
         | 
| 49 | 
            +
                cipher.auth_data = aad
         | 
| 50 | 
            +
                cipher_text = cipher.update(plain_text) + cipher.final
         | 
| 51 | 
            +
                return cipher_text, cipher.auth_tag
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              def next_cek
         | 
| 55 | 
            +
                return SecureRandom.random_bytes(cek_len)
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              def next_iv
         | 
| 59 | 
            +
                return SecureRandom.random_bytes(iv_len)
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            end
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            class JOSE::JWE::ENC_XC20P < 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 'XC20P'
         | 
| 8 | 
            +
                  return new('xchacha20-poly1305', 256, 32, 24), fields.delete('enc')
         | 
| 9 | 
            +
                else
         | 
| 10 | 
            +
                  raise ArgumentError, "invalid 'enc' for JWE: #{fields['enc'].inspect}"
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def to_map(fields)
         | 
| 15 | 
            +
                return fields.put('enc', algorithm)
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              # JOSE::JWE::ENC callbacks
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def algorithm
         | 
| 21 | 
            +
                case cipher_name
         | 
| 22 | 
            +
                when 'xchacha20-poly1305'
         | 
| 23 | 
            +
                  return 'XC20P'
         | 
| 24 | 
            +
                else
         | 
| 25 | 
            +
                  raise ArgumentError, "unhandled JOSE::JWE::ENC_XC20P cipher name: #{cipher_name.inspect}"
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def block_decrypt(aad_cipher_text_cipher_tag, cek, iv)
         | 
| 30 | 
            +
                aad, cipher_text, cipher_tag = aad_cipher_text_cipher_tag
         | 
| 31 | 
            +
                plain_text = JOSE.xchacha20poly1305_module().xchacha20poly1305_aead_decrypt(cek, iv, aad, cipher_text, cipher_tag)
         | 
| 32 | 
            +
                return plain_text
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              def block_encrypt(aad_plain_text, cek, iv)
         | 
| 36 | 
            +
                aad, plain_text = aad_plain_text
         | 
| 37 | 
            +
                cipher_text, cipher_tag = JOSE.xchacha20poly1305_module().xchacha20poly1305_aead_encrypt(cek, iv, aad, plain_text)
         | 
| 38 | 
            +
                return cipher_text, cipher_tag
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              def next_cek
         | 
| 42 | 
            +
                return SecureRandom.random_bytes(cek_len)
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def next_iv
         | 
| 46 | 
            +
                return SecureRandom.random_bytes(iv_len)
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            end
         | 
    
        data/lib/jose/jwe.rb
    CHANGED
    
    | @@ -1076,6 +1076,8 @@ module JOSE | |
| 1076 1076 | 
             
                      JOSE::JWE::ALG_AES_KW
         | 
| 1077 1077 | 
             
                    when 'A128GCMKW', 'A192GCMKW', 'A256GCMKW'
         | 
| 1078 1078 | 
             
                      JOSE::JWE::ALG_AES_GCM_KW
         | 
| 1079 | 
            +
                    when 'C20PKW'
         | 
| 1080 | 
            +
                      JOSE::JWE::ALG_C20P_KW
         | 
| 1079 1081 | 
             
                    when 'dir'
         | 
| 1080 1082 | 
             
                      JOSE::JWE::ALG_dir
         | 
| 1081 1083 | 
             
                    when 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'
         | 
| @@ -1084,6 +1086,8 @@ module JOSE | |
| 1084 1086 | 
             
                      JOSE::JWE::ALG_PBES2
         | 
| 1085 1087 | 
             
                    when 'RSA1_5', 'RSA-OAEP', 'RSA-OAEP-256'
         | 
| 1086 1088 | 
             
                      JOSE::JWE::ALG_RSA
         | 
| 1089 | 
            +
                    when 'XC20PKW'
         | 
| 1090 | 
            +
                      JOSE::JWE::ALG_XC20P_KW
         | 
| 1087 1091 | 
             
                    else
         | 
| 1088 1092 | 
             
                      raise ArgumentError, "unknown 'alg': #{jwe.fields['alg'].inspect}"
         | 
| 1089 1093 | 
             
                    end
         | 
| @@ -1095,6 +1099,10 @@ module JOSE | |
| 1095 1099 | 
             
                      JOSE::JWE::ENC_AES_CBC_HMAC
         | 
| 1096 1100 | 
             
                    when 'A128GCM', 'A192GCM', 'A256GCM'
         | 
| 1097 1101 | 
             
                      JOSE::JWE::ENC_AES_GCM
         | 
| 1102 | 
            +
                    when 'C20P'
         | 
| 1103 | 
            +
                      JOSE::JWE::ENC_C20P
         | 
| 1104 | 
            +
                    when 'XC20P'
         | 
| 1105 | 
            +
                      JOSE::JWE::ENC_XC20P
         | 
| 1098 1106 | 
             
                    else
         | 
| 1099 1107 | 
             
                      raise ArgumentError, "unknown 'enc': #{jwe.fields['enc'].inspect}"
         | 
| 1100 1108 | 
             
                    end
         | 
    
        data/lib/jose/jwk/kty_ec.rb
    CHANGED
    
    | @@ -14,16 +14,31 @@ class JOSE::JWK::KTY_EC < Struct.new(:key) | |
| 14 14 | 
             
                  else
         | 
| 15 15 | 
             
                    raise ArgumentError, "invalid 'EC' JWK"
         | 
| 16 16 | 
             
                  end
         | 
| 17 | 
            -
             | 
| 17 | 
            +
             | 
| 18 18 | 
             
                  x = JOSE.urlsafe_decode64(fields['x'])
         | 
| 19 19 | 
             
                  y = JOSE.urlsafe_decode64(fields['y'])
         | 
| 20 | 
            -
                   | 
| 20 | 
            +
                  point    = OpenSSL::PKey::EC::Point.new(
         | 
| 21 21 | 
             
                    OpenSSL::PKey::EC::Group.new(crv),
         | 
| 22 22 | 
             
                    OpenSSL::BN.new([0x04, x, y].pack('Ca*a*'), 2)
         | 
| 23 23 | 
             
                  )
         | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 24 | 
            +
             | 
| 25 | 
            +
                  sequence = if fields['d'].is_a?(String)
         | 
| 26 | 
            +
                    OpenSSL::ASN1::Sequence([
         | 
| 27 | 
            +
                      OpenSSL::ASN1::Integer(1),
         | 
| 28 | 
            +
                      OpenSSL::ASN1::OctetString(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2).to_s(2)),
         | 
| 29 | 
            +
                      OpenSSL::ASN1::ObjectId(crv, 0, :EXPLICIT),
         | 
| 30 | 
            +
                      OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT)
         | 
| 31 | 
            +
                    ])
         | 
| 32 | 
            +
                  else
         | 
| 33 | 
            +
                    OpenSSL::ASN1::Sequence([
         | 
| 34 | 
            +
                      OpenSSL::ASN1::Sequence([
         | 
| 35 | 
            +
                        OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
         | 
| 36 | 
            +
                        OpenSSL::ASN1::ObjectId(crv)
         | 
| 37 | 
            +
                      ]),
         | 
| 38 | 
            +
                      OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
         | 
| 39 | 
            +
                    ])
         | 
| 26 40 | 
             
                  end
         | 
| 41 | 
            +
                  ec = OpenSSL::PKey::EC.new(sequence.to_der)
         | 
| 27 42 | 
             
                  return JOSE::JWK::KTY_EC.new(JOSE::JWK::PKeyProxy.new(ec)), fields.except('kty', 'crv', 'd', 'x', 'y')
         | 
| 28 43 | 
             
                else
         | 
| 29 44 | 
             
                  raise ArgumentError, "invalid 'EC' JWK"
         | 
| @@ -132,7 +147,7 @@ class JOSE::JWK::KTY_EC < Struct.new(:key) | |
| 132 147 | 
             
                  curve_name
         | 
| 133 148 | 
             
                end
         | 
| 134 149 | 
             
                if curve_name.is_a?(String)
         | 
| 135 | 
            -
                  return from_key(OpenSSL::PKey::EC. | 
| 150 | 
            +
                  return from_key(OpenSSL::PKey::EC.generate(curve_name))
         | 
| 136 151 | 
             
                else
         | 
| 137 152 | 
             
                  raise ArgumentError, "'curve_name' must be a String"
         | 
| 138 153 | 
             
                end
         | 
    
        data/lib/jose/jwk/kty_rsa.rb
    CHANGED
    
    | @@ -8,36 +8,32 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key) | |
| 8 8 | 
             
                    raise ArgumentError, "multi-prime RSA keys are not supported"
         | 
| 9 9 | 
             
                  elsif fields['d'].is_a?(String)
         | 
| 10 10 | 
             
                    if fields['dp'].is_a?(String) and fields['dq'].is_a?(String) and fields['p'].is_a?(String) and fields['q'].is_a?(String) and fields['qi'].is_a?(String)
         | 
| 11 | 
            -
                       | 
| 12 | 
            -
             | 
| 13 | 
            -
                        OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2),
         | 
| 14 | 
            -
                        OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2),
         | 
| 15 | 
            -
                        OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
         | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
                        OpenSSL::BN.new(JOSE.urlsafe_decode64(fields[' | 
| 19 | 
            -
                        OpenSSL::BN.new(JOSE.urlsafe_decode64(fields[' | 
| 20 | 
            -
             | 
| 21 | 
            -
                       | 
| 22 | 
            -
             | 
| 23 | 
            -
                        OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dq']), 2),
         | 
| 24 | 
            -
                        OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['qi']), 2)
         | 
| 25 | 
            -
                      )
         | 
| 11 | 
            +
                      asn1_sequence = OpenSSL::ASN1::Sequence.new([
         | 
| 12 | 
            +
                        OpenSSL::ASN1::Integer.new(0),
         | 
| 13 | 
            +
                        OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)),
         | 
| 14 | 
            +
                        OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2)),
         | 
| 15 | 
            +
                        OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)),
         | 
| 16 | 
            +
                        OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['p']), 2)),
         | 
| 17 | 
            +
                        OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['q']), 2)),
         | 
| 18 | 
            +
                        OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dp']), 2)),
         | 
| 19 | 
            +
                        OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['dq']), 2)),
         | 
| 20 | 
            +
                        OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['qi']), 2))
         | 
| 21 | 
            +
                      ])
         | 
| 22 | 
            +
                      rsa = OpenSSL::PKey::RSA.new(asn1_sequence.to_der)
         | 
| 26 23 | 
             
                      return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(rsa)), fields.except('kty', 'd', 'dp', 'dq', 'e', 'n', 'p', 'q', 'qi')
         | 
| 27 24 | 
             
                    else
         | 
| 28 | 
            -
                      d | 
| 29 | 
            -
                      e | 
| 30 | 
            -
                      n | 
| 25 | 
            +
                      d = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['d']), 2)
         | 
| 26 | 
            +
                      e = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2)
         | 
| 27 | 
            +
                      n = OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)
         | 
| 31 28 | 
             
                      rsa = convert_sfm_to_crt(d, e, n)
         | 
| 32 29 | 
             
                      return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(rsa)), fields.except('kty', 'd', 'dp', 'dq', 'e', 'n', 'p', 'q', 'qi')
         | 
| 33 30 | 
             
                    end
         | 
| 34 31 | 
             
                  else
         | 
| 35 | 
            -
                     | 
| 36 | 
            -
             | 
| 37 | 
            -
                      OpenSSL::BN.new(JOSE.urlsafe_decode64(fields[' | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
                    )
         | 
| 32 | 
            +
                    asn1_sequence = OpenSSL::ASN1::Sequence.new([
         | 
| 33 | 
            +
                      OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['n']), 2)),
         | 
| 34 | 
            +
                      OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(JOSE.urlsafe_decode64(fields['e']), 2))
         | 
| 35 | 
            +
                    ])
         | 
| 36 | 
            +
                    rsa = OpenSSL::PKey::RSA.new(OpenSSL::PKey::RSA.new(asn1_sequence.to_der))
         | 
| 41 37 | 
             
                    return JOSE::JWK::KTY_RSA.new(JOSE::JWK::PKeyProxy.new(rsa)), fields.except('kty', 'e', 'n')
         | 
| 42 38 | 
             
                  end
         | 
| 43 39 | 
             
                else
         | 
| @@ -140,7 +136,8 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key) | |
| 140 136 | 
             
                  end
         | 
| 141 137 | 
             
                end
         | 
| 142 138 | 
             
                if modulus_size.is_a?(Integer) and (exponent_size.nil? or exponent_size.is_a?(Integer))
         | 
| 143 | 
            -
                  return from_key(OpenSSL::PKey::RSA.generate(modulus_size | 
| 139 | 
            +
                  return from_key(OpenSSL::PKey::RSA.generate(modulus_size)) if exponent_size.nil?
         | 
| 140 | 
            +
                  return from_key(OpenSSL::PKey::RSA.generate(modulus_size, exponent_size)) if exponent_size.is_a?(Integer)
         | 
| 144 141 | 
             
                else
         | 
| 145 142 | 
             
                  raise ArgumentError, "'modulus_size' must be an Integer and 'exponent_size' must be nil or an Integer"
         | 
| 146 143 | 
             
                end
         | 
| @@ -160,7 +157,12 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key) | |
| 160 157 | 
             
                when :rsa_pkcs1_padding
         | 
| 161 158 | 
             
                  return key.sign(digest_type.new, message)
         | 
| 162 159 | 
             
                when :rsa_pkcs1_pss_padding
         | 
| 163 | 
            -
                   | 
| 160 | 
            +
                  if key.respond_to?(:sign_pss)
         | 
| 161 | 
            +
                    digest_name = digest_type.new.name
         | 
| 162 | 
            +
                    return key.sign_pss(digest_name, message, salt_length: :digest, mgf1_hash: digest_name)
         | 
| 163 | 
            +
                  else
         | 
| 164 | 
            +
                    return JOSE::JWA::PKCS1.rsassa_pss_sign(digest_type, message, key)
         | 
| 165 | 
            +
                  end
         | 
| 164 166 | 
             
                else
         | 
| 165 167 | 
             
                  raise ArgumentError, "unsupported RSA padding: #{padding.inspect}"
         | 
| 166 168 | 
             
                end
         | 
| @@ -189,7 +191,12 @@ class JOSE::JWK::KTY_RSA < Struct.new(:key) | |
| 189 191 | 
             
                when :rsa_pkcs1_padding
         | 
| 190 192 | 
             
                  return key.verify(digest_type.new, signature, message)
         | 
| 191 193 | 
             
                when :rsa_pkcs1_pss_padding
         | 
| 192 | 
            -
                   | 
| 194 | 
            +
                  if key.respond_to?(:verify_pss)
         | 
| 195 | 
            +
                    digest_name = digest_type.new.name
         | 
| 196 | 
            +
                    return key.verify_pss(digest_name, signature, message, salt_length: :digest, mgf1_hash: digest_name)
         | 
| 197 | 
            +
                  else
         | 
| 198 | 
            +
                    return JOSE::JWA::PKCS1.rsassa_pss_verify(digest_type, message, signature, key)
         | 
| 199 | 
            +
                  end
         | 
| 193 200 | 
             
                else
         | 
| 194 201 | 
             
                  raise ArgumentError, "unsupported RSA padding: #{padding.inspect}"
         | 
| 195 202 | 
             
                end
         | 
| @@ -230,11 +237,18 @@ private | |
| 230 237 | 
             
                dq = d % (q - 1)
         | 
| 231 238 | 
             
                qi = q.mod_inverse(p)
         | 
| 232 239 |  | 
| 233 | 
            -
                 | 
| 234 | 
            -
             | 
| 235 | 
            -
             | 
| 236 | 
            -
             | 
| 237 | 
            -
             | 
| 240 | 
            +
                asn1_sequence = OpenSSL::ASN1::Sequence.new([
         | 
| 241 | 
            +
                  OpenSSL::ASN1::Integer.new(0),
         | 
| 242 | 
            +
                  OpenSSL::ASN1::Integer.new(n),
         | 
| 243 | 
            +
                  OpenSSL::ASN1::Integer.new(e),
         | 
| 244 | 
            +
                  OpenSSL::ASN1::Integer.new(d),
         | 
| 245 | 
            +
                  OpenSSL::ASN1::Integer.new(p),
         | 
| 246 | 
            +
                  OpenSSL::ASN1::Integer.new(q),
         | 
| 247 | 
            +
                  OpenSSL::ASN1::Integer.new(dp),
         | 
| 248 | 
            +
                  OpenSSL::ASN1::Integer.new(dq),
         | 
| 249 | 
            +
                  OpenSSL::ASN1::Integer.new(qi)
         | 
| 250 | 
            +
                ])
         | 
| 251 | 
            +
                rsa = OpenSSL::PKey::RSA.new(asn1_sequence.to_der)
         | 
| 238 252 | 
             
                return rsa
         | 
| 239 253 | 
             
              end
         | 
| 240 254 |  | 
    
        data/lib/jose/jwk/openssh_key.rb
    CHANGED
    
    
    
        data/lib/jose/jwk/set.rb
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 | 
            -
            require ' | 
| 1 | 
            +
            require 'immutable/vector'
         | 
| 2 2 |  | 
| 3 | 
            -
            # Immutable Set structure based on ` | 
| 4 | 
            -
            class JOSE::JWK::Set <  | 
| 3 | 
            +
            # Immutable Set structure based on `Immutable::Vector`.
         | 
| 4 | 
            +
            class JOSE::JWK::Set < Immutable::Vector
         | 
| 5 5 |  | 
| 6 6 | 
             
              def self.from_map(fields)
         | 
| 7 7 | 
             
                if fields['keys'].is_a?(Array)
         | 
    
        data/lib/jose/jwk.rb
    CHANGED
    
    | @@ -481,7 +481,7 @@ module JOSE | |
| 481 481 | 
             
                # Converts a private {JOSE::JWK JOSE::JWK} into a public {JOSE::JWK JOSE::JWK}.
         | 
| 482 482 | 
             
                #
         | 
| 483 483 | 
             
                #     !!!ruby
         | 
| 484 | 
            -
                #     jwk_rsa = JOSE::JWK.generate_key([:rsa,  | 
| 484 | 
            +
                #     jwk_rsa = JOSE::JWK.generate_key([:rsa, 1024]).to_map
         | 
| 485 485 | 
             
                #     # => JOSE::Map[
         | 
| 486 486 | 
             
                #     #  "dq" => "Iv_BghpjRyv8hk4AgsX_3w",
         | 
| 487 487 | 
             
                #     #  "e" => "AQAB",
         | 
    
        data/lib/jose/version.rb
    CHANGED