jose 0.3.1 → 1.0.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: 97b12e5771a9533cfe90cf343ad9829fea08959e
4
- data.tar.gz: 36896efd3b895906a16ff8f751449fba9159dc3d
3
+ metadata.gz: 8804406a3e47d37b89da4315eb021d33d447ecf7
4
+ data.tar.gz: 9409c19e851ef2036b1fc843eeeaa3667c64ed40
5
5
  SHA512:
6
- metadata.gz: dc6941ef61ef94954fe118082d564936fc59b13c53f6ab4b09dd7598355b4572b9dff093fe57e84febf842817c88e454b7d34c1551028ee687fbda36c439697c
7
- data.tar.gz: 919c7f009f80b2e22e82083c60f93c39571800b3069d9d86372c7ca9b12d8cb6b18d3f0c322c2dc812fdeee411dd2d42e36956803cf2405d68ffe169514859fe
6
+ metadata.gz: ade14cfd65ca8cab5f24b5329448db0e0ee19d04fa71ec43fda67300197563c361c20f2229dba79f0b6b4b01cf9440482cae460324ce069fa782c66e3430b284
7
+ data.tar.gz: 391d322825bf7905f41800ae0ed77f7d29b0c27018ac06e65bcf3d04288fe579191a4278beac44e5a2f09e2e9350c22da4cab0189c126fef258888d4e1f53516
@@ -3,6 +3,11 @@ language: ruby
3
3
  sudo: required
4
4
  dist: trusty
5
5
 
6
+ env:
7
+ global:
8
+ - JOSE_CRYPTO_FALLBACK=true
9
+ - RUBYOPT="-W0"
10
+
6
11
  rvm:
7
12
  - 2.3.1
8
13
 
