1defmodule JOSE.JWA do
2  @moduledoc ~S"""
3  JWA stands for JSON Web Algorithms which is defined in [RFC 7518](https://tools.ietf.org/html/rfc7518).
4
5  ## Cryptographic Algorithm Fallback
6
7  Native implementations of all cryptographic and public key algorithms
8  required by the JWA specifications are not present in current versions
9  of Elixir and OTP.
10
11  JOSE will detect whether a specific algorithm is natively supported or not
12  and, by default, it will mark the algorithm as unsupported if a native
13  implementation is not found.
14
15  However, JOSE also has pure Erlang versions of many of the missing algorithms
16  which can be used as a fallback by calling `JOSE.crypto_fallback/1` and
17  passing `true`.
18  """
19
20  ## Crypto API
21
22  @doc """
23  Decrypts `cipher_text` according to `cipher` block cipher.
24
25  Currently supported block ciphers:
26
27    * `{:aes_ecb, 128}` - AES ECB with 128-bit `key` size
28    * `{:aes_ecb, 192}` - AES ECB with 192-bit `key` size
29    * `{:aes_ecb, 256}` - AES ECB with 256-bit `key` size
30  """
31  defdelegate block_decrypt(cipher, key, cipher_text), to: :jose_jwa
32
33  @doc """
34  Decrypts `cipher_text` according to `cipher` block cipher.
35
36  Currently supported block ciphers:
37
38    * `{:aes_cbc, 128}` - AES CBC with 128-bit `key` size and 128-bit `iv` size
39    * `{:aes_cbc, 192}` - AES CBC with 192-bit `key` size and 128-bit `iv` size
40    * `{:aes_cbc, 256}` - AES CBC with 256-bit `key` size and 128-bit `iv` size
41    * `{:aes_gcm, 128}` - AES GCM with 128-bit `key` size and variable `iv` size
42    * `{:aes_gcm, 192}` - AES GCM with 192-bit `key` size and variable `iv` size
43    * `{:aes_gcm, 256}` - AES GCM with 256-bit `key` size and variable `iv` size
44    * `{:chacha20_poly1305, 256}` - ChaCha20/Poly1305 with 256-bit `key` size and 96-bit `iv` size
45  """
46  defdelegate block_decrypt(cipher, key, iv, cipher_text), to: :jose_jwa
47
48  @doc """
49  Encrypts `plain_text` according to `cipher` block cipher.
50
51  Currently supported block ciphers:
52
53    * `{:aes_ecb, 128}` - AES ECB with 128-bit `key` size
54    * `{:aes_ecb, 192}` - AES ECB with 192-bit `key` size
55    * `{:aes_ecb, 256}` - AES ECB with 256-bit `key` size
56  """
57  defdelegate block_encrypt(cipher, key, plain_text), to: :jose_jwa
58
59  @doc """
60  Encrypts `plain_text` according to `cipher` block cipher.
61
62  Currently supported block ciphers:
63
64    * `{:aes_cbc, 128}` - AES CBC with 128-bit `key` size and 128-bit `iv` size
65    * `{:aes_cbc, 192}` - AES CBC with 192-bit `key` size and 128-bit `iv` size
66    * `{:aes_cbc, 256}` - AES CBC with 256-bit `key` size and 128-bit `iv` size
67    * `{:aes_gcm, 128}` - AES GCM with 128-bit `key` size and variable `iv` size
68    * `{:aes_gcm, 192}` - AES GCM with 192-bit `key` size and variable `iv` size
69    * `{:aes_gcm, 256}` - AES GCM with 256-bit `key` size and variable `iv` size
70    * `{:chacha20_poly1305, 256}` - ChaCha20/Poly1305 with 256-bit `key` size and 96-bit `iv` size
71  """
72  defdelegate block_encrypt(cipher, key, iv, plain_text), to: :jose_jwa
73
74  ## Public Key API
75
76  @doc """
77  Decrypts `cipher_text` using the `private_key`.
78
79  ## Options
80
81    * `:rsa_padding` - one of `:rsa_pkcs1_oaep_padding` or `:rsa_pkcs1_padding`
82    * `:rsa_oaep_md` - sets the hashing algorithm for `:rsa_pkcs1_oaep_padding`, defaults to `:sha`
83    * `:rsa_oaep_label` - sets the label for `:rsa_pkcs1_oaep_padding`, defaults to `<<>>`
84  """
85  defdelegate decrypt_private(cipher_text, private_key, options), to: :jose_jwa
86
87  @doc """
88  Encrypts `plain_text` using the `public_key`.
89
90  ## Options
91
92    * `:rsa_padding` - one of `:rsa_pkcs1_oaep_padding` or `:rsa_pkcs1_padding`
93    * `:rsa_oaep_md` - sets the hashing algorithm for `:rsa_pkcs1_oaep_padding`, defaults to `:sha`
94    * `:rsa_oaep_label` - sets the label for `:rsa_pkcs1_oaep_padding`, defaults to `<<>>`
95  """
96  defdelegate encrypt_public(plain_text, public_key, options), to: :jose_jwa
97
98  @doc """
99  Signs the digested `message` using the `digest_type` and `private_key`.
100
101  ## Options
102
103    * `:rsa_padding` - one of `:rsa_pkcs1_pss_padding` or `:rsa_pkcs1_padding`
104    * `:rsa_pss_saltlen` - sets the salt length for `:rsa_pkcs1_pss_padding`, defaults to `-1`
105      * `-2` - use maximum for salt length
106      * `-1` - use hash length for salt length
107      * any number higher than `-1` is used as the actual salt length
108  """
109  defdelegate sign(message, digest_type, private_key, options), to: :jose_jwa
110
111  @doc """
112  Verifies the `signature` with the digested `message` using the `digest_type` and `public_key`.
113
114  ## Options
115
116    * `:rsa_padding` - one of `:rsa_pkcs1_pss_padding` or `:rsa_pkcs1_padding`
117    * `:rsa_pss_saltlen` - sets the salt length for `:rsa_pkcs1_pss_padding`, defaults to `-1`
118      * `-2` - automatically determine based on the PSS block structure
119      * `-1` - use hash length for salt length
120      * any number higher than `-1` is used as the actual salt length
121  """
122  defdelegate verify(message, digest_type, signature, public_key, options), to: :jose_jwa
123
124  ## API
125
126  @doc """
127  Returns the current module and first argument for the specified `cipher`.
128
129      iex> JOSE.JWA.block_cipher({:aes_cbc, 128})
130      {:crypto, :aes_cbc128}
131      iex> JOSE.JWA.block_cipher({:aes_cbc, 192})
132      {:jose_jwa_unsupported, {:aes_cbc, 192}}
133      iex> JOSE.crypto_fallback(true)
134      :ok
135      iex> JOSE.JWA.block_cipher({:aes_cbc, 192})
136      {:jose_jwa_aes, {:aes_cbc, 192}}
137
138  """
139  defdelegate block_cipher(cipher), to: :jose_jwa
140
141  @doc """
142  Returns the current block ciphers and their associated modules.
143
144      iex> JOSE.JWA.crypto_ciphers()
145      [{{:aes_cbc, 128}, :crypto}, {{:aes_cbc, 192}, :crypto},
146       {{:aes_cbc, 256}, :crypto}, {{:aes_ecb, 128}, :crypto},
147       {{:aes_ecb, 192}, :crypto}, {{:aes_ecb, 256}, :crypto},
148       {{:aes_gcm, 128}, :crypto}, {{:aes_gcm, 192}, :crypto},
149       {{:aes_gcm, 256}, :crypto},
150       {{:chacha20_poly1305, 256}, :jose_chacha20_poly1305}]
151
152  """
153  defdelegate crypto_ciphers(), to: :jose_jwa
154
155  @doc """
156  See `JOSE.crypto_fallback/0`
157  """
158  defdelegate crypto_fallback(), to: :jose_jwa
159
160  @doc """
161  See `JOSE.crypto_fallback/1`
162  """
163  defdelegate crypto_fallback(boolean), to: :jose_jwa
164
165  @doc """
166  Returns the current listing of supported `:crypto` and `:public_key` algorithms.
167
168      iex> JOSE.JWA.crypto_supports()
169      [ciphers: [aes_cbc: 128, aes_cbc: 192, aes_cbc: 256, aes_ecb: 128, aes_ecb: 192,
170        aes_ecb: 256, aes_gcm: 128, aes_gcm: 192, aes_gcm: 256,
171        chacha20_poly1305: 256],
172       hashs: [:md5, :poly1305, :sha, :sha256, :sha384, :sha512, :shake256],
173       public_keys: [:ec_gf2m, :ecdh, :ecdsa, :ed25519, :ed25519ph, :ed448, :ed448ph,
174        :rsa, :x25519, :x448], rsa_crypt: [:rsa1_5, :rsa_oaep, :rsa_oaep_256],
175       rsa_sign: [:rsa_pkcs1_padding, :rsa_pkcs1_pss_padding]]
176
177  """
178  defdelegate crypto_supports(), to: :jose_jwa
179
180  @doc """
181  Performs a constant time comparison between two binaries to help avoid [timing attacks](https://en.wikipedia.org/wiki/Timing_attack).
182  """
183  defdelegate constant_time_compare(a, b), to: :jose_jwa
184
185  @doc """
186  Returns either `:binary` or `:list` depending on the detected runtime behavior for EC keys.
187  """
188  defdelegate ec_key_mode(), to: :jose_jwa
189
190  @doc """
191  Checks whether the `cipher` is natively supported by `:crypto` or not.
192  """
193  defdelegate is_block_cipher_supported(cipher), to: :jose_jwa
194
195  @doc """
196  Checks whether ChaCha20/Poly1305 support is available or not.
197  """
198  defdelegate is_chacha20_poly1305_supported(), to: :jose_jwa
199
200  @doc """
201  Checks whether the `padding` is natively supported by `:public_key` or not.
202  """
203  defdelegate is_rsa_crypt_supported(padding), to: :jose_jwa
204
205  @doc """
206  Checks whether the `padding` is natively supported by `:public_key` or not.
207  """
208  defdelegate is_rsa_sign_supported(padding), to: :jose_jwa
209
210  @doc """
211  Returns the current listing of supported JOSE algorithms.
212
213      iex> JOSE.JWA.supports()
214      [{:jwe,
215        {:alg,
216         ["A128GCMKW", "A128KW", "A192GCMKW", "A192KW", "A256GCMKW", "A256KW",
217          "ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW",
218          "PBES2-HS256+A128KW", "PBES2-HS384+A192KW", "PBES2-HS512+A256KW",
219          "RSA-OAEP", "RSA-OAEP-256", "RSA1_5", "dir"]},
220        {:enc,
221         ["A128CBC-HS256", "A128GCM", "A192CBC-HS384", "A192GCM", "A256CBC-HS512",
222          "A256GCM", "ChaCha20/Poly1305"]}, {:zip, ["DEF"]}},
223       {:jwk, {:kty, ["EC", "OKP", "RSA", "oct"]},
224        {:kty_OKP_crv,
225         ["Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "X25519", "X448"]}},
226       {:jws,
227        {:alg,
228         ["ES256", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448", "Ed448ph",
229          "HS256", "HS384", "HS512", "PS256", "PS384", "PS512", "Poly1305", "RS256",
230          "RS384", "RS512", "none"]}}]
231
232  """
233  defdelegate supports(), to: :jose_jwa
234
235  @doc """
236  See `JOSE.unsecured_signing/0`
237  """
238  defdelegate unsecured_signing(), to: :jose_jwa
239
240  @doc """
241  See `JOSE.unsecured_signing/1`
242  """
243  defdelegate unsecured_signing(boolean), to: :jose_jwa
244end
245