@@ -0,0 +1,4 @@
1
+ --markup markdown
2
+ -
3
+ docs/*.md
4
+ *.md
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0 (2016-05-07)
4
+
5
+ * Enhancements
6
+ * [Documentation!](http://www.rubydoc.info/gems/jose) Many thanks to [@soumyaray](https://github.com/soumyaray) for the motivation to improve documentation.
7
+ * Support for OpenSSH octet key pairs (for Ed25519).
8
+ * Better key management behavior associated with ECDH-ES algorithms.
9
+
3
10
  ## 0.3.1 (2016-05-05)
4
11
 
5
12
  * Fixes
File without changes
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # JOSE
2
2
 
3
- [![Build Status](https://travis-ci.org/potatosalad/ruby-jose.png?branch=master)](https://travis-ci.org/potatosalad/ruby-jose) [![Gem](https://img.shields.io/gem/v/jose.svg?maxAge=2592000)](https://rubygems.org/gems/jose)
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)
4
4
 
5
5
  JSON Object Signing and Encryption (JOSE) for Ruby.
6
6
 
@@ -24,7 +24,7 @@ Or install it yourself as:
24
24
 
25
25
  ## Usage
26
26
 
27
- Better documentation is in progress, but the [erlang-jose documentation](https://hexdocs.pm/jose/) can provide an idea of the functionality available in this gem.
27
+ Better documentation is in progress, but here are a few resources to get started. First, a simple example of key generation and message signing:
28
28
 
29
29
  ```ruby
30
30
  # Let's use our secret key "symmetric key" for use with
@@ -44,6 +44,14 @@ verified, message, = jwk.verify(signed)
44
44
  # => [true, "test"]
45
45
  ```
46
46
 
47
+ More details and examples:
48
+ - [Getting Started](http://www.rubydoc.info/gems/jose/file/docs/GettingStarted.md)
49
+ - [Key Generation](http://www.rubydoc.info/gems/jose/file/docs/KeyGeneration.md)
50
+ - [Encryption Algorithms](http://www.rubydoc.info/gems/jose/file/docs/EncryptionAlgorithms.md)
51
+ - [Signature Algorithms](http://www.rubydoc.info/gems/jose/file/docs/SignatureAlgorithms.md)
52
+
53
+ Finally, the [erlang-jose documentation](https://hexdocs.pm/jose/) can provide more ideas of the functionality available in this gem.
54
+
47
55
  ## Development
48
56
 
49
57
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -57,4 +65,3 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/potato
57
65
  ## License
58
66
 
59
67
  The gem is available as open source under the terms of the [MPL-2.0 License](http://opensource.org/licenses/MPL-2.0).
60
-
@@ -0,0 +1,55 @@
1
+ # @title Encryption Algorithms
2
+
3
+ # Encryption Algorithms
4
+
5
+ The basic parameters for a {JOSE::JWE JOSE::JWE} header are:
6
+
7
+ - `"alg"` **(required)** - Key Management Algorithm used to encrypt or determine the value of the Content Encryption Key.
8
+ - `"enc"` **(required)** - Encryption Algorithm used to perform authenticated encryption on the plain text using the Content Encryption Key.
9
+ - `"zip"` *(optional)* - Compression Algorithm applied to the plaintext before encryption, if any.
10
+
11
+ See [RFC 7516](https://tools.ietf.org/html/rfc7516#section-4.1) for more information about other header parameters.
12
+
13
+ ### `alg` Header Parameter
14
+
15
+ Here are the supported options for the `alg` parameter, grouped by similar funcionality:
16
+
17
+ - Single Asymmetric Public/Private Key Pair
18
+ - [`RSA1_5`](http://www.rubydoc.info/gems/jose/JOSE/JWE#RSA-group)
19
+ - [`RSA-OAEP`](http://www.rubydoc.info/gems/jose/JOSE/JWE#RSA-group)
20
+ - [`RSA-OAEP-256`](http://www.rubydoc.info/gems/jose/JOSE/JWE#RSA-group)
21
+ - Two Asymmetric Public/Private Key Pairs with Key Agreement
22
+ - [`ECDH-ES`](http://www.rubydoc.info/gems/jose/JOSE/JWE#ECDH-ES-group)
23
+ - [`ECDH-ES+A128KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#ECDH-ES-group)
24
+ - [`ECDH-ES+A192KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#ECDH-ES-group)
25
+ - [`ECDH-ES+A256KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#ECDH-ES-group)
26
+ - Symmetric Password Based Key Derivation
27
+ - [`PBES2-HS256+A128KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#PBES2-group)
28
+ - [`PBES2-HS384+A192KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#PBES2-group)
29
+ - [`PBES2-HS512+A256KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#PBES2-group)
30
+ - Symmetric Key Wrap
31
+ - [`A128GCMKW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESGCMKW-group)
32
+ - [`A192GCMKW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESGCMKW-group)
33
+ - [`A256GCMKW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESGCMKW-group)
34
+ - [`A128KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESKW-group)
35
+ - [`A192KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESKW-group)
36
+ - [`A256KW`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESKW-group)
37
+ - Symmetric Direct Key (known to both sides)
38
+ - [`dir`](http://www.rubydoc.info/gems/jose/JOSE/JWE#direct-group)
39
+
40
+ ### `enc` Header Parameter
41
+
42
+ Here are the options for the `enc` parameter:
43
+
44
+ - [`A128CBC-HS256`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESCBC-group)
45
+ - [`A192CBC-HS384`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESCBC-group)
46
+ - [`A256CBC-HS512`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESCBC-group)
47
+ - [`A128GCM`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESGCM-group)
48
+ - [`A192GCM`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESGCM-group)
49
+ - [`A256GCM`](http://www.rubydoc.info/gems/jose/JOSE/JWE#AESGCM-group)
50
+
51
+ ### `zip` Header Parameter
52
+
53
+ Here are the options for the `zip` parameter:
54
+
55
+ - [`DEF`](http://www.rubydoc.info/gems/jose/JOSE/JWE#DEF-group)
@@ -0,0 +1,137 @@
1
+ # @title Getting Started
2
+
3
+ # Getting Started
4
+
5
+ JOSE stands for JSON Object Signing and Encryption which is a is a set of
6
+ standards established by the [JOSE Working Group](https://datatracker.ietf.org/wg/jose).
7
+
8
+ JOSE is split into 5 main components:
9
+
10
+ * {JOSE::JWA JOSE::JWA} - JSON Web Algorithms (JWA) {https://tools.ietf.org/html/rfc7518 RFC 7518}
11
+ * {JOSE::JWE JOSE::JWE} - JSON Web Encryption (JWE) {https://tools.ietf.org/html/rfc7516 RFC 7516}
12
+ * {JOSE::JWK JOSE::JWK} - JSON Web Key (JWK) {https://tools.ietf.org/html/rfc7517 RFC 7517}
13
+ * {JOSE::JWS JOSE::JWS} - JSON Web Signature (JWS) {https://tools.ietf.org/html/rfc7515 RFC 7515}
14
+ * {JOSE::JWT JOSE::JWT} - JSON Web Token (JWT) {https://tools.ietf.org/html/rfc7519 RFC 7519}
15
+
16
+ Additional specifications and drafts implemented:
17
+
18
+ * JSON Web Key (JWK) Thumbprint [RFC 7638](https://tools.ietf.org/html/rfc7638)
19
+ * JWS Unencoded Payload Option [draft-ietf-jose-jws-signing-input-options-04](https://tools.ietf.org/html/draft-ietf-jose-jws-signing-input-options-04)
20
+
21
+ ## More Information
22
+
23
+ * {file:docs/KeyGeneration.md}
24
+ * {file:docs/EncryptionAlgorithms.md}
25
+ * {file:docs/SignatureAlgorithms.md}
26
+
27
+ ## Usage Examples
28
+
29
+ The simplest combination might be `{"alg":"dir","enc":"A128GCM"}` which requires a 128-bit (or 16-byte) key that must be fully known by both parties.
30
+
31
+ ```ruby
32
+ # Alice wants to send Bob an encrypted message.
33
+ # Both Alice and Bob know about the 128-bit key "this is 16 bytes".
34
+
35
+ # Alice encrypts the plain_text and sends cipher_text to Bob.
36
+ plain_text = "Hello, World!"
37
+ jwk = JOSE::JWK.from_oct("this is 16 bytes")
38
+ cipher_text = jwk.block_encrypt(plain_text, {"alg" => "dir", "enc" => "A128GCM"}).compact
39
+ # => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..oSOfVgfW5dPo4Mwx.x3N6TNI0pTYlBVHiSA.Uu_kROoBRWL0Hb0BH150Zg"
40
+
41
+ # Bob decrypts the cipher_text using the shared secret key.
42
+ cipher_text = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..oSOfVgfW5dPo4Mwx.x3N6TNI0pTYlBVHiSA.Uu_kROoBRWL0Hb0BH150Zg"
43
+ jwk = JOSE::JWK.from_oct("this is 16 bytes")
44
+ plain_text, = jwk.block_decrypt(cipher_text)
45
+ # => "Hello, World!"
46
+ ```
47
+
48
+ A more complex combination might be `{"alg":"PBES2-HS256+A128KW","enc":"A128GCM","p2c":4096}` which uses a passphrase of any length and generates the Content Encryption Key of the correct length based on that passphrase. The `p2c` in the JSON specifies that 4096 rounds will be done which slows down any brute force attacks trying to determine the passphrase.
49
+
50
+ ```ruby
51
+ # Alice wants to send Bob an encrypted message.
52
+ # Both Alice and Bob know about the passphrase "alice and bob's secret".
53
+
54
+ # Alice encrypts the plain_text and sends cipher_text to Bob.
55
+ plain_text = "Hello, World!"
56
+ jwk = JOSE::JWK.from_oct("alice and bob's secret")
57
+ cipher_text = jwk.block_encrypt(plain_text, {"alg" => "PBES2-HS256+A128KW", "enc" => "A128GCM", "p2c" => 4096}).compact
58
+ # => "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjo0MDk2LCJwMnMiOiJfZEllWDFGX29zUSJ9.B8vGlGGJBNSeGiaOKFJq3MXqhvK5fihL.WUt7m0TldTqW4eNb.wyjPCvfglCovqEd7xw.qZFI-qEV9ACh142xs3MozA"
59
+
60
+ # Bob decrypts the cipher_text using the shared passphrase.
61
+ cipher_text = "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjo0MDk2LCJwMnMiOiJfZEllWDFGX29zUSJ9.B8vGlGGJBNSeGiaOKFJq3MXqhvK5fihL.WUt7m0TldTqW4eNb.wyjPCvfglCovqEd7xw.qZFI-qEV9ACh142xs3MozA"
62
+ jwk = JOSE::JWK.from_oct("alice and bob's secret")
63
+ plain_text, = jwk.block_decrypt(cipher_text)
64
+ # => "Hello, World!"
65
+ ```
66
+
67
+ An even more complex combination might be `{"alg":"ECDH-ES","enc":"A128GCM"}` which requires two sets of keypairs. The sender (in our case Alice) uses their secret key and the public key of the receiver (Bob) to compute a shared key. The public key of the sender is embedded in the resulting encrypted message which the receiver then uses with their own secret key to decrypt the message.
68
+
69
+ ```ruby
70
+ # Let's setup the keys that will be used below (use JOSE::JWK.from_binary(...) to load the string version)
71
+ ## Alice
72
+ alice_secret = JOSE::JWK.generate_key([:okp, :X25519])
73
+ # => "{\"crv\":\"X25519\",\"d\":\"0Pygq6jZVuWM4lPIhmCCbxtLIsWVzfnK5aM65PC1iX0\",\"kty\":\"OKP\",\"x\":\"uZGRsHIG33ebtKoIBG2WL4_TC_GTZtluSFuOmEPCngc\"}"
74
+ alice_public = alice_secret.to_public
75
+ # => "{\"crv\":\"X25519\",\"kty\":\"OKP\",\"x\":\"uZGRsHIG33ebtKoIBG2WL4_TC_GTZtluSFuOmEPCngc\"}"
76
+ ## Bob
77
+ bob_secret = JOSE::JWK.generate_key([:okp, :X25519])
78
+ # => "{\"crv\":\"X25519\",\"d\":\"CMVqzIl-pHk0vuAUxhsZccYSLHpJfhRYvz3rTu6R8kc\",\"kty\":\"OKP\",\"x\":\"U-ckTk7roeu-9peZjdhZUIm9yJHtBrrkBJojCpUz5Cs\"}"
79
+ bob_public = bob_secret.to_public
80
+ # => "{\"crv\":\"X25519\",\"kty\":\"OKP\",\"x\":\"U-ckTk7roeu-9peZjdhZUIm9yJHtBrrkBJojCpUz5Cs\"}"
81
+
82
+ # Alice wants to send Bob an encrypted message.
83
+ # Bob first sends Alice his public key (bob_public above).
84
+
85
+ # Alice loads Bob's public key and encrypts the plain_text using her secret key.
86
+ # She then sends the resulting cipher_text to Bob.
87
+ plain_text = "Hello, World!"
88
+ bob_public = JOSE::JWK.from_binary("{\"crv\":\"X25519\",\"kty\":\"OKP\",\"x\":\"U-ckTk7roeu-9peZjdhZUIm9yJHtBrrkBJojCpUz5Cs\"}")
89
+ cipher_text = bob_public.box_encrypt(plain_text, alice_secret).compact
90
+ # => "eyJhbGciOiJFQ0RILUVTIiwiYXB1IjoiZTdwaGd3YU92NXVIVlFkOFJIRFRxcXpMYjZ6T0Nlb1oteXJLRTVmcTM2ayIsImFwdiI6IjY5U1Y3VWo0MWstMEhrcU1GOXVMaEk5Ty14TXZ0UlJ0bU0tbmxJV1RyV2MiLCJlbmMiOiJBMTI4R0NNIiwiZXBrIjp7ImNydiI6IlgyNTUxOSIsImt0eSI6Ik9LUCIsIngiOiJ1WkdSc0hJRzMzZWJ0S29JQkcyV0w0X1RDX0dUWnRsdVNGdU9tRVBDbmdjIn19..EeHOlLmlZocrf0Iz.O2kmN_-6m2YEWiR8XA.CTpSFJKy1GRLU3OoNj_AvA"
91
+
92
+ # Bob decrypts the cipher_text using his secret key.
93
+ cipher_text = "eyJhbGciOiJFQ0RILUVTIiwiYXB1IjoiZTdwaGd3YU92NXVIVlFkOFJIRFRxcXpMYjZ6T0Nlb1oteXJLRTVmcTM2ayIsImFwdiI6IjY5U1Y3VWo0MWstMEhrcU1GOXVMaEk5Ty14TXZ0UlJ0bU0tbmxJV1RyV2MiLCJlbmMiOiJBMTI4R0NNIiwiZXBrIjp7ImNydiI6IlgyNTUxOSIsImt0eSI6Ik9LUCIsIngiOiJ1WkdSc0hJRzMzZWJ0S29JQkcyV0w0X1RDX0dUWnRsdVNGdU9tRVBDbmdjIn19..EeHOlLmlZocrf0Iz.O2kmN_-6m2YEWiR8XA.CTpSFJKy1GRLU3OoNj_AvA"
94
+ plain_text, = bob_secret.box_decrypt(cipher_text)
95
+ # => "Hello, World!"
96
+ ```
97
+
98
+ Here is an example of using X25519 and Ed25519 key pairs to encrypt and then sign a message.
99
+
100
+ ```ruby
101
+ # Alice's Signing Key Pair
102
+ alice_ed25519_secret = JOSE::JWS.generate_key({"alg" => "Ed25519"})
103
+ # => "{\"alg\":\"Ed25519\",\"crv\":\"Ed25519\",\"d\":\"CNnP7HYI-plw66s8GWOJwFCWWCZO1udseqEiyGxJGyk\",\"kty\":\"OKP\",\"use\":\"sig\",\"x\":\"atNiugZnSNxjmd5TM4eXg-aszq7Xarmpsuxrt2yIkUc\"}"
104
+ alice_ed25519_public = alice_ed25519_secret.to_public
105
+ # => "{\"alg\":\"Ed25519\",\"crv\":\"Ed25519\",\"kty\":\"OKP\",\"use\":\"sig\",\"x\":\"atNiugZnSNxjmd5TM4eXg-aszq7Xarmpsuxrt2yIkUc\"}"
106
+
107
+ # Bob's Key Agreement Key Pair
108
+ bob_x25519_secret = JOSE::JWK.generate_key([:okp, :X25519])
109
+ # => "{\"crv\":\"X25519\",\"d\":\"CMVqzIl-pHk0vuAUxhsZccYSLHpJfhRYvz3rTu6R8kc\",\"kty\":\"OKP\",\"x\":\"U-ckTk7roeu-9peZjdhZUIm9yJHtBrrkBJojCpUz5Cs\"}"
110
+ bob_x25519_public = bob_x25519_secret.to_public
111
+ # => "{\"crv\":\"X25519\",\"kty\":\"OKP\",\"x\":\"U-ckTk7roeu-9peZjdhZUIm9yJHtBrrkBJojCpUz5Cs\"}"
112
+
113
+ # Alice wants to send Bob an encrypted message that has also been signed.
114
+ # Alice provides Bob with her public signing key.
115
+ # Bob provides Alice with his public key agreement key.
116
+ # Alice does not specify her own key agreement key, which results in a new one being generated.
117
+ plain_text = "Hello, World!"
118
+ cipher_text, alice_x25519_secret = bob_x25519_public.box_encrypt(plain_text)
119
+ cipher_text = cipher_text.compact
120
+ # => ["eyJhbGciOiJFQ0RILUVTIiwiYXB1IjoiXy1leGtvYkpFQVpRWi01N1E2ZzRsMHNzbG0yT2I4TnRTeDlwcFFMZEJaNCIsImFwdiI6IjY5U1Y3VWo0MWstMEhrcU1GOXVMaEk5Ty14TXZ0UlJ0bU0tbmxJV1RyV2MiLCJlbmMiOiJBMTI4R0NNIiwiZXBrIjp7ImNydiI6IlgyNTUxOSIsImt0eSI6Ik9LUCIsIngiOiJQR3h4cXRXbnJ2Q0IwOVY0cVRoZEZpUUVweXp6ZVhEMVVJNjYyY0UxNHlrIn19..qcI2uruuJA7wZYda.-NhogJt2ofXlKSZMcQ.7Y9ZBHyPuuSj75u7zR7gpg",
121
+ # "{\"crv\":\"X25519\",\"d\":\"6Gu9vuKL_3YqjBrxLm2rcz3mkKNHMj5pkslVbL7XEVU\",\"kty\":\"OKP\",\"x\":\"PGxxqtWnrvCB09V4qThdFiQEpyzzeXD1UI662cE14yk\"}"]
122
+
123
+ # Alice then signs the cipher_text using her Ed25519 secret key.
124
+ signed_text = alice_ed25519_secret.sign(cipher_text).compact
125
+ # => "eyJhbGciOiJFZDI1NTE5In0.ZXlKaGJHY2lPaUpGUTBSSUxVVlRJaXdpWVhCMUlqb2lYeTFsZUd0dllrcEZRVnBSV2kwMU4xRTJaelJzTUhOemJHMHlUMkk0VG5SVGVEbHdjRkZNWkVKYU5DSXNJbUZ3ZGlJNklqWTVVMVkzVldvME1Xc3RNRWhyY1UxR09YVk1hRWs1VHkxNFRYWjBVbEowYlUwdGJteEpWMVJ5VjJNaUxDSmxibU1pT2lKQk1USTRSME5OSWl3aVpYQnJJanA3SW1OeWRpSTZJbGd5TlRVeE9TSXNJbXQwZVNJNklrOUxVQ0lzSW5naU9pSlFSM2g0Y1hSWGJuSjJRMEl3T1ZZMGNWUm9aRVpwVVVWd2VYcDZaVmhFTVZWSk5qWXlZMFV4TkhsckluMTkuLnFjSTJ1cnV1SkE3d1pZZGEuLU5ob2dKdDJvZlhsS1NaTWNRLjdZOVpCSHlQdXVTajc1dTd6UjdncGc.AK5wm7g9UjZflK5Z-0K7SRu8gPiT-zJoz0HBGy1fI9tnpw9_iXReqmsV0Z8NEa34gj4SZbSGYI7KZxXzyZ-VBw"
126
+
127
+ # Bob receives the signed_text and can immediately verify whether it's from Alice or not.
128
+ verified, cipher_text, = alice_ed25519_public.verify(signed_text)
129
+ if verified == true
130
+ # Bob can decrypt the cipher_text using his secret X25519 key.
131
+ plain_text, jwe = bob_x25519_secret.box_decrypt(cipher_text)
132
+ # => "Hello, World!"
133
+ # If Bob wanted to send a message back to Alice, he can use the embedded public key to do so:
134
+ jwe.alg.epk.box_encrypt("A message for Alice", bob_x25519_secret)
135
+ # At this point, however, we essentially have a partially functional SSL/TLS implementation.
136
+ end
137
+ ```
@@ -0,0 +1,263 @@
1
+ # @title Key Generation
2
+
3
+ # Key Generation
4
+
5
+ There are four key generation methods described below for each key type:
6
+
7
+ * Method 1: OpenSSL
8
+ * Method 2: {JOSE::JWK.generate_key JOSE::JWK.generate_key}
9
+ * Method 3: {JOSE::JWE.generate_key JOSE::JWE.generate_key}
10
+ * Method 4: {JOSE::JWS.generate_key JOSE::JWS.generate_key}
11
+
12
+ ## EC
13
+
14
+ The three curve types defined in the [JWA RFC 7518](https://tools.ietf.org/html/rfc7518#section-6.2.1.1) for the `EC` key type are:
15
+
16
+ 1. `"P-256"` (openssl curve `secp256r1`)
17
+ 2. `"P-384"` (openssl curve `secp384r1`)
18
+ 3. `"P-521"` (openssl curve `secp521r1`)
19
+
20
+ ### Method 1
21
+
22
+ The basic formula for key generation is `openssl ecparam -name CURVE -genkey -noout -out FILE`, for example:
23
+
24
+ ```bash
25
+ openssl ecparam -name secp256r1 -genkey -noout -out ec-secp256r1.pem
26
+ openssl ecparam -name secp384r1 -genkey -noout -out ec-secp384r1.pem
27
+ openssl ecparam -name secp521r1 -genkey -noout -out ec-secp521r1.pem
28
+ ```
29
+
30
+ The PEM files can then be read using {JOSE::JWK.from_pem_file JOSE::JWK.from_pem_file}:
31
+
32
+ ```ruby
33
+ jwk = JOSE::JWK.from_pem_file("ec-secp256r1.pem")
34
+ ```
35
+
36
+ ### Method 2
37
+
38
+ The curve names are almost the same as the ones for OpenSSL.
39
+
40
+ ```ruby
41
+ jwk = JOSE::JWK.generate_key([:ec, 'prime256v1'])
42
+ jwk = JOSE::JWK.generate_key([:ec, 'secp384r1'])
43
+ jwk = JOSE::JWK.generate_key([:ec, 'secp521r1'])
44
+
45
+ # Alternative curve alias syntax:
46
+ jwk = JOSE::JWK.generate_key([:ec, 'P-256'])
47
+ jwk = JOSE::JWK.generate_key([:ec, 'P-384'])
48
+ jwk = JOSE::JWK.generate_key([:ec, 'P-521'])
49
+ ```
50
+
51
+ Keys may also be generated based on other keys. The new key will use the same curve as the supplied key.
52
+
53
+ ```ruby
54
+ old_jwk = JOSE::JWK.from_pem_file("ec-secp256r1.pem")
55
+ new_jwk = JOSE::JWK.generate_key(old_jwk)
56
+ ```
57
+
58
+ ### Method 3
59
+
60
+ If you have a JWE header with an `"epk"` field, a new key will be generated based on the same key type of the `"epk"`. Otherwise, the `P-521` curve will be used.
61
+
62
+ ```ruby
63
+ # Based on the "epk" field.
64
+ epk = JOSE::JWK.generate_key([:ec, 'P-256'])
65
+ jwe = JOSE::JWE.from_map({"alg" => "ECDH-ES", "enc" => "A128GCM", "epk" => epk.to_map})
66
+ jwk = jwe.generate_key
67
+
68
+ # Otherwise, defaults to "P-521".
69
+ jwk = JOSE::JWE.generate_key({"alg" => "ECDH-ES", "enc" => "A128GCM"})
70
+ ```
71
+
72
+ ### Method 4
73
+
74
+ If you have a JWS header with one of the ECDSA signature algorithms specified, a corresponding EC key will be generated with the correct curve for the signature type.
75
+
76
+ ```ruby
77
+ jwk_ec256 = JOSE::JWS.generate_key({"alg" => "ES256"})
78
+ jwk_ec384 = JOSE::JWS.generate_key({"alg" => "ES384"})
79
+ jwk_ec521 = JOSE::JWS.generate_key({"alg" => "ES512"})
80
+ ```
81
+
82
+ ## oct
83
+
84
+ This key type is simply an octet or byte sequence (see [RFC 7518 Section 6.4](https://tools.ietf.org/html/rfc7518#section-6.4)).
85
+
86
+ ### Method 1
87
+
88
+ The basic formula for generating a random octet sequence is `openssl rand -out FILE BYTE_SIZE`, for example:
89
+
90
+ ```bash
91
+ openssl rand -out oct-128-bit.bin 16
92
+ ```
93
+
94
+ The binary file can then be read using {JOSE::JWK.from_oct_file JOSE::JWK.from_oct_file}:
95
+
96
+ ```ruby
97
+ jwk = JOSE::JWK.from_oct_file("oct-128-bit.bin")
98
+ ```
99
+
100
+ ### Method 2
101
+
102
+ Calling either of these functions with an integer will generate a random octet sequence.
103
+
104
+ ```ruby
105
+ jwk = JOSE::JWK.generate_key([:oct, 16])
106
+ ```
107
+
108
+ Keys may also be generated based on other keys. The new key will use the same byte size as the supplied key.
109
+
110
+ ```ruby
111
+ old_jwk = JOSE::JWK.from_oct_file("oct-128-bit.bin")
112
+ new_jwk = JOSE::JWK.generate_key(old_jwk)
113
+ ```
114
+
115
+ ### Method 3
116
+
117
+ If you have a JWE header with an `"alg"` field that requires a symmetric key, a new `oct` key will be generated based on the byte size required of `"alg"` and/or `"enc"`.
118
+
119
+ ```ruby
120
+ jwk_oct16 = JOSE::JWE.generate_key({"alg" => "dir", "enc" => "A128GCM"})
121
+ jwk_oct24 = JOSE::JWE.generate_key({"alg" => "dir", "enc" => "A192GCM"})
122
+ jwk_oct32 = JOSE::JWE.generate_key({"alg" => "dir", "enc" => "A256GCM"})
123
+ jwk_oct32 = JOSE::JWE.generate_key({"alg" => "dir", "enc" => "A128CBC-HS256"})
124
+ jwk_oct48 = JOSE::JWE.generate_key({"alg" => "dir", "enc" => "A192CBC-HS384"})
125
+ jwk_oct64 = JOSE::JWE.generate_key({"alg" => "dir", "enc" => "A256CBC-HS512"})
126
+ ```
127
+
128
+ ### Method 4
129
+
130
+ If you have a JWS header with an `"alg"` field that requires a symmetric key, a new `oct` key will be generated based on the byte size recommended for `"alg".
131
+
132
+ ```ruby
133
+ jwk_oct32 = JOSE::JWS.generate_key({"alg" => "HS256"})
134
+ jwk_oct48 = JOSE::JWS.generate_key({"alg" => "HS384"})
135
+ jwk_oct64 = JOSE::JWS.generate_key({"alg" => "HS512"})
136
+ ```
137
+
138
+ ## OKP
139
+
140
+ This key type is an octet key pair with an associated curve (see [draft-ietf-jose-cfrg-curves](https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves)).
141
+
142
+ ### Method 1
143
+
144
+ *NOTE:* Only `Ed25519` is currently supported by `ssh-keygen`.
145
+
146
+ The basic formula for generating a octet key pair is `ssh-keygen -t TYPE -f FILE`, for example:
147
+
148
+ ```bash
149
+ ssh-keygen -t ed25519 -f ed25519
150
+ ```
151
+
152
+ The private key file can then be read using {JOSE::JWK.from_openssh_key_file JOSE::JWK.from_openssh_key_file}:
153
+
154
+ ```ruby
155
+ jwk = JOSE::JWK.from_openssh_key_file("ed25519")
156
+ ```
157
+
158
+ ### Method 2
159
+
160
+ Calling either of these functions with a specified curve will generate an octet key pair. You may also specify the secret portion of the key after the curve.
161
+
162
+ ```ruby
163
+ # Curve25519
164
+ jwk_Ed25519 = JOSE::JWK.generate_key([:okp, :Ed25519])
165
+ jwk_Ed25519ph = JOSE::JWK.generate_key([:okp, :Ed25519ph])
166
+ jwk_X25519 = JOSE::JWK.generate_key([:okp, :X25519])
167
+
168
+ # Curve448
169
+ jwk_Ed448 = JOSE::JWK.generate_key([:okp, :Ed448])
170
+ jwk_Ed448ph = JOSE::JWK.generate_key([:okp, :Ed448ph])
171
+ jwk_X448 = JOSE::JWK.generate_key([:okp, :X448])
172
+ ```
173
+
174
+ Keys may also be generated based on other keys. The new key will use the same curve as the supplied key.
175
+
176
+ ```ruby
177
+ old_jwk = JOSE::JWK.from_openssh_key_file("ed25519")
178
+ new_jwk = JOSE::JWK.generate_key(old_jwk)
179
+ ```
180
+
181
+ ### Method 3
182
+
183
+ If you have a JWE header with an `"epk"` field, a new key will be generated based on the same key type of the `"epk"`.
184
+
185
+ ```ruby
186
+ # Based on the "epk" field.
187
+ epk = JOSE::JWK.generate_key([:okp, :X25519])
188
+ jwe = JOSE::JWE.from_map({"alg" => "ECDH-ES", "enc" => "A128GCM", "epk" => epk.to_map})
189
+ jwk = jwe.generate_key
190
+ ```
191
+
192
+ ### Method 4
193
+
194
+ If you have a JWS header with one of the EdDSA signature algorithms specified, a corresponding OKP key will be generated with the correct curve for the signature type.
195
+
196
+ ```ruby
197
+ jwk_Ed25519 = JOSE::JWS.generate_key({"alg" => "Ed25519"})
198
+ jwk_Ed25519ph = JOSE::JWS.generate_key({"alg" => "Ed25519ph"})
199
+ jwk_Ed448 = JOSE::JWS.generate_key({"alg" => "Ed448"})
200
+ jwk_Ed448ph = JOSE::JWS.generate_key({"alg" => "Ed448ph"})
201
+ ```
202
+
203
+ ## RSA
204
+
205
+ Both two-prime and multi-prime RSA keys are supported by [RFC 7518 Section 6.3](https://tools.ietf.org/html/rfc7518#section-6.3), but currently only two-prime RSA keys can be generated by OpenSSL-based generators. Ruby does not support multi-prime RSA at this time.
206
+
207
+ ### Method 1
208
+
209
+ The basic formula for generating a RSA key is `openssl genrsa -out FILE BIT_SIZE`, for example:
210
+
211
+ ```bash
212
+ openssl genrsa -out rsa-2048.pem 2048
213
+ ```
214
+
215
+ The PEM file can then be read using {JOSE::JWK.from_pem_file JOSE::JWK.from_pem_file}:
216
+
217
+ ```ruby
218
+ jwk = JOSE::JWK.from_pem_file("rsa-2048.pem")
219
+ ```
220
+
221
+ ### Method 2
222
+
223
+ The modulus bit size is the only required argument. Optionally, you may specify the public exponent as the second argument (default is `65537`).
224
+
225
+ ```ruby
226
+ jwk = JOSE::JWK.generate_key([:rsa, 2048])
227
+
228
+ # Alternative explicit syntax with public exponent:
229
+ jwk = JOSE::JWK.generate_key([:rsa, 4096, 65537])
230
+ ```
231
+
232
+ Keys may also be generated based on other keys. The new key will use the same modulus size and public exponent as the supplied key.
233
+
234
+ ```ruby
235
+ old_jwk = JOSE::JWK.from_pem_file("rsa-2048.pem")
236
+ new_jwk = JOSE::JWK.generate_key(old_jwk)
237
+ ```
238
+
239
+ ### Method 3
240
+
241
+ If you have a JWE header with an `"alg"` field that requires an asymmetric RSA key, a new `RSA` key will be generated. 2048-bit keys are generated in these cases.
242
+
243
+ ```ruby
244
+ jwk_rsa1_5 = JOSE::JWE.generate_key({"alg" => "RSA1_5", "enc" => "A128GCM"})
245
+ jwk_rsa_oaep = JOSE::JWE.generate_key({"alg" => "RSA-OAEP", "enc" => "A128GCM"})
246
+ jwk_rsa_oaep256 = JOSE::JWE.generate_key({"alg" => "RSA-OAEP-256", "enc" => "A128GCM"})
247
+ ```
248
+
249
+ ### Method 4
250
+
251
+ If you have a JWS header with one of the RSA PKCS1 or PSS signature algorithms specified, a corresponding RSA key will be generated with a recommended modulus size based on the digest type.
252
+
253
+ ```ruby
254
+ # RS256, RS384, RS512
255
+ jwk_rsa2048 = JOSE::JWS.generate_key({"alg" => "RS256"})
256
+ jwk_rsa3072 = JOSE::JWS.generate_key({"alg" => "RS384"})
257
+ jwk_rsa4096 = JOSE::JWS.generate_key({"alg" => "RS512"})
258
+
259
+ # PS256, PS384, PS512
260
+ jwk_rsa2048 = JOSE::JWS.generate_key({"alg" => "PS256"})
261
+ jwk_rsa3072 = JOSE::JWS.generate_key({"alg" => "PS384"})
262
+ jwk_rsa4096 = JOSE::JWS.generate_key({"alg" => "PS512"})
263
+ ```