erlang-jose-1.10.1/0000755000232200023220000000000013605433351014351 5ustar debalancedebalanceerlang-jose-1.10.1/lib/0000755000232200023220000000000013605433351015117 5ustar debalancedebalanceerlang-jose-1.10.1/lib/jose.ex0000644000232200023220000001234413605433351016421 0ustar debalancedebalancedefmodule JOSE do @moduledoc ~S""" JOSE stands for JSON Object Signing and Encryption which is a is a set of standards established by the [JOSE Working Group](https://datatracker.ietf.org/wg/jose). JOSE is split into 5 main components: * `JOSE.JWA` - JSON Web Algorithms (JWA) [RFC 7518](https://tools.ietf.org/html/rfc7518) * `JOSE.JWE` - JSON Web Encryption (JWE) [RFC 7516](https://tools.ietf.org/html/rfc7516) * `JOSE.JWK` - JSON Web Key (JWK) [RFC 7517](https://tools.ietf.org/html/rfc7517) * `JOSE.JWS` - JSON Web Signature (JWS) [RFC 7515](https://tools.ietf.org/html/rfc7515) * `JOSE.JWT` - JSON Web Token (JWT) [RFC 7519](https://tools.ietf.org/html/rfc7519) Additional specifications and drafts implemented: * JSON Web Key (JWK) Thumbprint [RFC 7638](https://tools.ietf.org/html/rfc7638) * JWS Unencoded Payload Option [RFC 7797](https://tools.ietf.org/html/rfc7797) """ ## Functions @doc """ Gets the current ChaCha20/Poly1305 module used by `jose_chacha20_poly1305`, see `chacha20_poly1305_module/1` for default. """ defdelegate chacha20_poly1305_module(), to: :jose @doc """ Sets the current ChaCha20/Poly1305 module used by `jose_chacha20_poly1305`. Currently supported ChaCha20/Poly1305 modules (first found is used as default): * `crypto` - only when 96-bit nonce is supported * [`libsodium`](https://github.com/potatosalad/erlang-libsodium) * `jose_jwa_chacha20_poly1305` - only supported when `crypto_fallback/0` is `true` Additional modules that implement the `jose_chacha20_poly1305` behavior may also be used. """ defdelegate chacha20_poly1305_module(module), to: :jose @doc """ Gets the current Cryptographic Algorithm Fallback state, defaults to `false`. """ defdelegate crypto_fallback(), to: :jose @doc """ Sets the current Cryptographic Algorithm Fallback state. """ defdelegate crypto_fallback(boolean), to: :jose @doc """ Gets the current Curve25519 module used by `jose_curve25519`, see `curve25519_module/1` for default. """ defdelegate curve25519_module(), to: :jose @doc """ Sets the current Curve25519 module used by `jose_curve25519`. Currently supported Curve25519 modules (first found is used as default): * [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf) * [`libsodium`](https://github.com/potatosalad/erlang-libsodium) * `jose_jwa_curve25519` - only supported when `crypto_fallback/0` is `true` Additional modules that implement the `jose_curve25519` behavior may also be used. """ defdelegate curve25519_module(module), to: :jose @doc """ Gets the current Curve448 module used by `jose_curve448`, see `curve448_module/1` for default. """ defdelegate curve448_module(), to: :jose @doc """ Sets the current Curve448 module used by `jose_curve448`. Currently supported Curve448 modules (first found is used as default): * [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf) * `jose_jwa_curve448` - only supported when `crypto_fallback/0` is `true` Additional modules that implement the `jose_curve448` behavior may also be used. """ defdelegate curve448_module(module), to: :jose @doc """ Decode JSON to a term using the module returned by `json_module/0`. """ defdelegate decode(binary), to: :jose @doc """ Encode a term to JSON using the module returned by `json_module/0`. """ defdelegate encode(term), to: :jose @doc """ Gets the current JSON module used by `decode/1` and `encode/1`, see `json_module/1` for default. """ defdelegate json_module(), to: :jose @doc """ Sets the current JSON module used by `decode/1` and `encode/1`. Currently supported JSON modules (first found is used as default): * [`ojson`](https://github.com/potatosalad/erlang-ojson) * [`Jason`](https://github.com/michalmuskala/jason) * [`Poison`](https://github.com/devinus/poison) * [`jiffy`](https://github.com/davisp/jiffy) * [`jsone`](https://github.com/sile/jsone) * [`jsx`](https://github.com/talentdeficit/jsx) Additional modules that implement the `jose_json` behavior may also be used. """ defdelegate json_module(module), to: :jose @doc """ Gets the current SHA3 module used by `jose_sha3`, see `sha3_module/1` for default. """ defdelegate sha3_module(), to: :jose @doc """ Sets the current SHA3 module used by `jose_sha3`. Currently supported SHA3 modules (first found is used as default): * [`keccakf1600`](https://github.com/potatosalad/erlang-keccakf1600) * [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf) * `jose_jwa_sha3` - only supported when `crypto_fallback/0` is `true` Additional modules that implement the `jose_sha3` behavior may also be used. """ defdelegate sha3_module(module), to: :jose @doc """ Gets the current Unsecured Signing state, defaults to `false`. """ defdelegate unsecured_signing(), to: :jose @doc """ Sets the current Unsecured Signing state. Enables/disables the `"none"` algorithm used for signing and verifying. See [Critical vulnerabilities in JSON Web Token libraries](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/) for more information. """ defdelegate unsecured_signing(boolean), to: :jose end erlang-jose-1.10.1/lib/jose/0000755000232200023220000000000013605433351016057 5ustar debalancedebalanceerlang-jose-1.10.1/lib/jose/jwt.ex0000644000232200023220000002530013605433351017221 0ustar debalancedebalancerequire Record defmodule JOSE.JWT do @moduledoc ~S""" JWT stands for JSON Web Token which is defined in [RFC 7519](https://tools.ietf.org/html/rfc7519). ## Encryption Examples ## Signature Examples All of the example keys generated below can be found here: [https://gist.github.com/potatosalad/925a8b74d85835e285b9](https://gist.github.com/potatosalad/925a8b74d85835e285b9) See `JOSE.JWS` for more Signature examples. For security purposes, `verify_strict/3` is recommended over `verify/2`. ### HS256 # let's generate the key we'll use below and define our jwt jwk_hs256 = JOSE.JWK.generate_key({:oct, 16}) jwt = %{ "test" => true } # HS256 iex> signed_hs256 = JOSE.JWT.sign(jwk_hs256, %{ "alg" => "HS256" }, jwt) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0Ijp0cnVlfQ.XYsFJDhfBZCAKnEZjR0WWd1l1ZPDD4bYpZYMHizexfQ" # verify_strict/3 is recommended over verify/2 iex> JOSE.JWT.verify_strict(jwk_hs256, ["HS256"], signed_hs256) {true, %JOSE.JWT{fields: %{"test" => true}}, %JOSE.JWS{alg: {:jose_jws_alg_hmac, {:jose_jws_alg_hmac, :sha256}}, b64: :undefined, fields: %{"typ" => "JWT"}}} # verify/2 returns the same thing without "alg" whitelisting iex> JOSE.JWT.verify(jwk_hs256, signed_hs256) {true, %JOSE.JWT{fields: %{"test" => true}}, %JOSE.JWS{alg: {:jose_jws_alg_hmac, {:jose_jws_alg_hmac, :sha256}}, b64: :undefined, fields: %{"typ" => "JWT"}}} # the default signing algorithm is also "HS256" based on the type of jwk used iex> signed_hs256 == JOSE.JWT.sign(jwk_hs256, jwt) |> JOSE.JWS.compact |> elem(1) true """ record = Record.extract(:jose_jwt, from_lib: "jose/include/jose_jwt.hrl") keys = :lists.map(&elem(&1, 0), record) vals = :lists.map(&{&1, [], nil}, keys) pairs = :lists.zip(keys, vals) defstruct keys @type t :: %__MODULE__{} @doc """ Converts a `JOSE.JWT` struct to a `:jose_jwt` record. """ def to_record(%JOSE.JWT{unquote_splicing(pairs)}) do {:jose_jwt, unquote_splicing(vals)} end def to_record(list) when is_list(list), do: for(element <- list, into: [], do: to_record(element)) @doc """ Converts a `:jose_jwt` record into a `JOSE.JWT`. """ def from_record(jose_jwt) def from_record({:jose_jwt, unquote_splicing(vals)}) do %JOSE.JWT{unquote_splicing(pairs)} end def from_record(list) when is_list(list), do: for(element <- list, into: [], do: from_record(element)) ## Decode API @doc """ Converts a binary or map into a `JOSE.JWT`. iex> JOSE.JWT.from(%{ "test" => true }) %JOSE.JWT{fields: %{"test" => true}} iex> JOSE.JWT.from("{\"test\":true}") %JOSE.JWT{fields: %{"test" => true}} """ def from(list) when is_list(list), do: for(element <- list, into: [], do: from(element)) def from(jwt = %JOSE.JWT{}), do: from(to_record(jwt)) def from(any), do: :jose_jwt.from(any) |> from_record() @doc """ Converts a binary into a `JOSE.JWT`. """ def from_binary(list) when is_list(list), do: for(element <- list, into: [], do: from_binary(element)) def from_binary(binary), do: :jose_jwt.from_binary(binary) |> from_record() @doc """ Reads file and calls `from_binary/1` to convert into a `JOSE.JWT`. """ def from_file(file), do: :jose_jwt.from_file(file) |> from_record() @doc """ Converts a map into a `JOSE.JWT`. """ def from_map(list) when is_list(list), do: for(element <- list, into: [], do: from_map(element)) def from_map(map), do: :jose_jwt.from_map(map) |> from_record() ## Encode API @doc """ Converts a `JOSE.JWT` into a binary. """ def to_binary(list) when is_list(list), do: for(element <- list, into: [], do: to_binary(element)) def to_binary(jwt = %JOSE.JWT{}), do: to_binary(to_record(jwt)) def to_binary(any), do: :jose_jwt.to_binary(any) @doc """ Calls `to_binary/1` on a `JOSE.JWT` and then writes the binary to file. """ def to_file(file, jwt = %JOSE.JWT{}), do: to_file(file, to_record(jwt)) def to_file(file, any), do: :jose_jwt.to_file(file, any) @doc """ Converts a `JOSE.JWT` into a map. """ def to_map(list) when is_list(list), do: for(element <- list, into: [], do: to_map(element)) def to_map(jwt = %JOSE.JWT{}), do: to_map(to_record(jwt)) def to_map(any), do: :jose_jwt.to_map(any) ## API @doc """ Decrypts an encrypted `JOSE.JWT` using the `jwk`. See `JOSE.JWE.block_decrypt/2`. """ def decrypt(jwk = %JOSE.JWK{}, encrypted), do: decrypt(JOSE.JWK.to_record(jwk), encrypted) def decrypt(key, encrypted) do case :jose_jwt.decrypt(key, encrypted) do {jwe, jwt} when is_tuple(jwe) and is_tuple(jwt) -> {JOSE.JWE.from_record(jwe), from_record(jwt)} error -> error end end @doc """ Encrypts a `JOSE.JWT` using the `jwk` and the default block encryptor algorithm `jwe` for the key type. See `encrypt/3`. """ def encrypt(jwk = %JOSE.JWK{}, jwt), do: encrypt(JOSE.JWK.to_record(jwk), jwt) def encrypt({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, jwt), do: encrypt({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, jwt) def encrypt({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, jwt), do: encrypt({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, jwt) def encrypt(jwk, jwt = %JOSE.JWT{}), do: encrypt(jwk, to_record(jwt)) def encrypt(jwk, jwt), do: :jose_jwt.encrypt(jwk, jwt) @doc """ Encrypts a `JOSE.JWT` using the `jwk` and the `jwe` algorithm. See `JOSE.JWK.block_encrypt/3`. If `"typ"` is not specified in the `jwe`, `%{ "typ" => "JWT" }` will be added. """ def encrypt(jwk = %JOSE.JWK{}, jwe, jwt), do: encrypt(JOSE.JWK.to_record(jwk), jwe, jwt) def encrypt({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, jwe, jwt), do: encrypt({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, jwe, jwt) def encrypt({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, jwe, jwt), do: encrypt({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, jwe, jwt) def encrypt(jwk, jwe = %JOSE.JWE{}, jwt), do: encrypt(jwk, JOSE.JWE.to_record(jwe), jwt) def encrypt(jwk, jwe, jwt = %JOSE.JWT{}), do: encrypt(jwk, jwe, to_record(jwt)) def encrypt(jwk, jwe, jwt), do: :jose_jwt.encrypt(jwk, jwe, jwt) @doc """ Merges map on right into map on left. """ def merge(left = %JOSE.JWT{}, right), do: merge(left |> to_record(), right) def merge(left, right = %JOSE.JWT{}), do: merge(left, right |> to_record()) def merge(left, right), do: :jose_jwt.merge(left, right) |> from_record() @doc """ See `peek_payload/1`. """ def peek(signed), do: from_record(:jose_jwt.peek(signed)) @doc """ Returns the decoded payload as a `JOSE.JWT` of a signed binary or map without verifying the signature. See `JOSE.JWS.peek_payload/1`. """ def peek_payload(signed), do: from_record(:jose_jwt.peek_payload(signed)) @doc """ Returns the decoded protected as a `JOSE.JWS` of a signed binary or map without verifying the signature. See `JOSE.JWS.peek_protected/1`. """ def peek_protected(signed), do: JOSE.JWS.from_record(:jose_jwt.peek_protected(signed)) @doc """ Signs a `JOSE.JWT` using the `jwk` and the default signer algorithm `jws` for the key type. See `sign/3`. """ def sign(jwk = %JOSE.JWK{}, jwt), do: sign(JOSE.JWK.to_record(jwk), jwt) def sign(jwk, jwt = %JOSE.JWT{}), do: sign(jwk, to_record(jwt)) def sign(jwk = [%JOSE.JWK{} | _], jwt) do sign( for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end, jwt ) end def sign(jwk, jwt), do: :jose_jwt.sign(jwk, jwt) @doc """ Signs a `JOSE.JWT` using the `jwk` and the `jws` algorithm. See `JOSE.JWK.sign/3`. If `"typ"` is not specified in the `jws`, `%{ "typ" => "JWT" }` will be added. """ def sign(jwk = %JOSE.JWK{}, jws, jwt), do: sign(JOSE.JWK.to_record(jwk), jws, jwt) def sign(jwk, jws = %JOSE.JWS{}, jwt), do: sign(jwk, JOSE.JWS.to_record(jws), jwt) def sign(jwk, jws, jwt = %JOSE.JWT{}), do: sign(jwk, jws, to_record(jwt)) def sign(jwk = [%JOSE.JWK{} | _], jws, jwt) do sign( for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end, jws, jwt ) end def sign(jwk, jws, jwt), do: :jose_jwt.sign(jwk, jws, jwt) @doc """ Verifies the `signed` using the `jwk` and calls `from/1` on the payload. See `JOSE.JWS.verify/2`. """ def verify(jwk = %JOSE.JWK{}, signed), do: verify(JOSE.JWK.to_record(jwk), signed) def verify(jwk = [%JOSE.JWK{} | _], signed) do verify( for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end, signed ) end def verify(key, signed) do try do case :jose_jwt.verify(key, signed) do {verified, jwt, jws} when is_tuple(jwt) and is_tuple(jws) -> {verified, from_record(jwt), JOSE.JWS.from_record(jws)} list when is_list(list) -> for {jwk, verifications} <- list do {JOSE.JWK.from_record(jwk), Enum.map(verifications, fn {verified, jwt, jws} when is_tuple(jwt) and is_tuple(jws) -> {verified, from_record(jwt), JOSE.JWS.from_record(jws)} other -> other end)} end error -> error end catch class, reason -> {class, reason} end end @doc """ Verifies the `signed` using the `jwk`, whitelists the `"alg"` using `allow`, and calls `from/1` on the payload. See `JOSE.JWS.verify_strict/3`. """ def verify_strict(jwk = %JOSE.JWK{}, allow, signed), do: verify_strict(JOSE.JWK.to_record(jwk), allow, signed) def verify_strict(jwk = [%JOSE.JWK{} | _], allow, signed) do verify_strict( for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end, allow, signed ) end def verify_strict(key, allow, signed) do try do case :jose_jwt.verify_strict(key, allow, signed) do {verified, jwt, jws} when is_tuple(jwt) and is_tuple(jws) -> {verified, from_record(jwt), JOSE.JWS.from_record(jws)} list when is_list(list) -> for {jwk, verifications} <- list do {JOSE.JWK.from_record(jwk), Enum.map(verifications, fn {verified, jwt, jws} when is_tuple(jwt) and is_tuple(jws) -> {verified, from_record(jwt), JOSE.JWS.from_record(jws)} other -> other end)} end error -> error end catch class, reason -> {class, reason} end end end erlang-jose-1.10.1/lib/jose/poison/0000755000232200023220000000000013605433351017366 5ustar debalancedebalanceerlang-jose-1.10.1/lib/jose/poison/lexical_encoder.ex0000644000232200023220000002476413605433351023061 0ustar debalancedebalancedefmodule JOSE.Poison.LexicalEncodeError do @type t :: %__MODULE__{message: String.t(), value: any} defexception message: nil, value: nil def exception(args) when is_list(args) do if Code.ensure_loaded?(Poison) and Code.ensure_loaded?(Poison.EncodeError) do Poison.EncodeError.exception(args) else struct = __struct__() {valid, invalid} = Enum.split_with(args, fn {k, _} -> Map.has_key?(struct, k) end) case invalid do [] -> :ok _ -> IO.warn( "the following fields are unknown when raising " <> "#{inspect(__MODULE__)}: #{inspect(invalid)}. " <> "Please make sure to only give known fields when raising " <> "or redefine #{inspect(__MODULE__)}.exception/1 to " <> "discard unknown fields. Future Elixir versions will raise on " <> "unknown fields given to raise/2" ) end Kernel.struct!(struct, valid) end end def message(%{message: nil, value: value}) do "unable to encode value: #{inspect(value)}" end def message(%{message: message}) do message end end defmodule JOSE.Poison.LexicalEncode do @moduledoc false alias JOSE.Poison.{LexicalEncodeError, LexicalEncoder} defmacro __using__(_) do quote do alias JOSE.Poison.LexicalEncodeError alias String.Chars @compile {:inline, encode_name: 1} # Fast path encoding string keys defp encode_name(value) when is_binary(value) do value end defp encode_name(value) do case Chars.impl_for(value) do nil -> raise LexicalEncodeError, value: value, message: "expected a String.Chars encodable value, got: #{inspect(value)}" impl -> impl.to_string(value) end end end end end defmodule JOSE.Poison.LexicalPretty do @moduledoc false defmacro __using__(_) do quote do @default_indent 2 @default_offset 0 @compile {:inline, pretty: 1, indent: 1, offset: 1, offset: 2, spaces: 1} defp pretty(options) do Map.get(options, :pretty) == true end defp indent(options) do Map.get(options, :indent, @default_indent) end defp offset(options) do Map.get(options, :offset, @default_offset) end defp offset(options, value) do Map.put(options, :offset, value) end defp spaces(count) do :binary.copy(" ", count) end end end end defprotocol JOSE.Poison.LexicalEncoder do @fallback_to_any true @typep escape :: :unicode | :javascript | :html_safe @typep pretty :: boolean @typep indent :: non_neg_integer @typep offset :: non_neg_integer @typep strict_keys :: boolean @type options :: %{ optional(:escape) => escape, optional(:pretty) => pretty, optional(:indent) => indent, optional(:offset) => offset, optional(:strict_keys) => strict_keys } @spec encode(t, options) :: iodata def encode(value, options) end defimpl JOSE.Poison.LexicalEncoder, for: Atom do alias JOSE.Poison.LexicalEncoder def encode(nil, _), do: "null" def encode(true, _), do: "true" def encode(false, _), do: "false" def encode(atom, options) do LexicalEncoder.BitString.encode(Atom.to_string(atom), options) end end defimpl JOSE.Poison.LexicalEncoder, for: BitString do alias JOSE.Poison.LexicalEncodeError use Bitwise def encode("", _), do: "\"\"" def encode(string, options) do [?", escape(string, Map.get(options, :escape)), ?"] end defp escape("", _), do: [] for {char, seq} <- Enum.zip('"\\\n\t\r\f\b', '"\\ntrfb') do defp escape(<> <> rest, mode) do [unquote("\\" <> <>) | escape(rest, mode)] end end # http://en.wikipedia.org/wiki/Unicode_control_characters defp escape(<> <> rest, mode) when char <= 0x1F or char == 0x7F do [seq(char) | escape(rest, mode)] end defp escape(<> <> rest, mode) when char in 0x80..0x9F do [seq(char) | escape(rest, mode)] end defp escape(<> <> rest, :unicode) when char in 0xA0..0xFFFF do [seq(char) | escape(rest, :unicode)] end # http://en.wikipedia.org/wiki/UTF-16#Example_UTF-16_encoding_procedure # http://unicodebook.readthedocs.org/unicode_encodings.html defp escape(<> <> rest, :unicode) when char > 0xFFFF do code = char - 0x10000 [ seq(0xD800 ||| code >>> 10), seq(0xDC00 ||| (code &&& 0x3FF)) | escape(rest, :unicode) ] end defp escape(<> <> rest, mode) when mode in [:html_safe, :javascript] and char in [0x2028, 0x2029] do [seq(char) | escape(rest, mode)] end defp escape(<> <> rest, :html_safe) do ["\\/" | escape(rest, :html_safe)] end defp escape(string, mode) do size = chunk_size(string, mode, 0) <> = string [chunk | escape(rest, mode)] end defp chunk_size(<> <> _, _mode, acc) when char <= 0x1F or char in '"\\' do acc end defp chunk_size(<> <> _, :html_safe, acc) do acc end defp chunk_size(<> <> rest, mode, acc) when char < 0x80 do chunk_size(rest, mode, acc + 1) end defp chunk_size(<<_::utf8>> <> _, :unicode, acc) do acc end defp chunk_size(<> <> _, mode, acc) when mode in [:html_safe, :javascript] and char in [0x2028, 0x2029] do acc end defp chunk_size(<> <> rest, mode, acc) do size = cond do codepoint < 0x800 -> 2 codepoint < 0x10000 -> 3 true -> 4 end chunk_size(rest, mode, acc + size) end defp chunk_size("", _, acc), do: acc defp chunk_size(other, _, _) do raise LexicalEncodeError, value: other end @compile {:inline, seq: 1} defp seq(char) do case Integer.to_charlist(char, 16) do s when length(s) < 2 -> ["\\u000" | s] s when length(s) < 3 -> ["\\u00" | s] s when length(s) < 4 -> ["\\u0" | s] s -> ["\\u" | s] end end end defimpl JOSE.Poison.LexicalEncoder, for: Integer do def encode(integer, _options) do Integer.to_string(integer) end end defimpl JOSE.Poison.LexicalEncoder, for: Float do def encode(float, _options) do :io_lib_format.fwrite_g(float) end end defimpl JOSE.Poison.LexicalEncoder, for: Map do @compile :inline_list_funcs alias JOSE.Poison.{LexicalEncoder, LexicalEncodeError} use JOSE.Poison.{LexicalEncode, LexicalPretty} def encode(map, _) when map_size(map) < 1, do: "{}" def encode(map, options) do map |> strict_keys(Map.get(options, :strict_keys, false)) |> encode(pretty(options), options) end def encode(map, true, options) do indent = indent(options) offset = offset(options) + indent options = offset(options, offset) fun = &[ ",\n", spaces(offset), LexicalEncoder.BitString.encode(encode_name(&1), options), ": ", LexicalEncoder.encode(:maps.get(&1, map), options) | &2 ] [ "{\n", tl(:lists.foldr(fun, [], :lists.sort(:maps.keys(map)))), ?\n, spaces(offset - indent), ?} ] end def encode(map, _, options) do fun = &[ ?,, LexicalEncoder.BitString.encode(encode_name(&1), options), ?:, LexicalEncoder.encode(:maps.get(&1, map), options) | &2 ] [?{, tl(:lists.foldr(fun, [], :lists.sort(:maps.keys(map)))), ?}] end defp strict_keys(map, false), do: map defp strict_keys(map, true) do map |> Map.keys() |> Enum.each(fn key -> name = encode_name(key) if Map.has_key?(map, name) do raise LexicalEncodeError, value: name, message: "duplicate key found: #{inspect(key)}" end end) map end end defimpl JOSE.Poison.LexicalEncoder, for: List do alias JOSE.Poison.LexicalEncoder use JOSE.Poison.LexicalPretty @compile :inline_list_funcs def encode([], _), do: "[]" def encode(list, options) do encode(list, pretty(options), options) end def encode(list, false, options) do fun = &[?,, LexicalEncoder.encode(&1, options) | &2] [?[, tl(:lists.foldr(fun, [], list)), ?]] end def encode(list, true, options) do indent = indent(options) offset = offset(options) + indent options = offset(options, offset) fun = &[",\n", spaces(offset), LexicalEncoder.encode(&1, options) | &2] ["[\n", tl(:lists.foldr(fun, [], list)), ?\n, spaces(offset - indent), ?]] end end defimpl JOSE.Poison.LexicalEncoder, for: [Range, Stream, MapSet, HashSet] do alias JOSE.Poison.LexicalEncoder use JOSE.Poison.LexicalPretty def encode(collection, options) do encode(collection, pretty(options), options) end def encode(collection, false, options) do fun = &[?,, LexicalEncoder.encode(&1, options)] case Enum.flat_map(collection, fun) do [] -> "[]" [_ | tail] -> [?[, tail, ?]] end end def encode(collection, true, options) do indent = indent(options) offset = offset(options) + indent options = offset(options, offset) fun = &[",\n", spaces(offset), LexicalEncoder.encode(&1, options)] case Enum.flat_map(collection, fun) do [] -> "[]" [_ | tail] -> ["[\n", tail, ?\n, spaces(offset - indent), ?]] end end end defimpl JOSE.Poison.LexicalEncoder, for: [Date, Time, NaiveDateTime, DateTime] do alias JOSE.Poison.LexicalEncoder def encode(value, options) do LexicalEncoder.BitString.encode(@for.to_iso8601(value), options) end end defimpl JOSE.Poison.LexicalEncoder, for: Any do alias JOSE.Poison.{LexicalEncoder, LexicalEncodeError} defmacro __deriving__(module, struct, options) do deriving(module, struct, options) end def deriving(module, _struct, options) do only = options[:only] except = options[:except] extractor = cond do only -> quote(do: Map.take(struct, unquote(only))) except -> except = [:__struct__ | except] quote(do: Map.drop(struct, unquote(except))) true -> quote(do: :maps.remove(:__struct__, struct)) end quote do defimpl LexicalEncoder, for: unquote(module) do def encode(struct, options) do LexicalEncoder.Map.encode(unquote(extractor), options) end end end end def encode(%{__struct__: _} = struct, options) do LexicalEncoder.Map.encode(Map.from_struct(struct), options) end def encode(value, _options) do raise LexicalEncodeError, value: value end end erlang-jose-1.10.1/lib/jose/jwe.ex0000644000232200023220000011225413605433351017207 0ustar debalancedebalancerequire Record defmodule JOSE.JWE do @moduledoc ~S""" JWE stands for JSON Web Encryption which is defined in [RFC 7516](https://tools.ietf.org/html/rfc7516). ## Key Derivation Algorithms The following key derivation algorithms for the `"alg"` field are currently supported by `JOSE.JWE` (some may need the `JOSE.crypto_fallback/1` option to be enabled): * `"A128GCMKW"` * `"A192GCMKW"` * `"A256GCMKW"` * `"A128KW"` * `"A192KW"` * `"A256KW"` * `"dir"` * `"ECDH-ES"` * `"ECDH-ES+A128GCMKW"` * `"ECDH-ES+A192GCMKW"` * `"ECDH-ES+A256GCMKW"` * `"ECDH-ES+A128KW"` * `"ECDH-ES+A192KW"` * `"ECDH-ES+A256KW"` * `"ECDH-ES+C20PKW"` * `"ECDH-ES+XC20PKW"` * `"PBES2-HS256+A128KW"` * `"PBES2-HS384+A192KW"` * `"PBES2-HS512+A256KW"` * `"RSA1_5"` * `"RSA-OAEP"` * `"RSA-OAEP-256"` ## Encryption Algorithms The following encryption algorithms for the `"enc"` field are currently supported by `JOSE.JWE` (some may need the `JOSE.crypto_fallback/1` option to be enabled): * `"A128CBC-HS256"` * `"A192CBC-HS384"` * `"A256CBC-HS512"` * `"A128GCM"` * `"A192GCM"` * `"A256GCM"` * `"C20P"` * `"XC20P"` ## Compression Algorithms The following compression algorithms for the `"zip"` field are currently supported by `JOSE.JWE`: * `"DEF"` ## Key Derivation Examples All of the examples below will use `"enc"` set to `"A128GCM"`, `"A192GCM"`, or `"A256GCM"` depending on the derived key size. The octet key used will typically be all zeroes of the required size in the form of `<<0::128>>` (for a 128-bit key). All of the example keys generated below can be found here: [https://gist.github.com/potatosalad/dd140560b2bdbdab886d](https://gist.github.com/potatosalad/dd140560b2bdbdab886d) # octet keys we'll use below jwk_oct128 = JOSE.JWK.from_oct(<<0::128>>) jwk_oct192 = JOSE.JWK.from_oct(<<0::192>>) jwk_oct256 = JOSE.JWK.from_oct(<<0::256>>) jwk_secret = JOSE.JWK.from_oct("secret") # EC keypairs we'll use below jwk_ec256_alice_sk = JOSE.JWK.generate_key({:ec, :secp256r1}) jwk_ec256_alice_pk = JOSE.JWK.to_public(jwk_ec256_alice_sk) jwk_ec256_bob_sk = JOSE.JWK.generate_key({:ec, :secp256r1}) jwk_ec256_bob_pk = JOSE.JWK.to_public(jwk_ec256_bob_sk) # X25519 keypairs we'll use below jwk_x25519_alice_sk = JOSE.JWK.generate_key({:okp, :X25519}) jwk_x25519_alice_pk = JOSE.JWK.to_public(jwk_x25519_alice_sk) jwk_x25519_bob_sk = JOSE.JWK.generate_key({:okp, :X25519}) jwk_x25519_bob_pk = JOSE.JWK.to_public(jwk_x25519_bob_sk) # X448 keypairs we'll use below jwk_x448_alice_sk = JOSE.JWK.generate_key({:okp, :X448}) jwk_x448_alice_pk = JOSE.JWK.to_public(jwk_x448_alice_sk) jwk_x448_bob_sk = JOSE.JWK.generate_key({:okp, :X448}) jwk_x448_bob_pk = JOSE.JWK.to_public(jwk_x448_bob_sk) # RSA keypairs we'll use below jwk_rsa_sk = JOSE.JWK.generate_key({:rsa, 4096}) jwk_rsa_pk = JOSE.JWK.to_public(jwk_rsa_sk) ### A128GCMKW, A192GCMKW, and A256GCMKW # A128GCMKW iex> encrypted_a128gcmkw = JOSE.JWE.block_encrypt(jwk_oct128, "{}", %{ "alg" => "A128GCMKW", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJBMTI4R0NNS1ciLCJlbmMiOiJBMTI4R0NNIiwiaXYiOiJzODNFNjhPNjhsWlM5ZVprIiwidGFnIjoieF9Ea2M5dm1LMk5RQV8tU2hvTkFRdyJ9.8B2qX8fVEa-s61RsZXqkCg.J7yJ8sKLbUlzyor6.FRs.BhBwImTv9B14NwVuxmfU6A" iex> JOSE.JWE.block_decrypt(jwk_oct128, encrypted_a128gcmkw) |> elem(0) "{}" # A192GCMKW iex> encrypted_a192gcmkw = JOSE.JWE.block_encrypt(jwk_oct192, "{}", %{ "alg" => "A192GCMKW", "enc" => "A192GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJBMTkyR0NNS1ciLCJlbmMiOiJBMTkyR0NNIiwiaXYiOiIxMkduZWQyTDB6NE5LZG83IiwidGFnIjoiM0thbG9iaER1Wmx5dE1YSjhjcXhZZyJ9.jJC4E1c6augIhvGDp3fquRfO-mnnud4F.S2NkKNGxBKTsCnKo.gZA.MvfhqSTeEN75H8HDyvfzRQ" iex> JOSE.JWE.block_decrypt(jwk_oct192, encrypted_a192gcmkw) |> elem(0) "{}" # A256GCMKW iex> encrypted_a256gcmkw = JOSE.JWE.block_encrypt(jwk_oct256, "{}", %{ "alg" => "A256GCMKW", "enc" => "A256GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJBMjU2R0NNS1ciLCJlbmMiOiJBMjU2R0NNIiwiaXYiOiJHU3lFMTBLQURxZTczNUMzIiwidGFnIjoiR3dVbDJCbXRNWlVseDlXNEMtY0tQZyJ9.sSsbFw9z8WTkzBLvPMywSedTXXygFxfP9g5U2qpzUX8.eiVFfe7iojfK0AXb._v8.YVfk9dNrtS7wxbGqCVge-g" iex> JOSE.JWE.block_decrypt(jwk_oct256, encrypted_a256gcmkw) |> elem(0) "{}" ### A128KW, A192KW, and A256KW # A128KW iex> encrypted_a128kw = JOSE.JWE.block_encrypt(jwk_oct128, "{}", %{ "alg" => "A128KW", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0.t4_Fb4kCl6BcS1cXnR4P4Xgm-jwVNsFl.RerKfWjzqqtLIUrz.JmE.ZDpVlWo-aQYM5la9eshwWw" iex> JOSE.JWE.block_decrypt(jwk_oct128, encrypted_a128kw) |> elem(0) "{}" # A192KW iex> encrypted_a192kw = JOSE.JWE.block_encrypt(jwk_oct192, "{}", %{ "alg" => "A192KW", "enc" => "A192GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJBMTkyS1ciLCJlbmMiOiJBMTkyR0NNIn0.edpvNrztlNADbkwfq5YBJgqFBSH_Znv1Y1uXKNQ_13w.yCkEYTCPOKH6CoxZ.siw.zP_ZM9OEeX1FIdFjqNawtQ" iex> JOSE.JWE.block_decrypt(jwk_oct192, encrypted_a192kw) |> elem(0) "{}" # A256KW iex> encrypted_a256kw = JOSE.JWE.block_encrypt(jwk_oct256, "{}", %{ "alg" => "A256KW", "enc" => "A256GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2R0NNIn0.OvAhC1a2BoP_2SMIiZXwIHWPoIkD-Cosgp3nlpiTs8ySUBPfPzwG1g.4GeackYJbuBksAWA.HPE.vG0sGC2kuklH5xk8KXhyNA" iex> JOSE.JWE.block_decrypt(jwk_oct256, encrypted_a256kw) |> elem(0) "{}" ### dir The `"dir"` key derivation algorithm is essentially just a pass-through to the underlying `"enc"` algorithm. The `"encrypted_key"` is not included in the protected header, so the key must be fully known by both parties. # dir iex> encrypted_dir = JOSE.JWE.block_encrypt(jwk_oct128, "{}", %{ "alg" => "dir", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..HdRR8O0kk_SvOjAS.rxo.JTMPGPKZZKVNlWV0RexsmQ" iex> JOSE.JWE.block_decrypt(jwk_oct128, encrypted_dir) |> elem(0) "{}" ### ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, and ECDH-ES+A256KW The `"ECDH-ES"` key derivation algorithm does not include the `"encrypted_key"` field in the protected header, similar to how `"dir"` functions. The size of the generated key is dependent on the `"enc"` setting (for example, `"A128GCM"` will generate a 128-bit key, `"A256GCM"` a 256-bit key, etc). # ECDH-ES with EC keypairs iex> encrypted_ecdhes_ec256_alice2bob = JOSE.JWE.block_encrypt({jwk_ec256_bob_pk, jwk_ec256_alice_sk}, "{}", %{ "alg" => "ECDH-ES", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjQ4UVUzUTBDeVN4d0piRXdXckpyWVhscDg4X2RWcEhUeHE0YXZjNjZoNVEiLCJ5IjoiWnpxcklOdE1NeEh4US1RQjcyUk1jZGxtRHNPSXdsS2hNcVZtX2dZV0MxNCJ9fQ..UssNrY5qEeFdluZY.R6g.32nlr0wHF2TwfL1UnBtIow" iex> JOSE.JWE.block_decrypt({jwk_ec256_alice_pk, jwk_ec256_bob_sk}, encrypted_ecdhes_ec256_alice2bob) |> elem(0) "{}" # ECDH-ES with X25519 keypairs iex> encrypted_ecdhes_x25519_alice2bob = JOSE.JWE.block_encrypt({jwk_x25519_bob_pk, jwk_x25519_alice_sk}, "{}", %{ "alg" => "ECDH-ES", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJjcnYiOiJYMjU1MTkiLCJrdHkiOiJPS1AiLCJ4IjoiZ0g3TjJwT0duenZfd0tBLUhqREZKTlVSZVhfdG05XzdiMkZSUjI3cXFYcyJ9fQ..T-0q42FPCUy3hlla.MHU.9TNP2jG5bN1vSvaesijdww" iex> JOSE.JWE.block_decrypt({jwk_x25519_alice_pk, jwk_x25519_bob_sk}, encrypted_ecdhes_x25519_alice2bob) |> elem(0) "{}" # ECDH-ES with X448 keypairs iex> encrypted_ecdhes_x448_alice2bob = JOSE.JWE.block_encrypt({jwk_x448_bob_pk, jwk_x448_alice_sk}, "{}", %{ "alg" => "ECDH-ES", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOEdDTSIsImVwayI6eyJjcnYiOiJYNDQ4Iiwia3R5IjoiT0tQIiwieCI6ImFFaHZISGxFM2V1Y3lsY0RNNzBMd1paY2dDRk9acXExNWM3YXZNMjJkcWZIUEtja1FZNmo3LXFfM19kMGI1cGVWZEFoNVoyQWZIWSJ9fQ..T-UNE-wOApuRH71r.Uj8.l8bIfhC1UPAPVWBV3wkc6A" iex> JOSE.JWE.block_decrypt({jwk_x448_alice_pk, jwk_x448_bob_sk}, encrypted_ecdhes_x448_alice2bob) |> elem(0) "{}" When decrypting with any of the `"ECDH-ES"` related algorithms, the other party's public key is recommended, but not required for decryption (the embedded Ephemeral Public Key will be used instead): # decrypting the X448 example with and without the public key specified iex> JOSE.JWE.block_decrypt({jwk_x448_alice_pk, jwk_x448_bob_sk}, encrypted_ecdhes_x448_alice2bob) |> elem(0) "{}" iex> JOSE.JWE.block_decrypt(jwk_x448_bob_sk, encrypted_ecdhes_x448_alice2bob) |> elem(0) "{}" The `"ECDH-ES+A128KW"`, `"ECDH-ES+A192KW"`, and `"ECDH-ES+A256KW"` key derivation algorithms do include the `"encrypted_key"` and the suffix after `"ECDH-ES+"` determines the key size (so `"ECDH-ES+A128KW"` computes a 128-bit key). # ECDH-ES+A128KW with EC keypairs iex> encrypted_ecdhesa128kw_alice2bob = JOSE.JWE.block_encrypt({jwk_ec256_bob_pk, jwk_ec256_alice_sk}, "{}", %{ "alg" => "ECDH-ES+A128KW", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhHQ00iLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiI0OFFVM1EwQ3lTeHdKYkV3V3JKcllYbHA4OF9kVnBIVHhxNGF2YzY2aDVRIiwieSI6Ilp6cXJJTnRNTXhIeFEtUUI3MlJNY2RsbURzT0l3bEtoTXFWbV9nWVdDMTQifX0.ZwuqXf7svd3SH0M-XYLjWz5JsN6xX03C.l8tt83EJjy86IovL.i5A.nw05dPUA0a18xdtvmHbhHA" iex> JOSE.JWE.block_decrypt({jwk_ec256_alice_pk, jwk_ec256_bob_sk}, encrypted_ecdhesa128kw_alice2bob) |> elem(0) "{}" # ECDH-ES+A192KW with EC keypairs iex> encrypted_ecdhesa192kw_alice2bob = JOSE.JWE.block_encrypt({jwk_ec256_bob_pk, jwk_ec256_alice_sk}, "{}", %{ "alg" => "ECDH-ES+A192KW", "enc" => "A192GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExOTJHQ00iLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiI0OFFVM1EwQ3lTeHdKYkV3V3JKcllYbHA4OF9kVnBIVHhxNGF2YzY2aDVRIiwieSI6Ilp6cXJJTnRNTXhIeFEtUUI3MlJNY2RsbURzT0l3bEtoTXFWbV9nWVdDMTQifX0.S9LZ1i_Lua_if4I83WcaCQ9yT5qqPI_NhCFR7tMiZDQ.kG3taKEjGeKDRTzs.H1s.oVGBFP63z4gd3e-R2d1cmA" iex> JOSE.JWE.block_decrypt({jwk_ec256_alice_pk, jwk_ec256_bob_sk}, encrypted_ecdhesa192kw_alice2bob) |> elem(0) "{}" # ECDH-ES+A256KW with EC keypairs iex> encrypted_ecdhesa256kw_alice2bob = JOSE.JWE.block_encrypt({jwk_ec256_bob_pk, jwk_ec256_alice_sk}, "{}", %{ "alg" => "ECDH-ES+A256KW", "enc" => "A256GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkEyNTZHQ00iLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiI0OFFVM1EwQ3lTeHdKYkV3V3JKcllYbHA4OF9kVnBIVHhxNGF2YzY2aDVRIiwieSI6Ilp6cXJJTnRNTXhIeFEtUUI3MlJNY2RsbURzT0l3bEtoTXFWbV9nWVdDMTQifX0.4KWy1-vRiJyNINF6mWYbUPPTVNG9ADfvvfpSDbddPTftz7GmUHUsuQ.IkRhtGH23R-9dFF3.9yk.RnALhnqWMHWCZFxqc-DU4A" iex> JOSE.JWE.block_decrypt({jwk_ec256_alice_pk, jwk_ec256_bob_sk}, encrypted_ecdhesa256kw_alice2bob) |> elem(0) "{}" See `JOSE.JWK.box_encrypt/2` for generating an Ephemeral Public Key based on the same curve as the supplied other party key in the same step. ### PBES2-HS256+A128KW, PBES2-HS384+A192KW, and PBES2-HS512+A256KW # PBES2-HS256+A128KW iex> encrypted_pbes2hs256a128kw = JOSE.JWE.block_encrypt(jwk_secret, "{}", %{ "alg" => "PBES2-HS256+A128KW", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjo0MDk2LCJwMnMiOiJRR0laNTlzbjRnQThySHBWYjFrSkd3In0.8WMQ0fysLiHU8AjpjkcqJGpYe53VRf2s.vVEb2ZtKmtPIw8M-.Cmg.GCjDtdKV6khqEuyZy2gUxw" iex> JOSE.JWE.block_decrypt(jwk_secret, encrypted_pbes2hs256a128kw) |> elem(0) "{}" # PBES2-HS384+A192KW iex> encrypted_pbes2hs384a192kw = JOSE.JWE.block_encrypt(jwk_secret, "{}", %{ "alg" => "PBES2-HS384+A192KW", "enc" => "A192GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJQQkVTMi1IUzM4NCtBMTkyS1ciLCJlbmMiOiJBMTkyR0NNIiwicDJjIjo2MTQ0LCJwMnMiOiJKSDRjZ0hlNTZiU0prZ1d6VktpWWJCb0FzWEJBY1A1NiJ9.Ck5GvgXxmyac3jzs0lRavoRh6tI9nEs3lYkx8sdDzGw.IdxaPATMkQ8FYiYQ.uHk.rDU6ltWsTsw9vuvA73bgJQ" iex> JOSE.JWE.block_decrypt(jwk_secret, encrypted_pbes2hs384a192kw) |> elem(0) "{}" # PBES2-HS512+A256KW iex> encrypted_pbes2hs512a256kw = JOSE.JWE.block_encrypt(jwk_secret, "{}", %{ "alg" => "PBES2-HS512+A256KW", "enc" => "A256GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJlbmMiOiJBMjU2R0NNIiwicDJjIjo4MTkyLCJwMnMiOiJ6YWRiMVNmT1F4V1gyTHJrSVgwWDFGM2QzNlBIdUdxRVFzUDVhbWVnTk00In0.6SUVO9sSevqZrZ5yPX-JvJNJrzfIQeTTzrkWBHEqHra1_AITtwEe0A.0AaF_3ZlJOkRlqgb.W8I.jFWob73QTn52IFSIPEWHFA" iex> JOSE.JWE.block_decrypt(jwk_secret, encrypted_pbes2hs512a256kw) |> elem(0) "{}" The `"p2s"` and `"p2i"` fields may also be specified to control the Salt and Iterations of the PBES2 Key Derivation Function, respectively. The default Salt is a randomly generated binary the same length of bytes as the key wrap (for example, `"PBES2-HS256+A128KW"` will generate a 16-byte Salt). The default Iterations is 32 times the number of bits specified by the key wrap (for example, `"PBES2-HS256+A128KW"` will have 4096 Iterations). # let's setup the JWE header iterations = 8192 salt = <<0::256>> # all zero salt, for example usage only jwe = %{ "alg" => "PBES2-HS256+A128KW", "enc" => "A128GCM", "p2i" => iterations, "p2s" => :jose_base64url.encode(salt) } # PBES2-HS256+A128KW iex> encrypted_pbes2 = JOSE.JWE.block_encrypt(jwk_secret, "{}", jwe) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjo0MDk2LCJwMmkiOjgxOTIsInAycyI6IkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEifQ.I7wcBmg7O_rOWpg1aak7wQWX84YtED6k.Rgh3f6Kzl5SZ1z7x.FNo.eyK1ySx4SGR-xC2EYNySQA" iex> JOSE.JWE.block_decrypt(jwk_secret, encrypted_pbes2) |> elem(0) "{}" ### RSA1_5, RSA-OAEP, and RSA-OAEP-256 # RSA1_5 iex> encrypted_rsa1_5 = JOSE.JWE.block_encrypt(jwk_rsa_pk, "{}", %{ "alg" => "RSA1_5", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4R0NNIn0.NlndPTqULN1vArshEzfEXY0nHCf4ubsTK9iHAeIxL85fReYrYG8EDB2_IirUneavvHSa-hsVLXNzBu0F9OY3TRFAIuJ8Jt1tqZZEhHZ97vzTEIjdlPNctGNI11-mhNCJ0doSvx9T4ByngaAFtJnRoR2cqbJkJFGja60fHtO0CfKLW5XzPf0NAhr8Tof-5IJfbNpMcC_LdCItJ6i8cuj4i5pG_CikOKDrNzbaBP72200_kl_-YaLDMA4tVb2YjWksY5Vau0Hz16QvI9QwDIcIDLYPAlTlDrU7s_FfmO_89S9Z69-lc_OBG7x2CYzIhB-0wzx753nZRl_WNJKi1Ya_AV552FEqVUhR-SuKcyrTA9OwkKC2JoL3lFqsCL9jkZkBrVREQlT0cxNI_AInyx5FHNLBbdtkz0JQbvzMJ854RP0V_eTlI5u8DZ42aOTRMBLHPi-4gP0J_CGWyKDQreXEEF6LSuLJb1cGk-NX1Vd85aARstQPuOoy7pWJjPvBEKEib70fjkUuMA0Atid-5BusQLKc1H-D6c5HIFH0DgYtXhN6AtQ_fmqw1F_X1JrGnYiYGzJCD2hh0Yt2UJZoCuHlPKk8aM5L3lNU3AISb1soSQl3hfX8Skb817ffC7jYezdhZc12cRNzOPAYqJYjN2eDlQhx-gpFjVzc-W1bFG8Yijo.grliT3M1iZ48aSY9.F4Y.pBRqIGZ4Q_fI1kmeAggvRg" iex> JOSE.JWE.block_decrypt(jwk_rsa_sk, encrypted_rsa1_5) |> elem(0) "{}" # RSA-OAEP iex> encrypted_rsaoaep = JOSE.JWE.block_encrypt(jwk_rsa_pk, "{}", %{ "alg" => "RSA-OAEP", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.YZfGKTTU2KuvwIMpSYadbNmGzWIbLrwRYD8JvZAWkvcnFeky09S04VadRNPXmCBSl4EF1K7oBm0fiYXuvNbLFNKYT_Jo_y6Lb-XsP--BZKaEcq6wIdZ4-xTJ7YYX5dfco_cMknZLG8W2sQRwtWopisn9NyzSpfGNlYqeJqjpoJy0qnO8yZeEYeadwoVF9-XZfYwvMjEt7HORqBIPF1JIaOYTQ-LQBvya6XYhOR7dkSnuCZ_ITGW5ZbPvzOILSMW_3Ixe78ncfO2gxF6AiLh02oTLsOSrF9xDlJvuU0k1TdkNWtGroeP_WVbXEO7O_GI5LVW-cDzoVm5ZCQs2Df0018-qDxFyY9xhKS9aNDi_btiarstXMSz3EkOfPhWR_IzlVyUkYnzs3GS993gKLQ0Tk-ipvOT9Bcw9VTLLK3-f5YSkf51IA---hPFlxVlboH9bmTXlT4JzSbErQEYp3JuXjOP7FQn0OPko5Utqbbm41XBEJhUpBNhjrBGDspsMxML_eJdyzBgA5UyNfdCEQ2vM1pCegxG_hSKAhCKVNn71wW4O_y_eqUcoyhjB7HtVxiF29jzNUKF-y14171L4-mxsIpixaM1ofnayWMiherVP0Wz2MXkzWB0AUv8c3kNEJIh3oeyrczWwzpmeCh1Bq7-J4D6aaFjyGFcm-03_QZmfwho.ymxveKBeRuaZ8HzD.3H4.6oKLh2NouhPGpO1dmA-tTg" iex> JOSE.JWE.block_decrypt(jwk_rsa_sk, encrypted_rsaoaep) |> elem(0) "{}" # RSA-OAEP-256 iex> encrypted_rsaoaep256 = JOSE.JWE.block_encrypt(jwk_rsa_pk, "{}", %{ "alg" => "RSA-OAEP-256", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIn0.OW9Hy9qpOIgVueODQXcWIUw_-Sm3UFGtxosyOAaI6JUQFt8q-iEtKkUp4NHrOlczO6tP5t8zRKdNXFfCm9QZk6F9PsSO-NzE2-DV1ANAMck-CDfGTK0mwG5U_KZwlObSgU0gxf87K49Wuno1rWlHWzJb__C_hCJXi_aQW17tLmbuTpJMkB0NTCKX3y6QaxvynP98jqwMJT6uGmE3AeuZYhPGzAOWbltbWyw-TqWqyLJirAUY_fvDNsKt1TDrTd9216TK5y7RQeUtdGfbuYK9lt2TIwfh9ycAHd7SANH_YJc2cKYa3e6CgqnQAjVpbhpogBz5sz5HaK95XYbXOdnYyHQ00gS44YquiQCvX331UgEWnthtmYwDZfnCxTkPydafGOBsjaagGvV2tQtxUKW3JmVChF97bNj5lQZ7rAkyooxx-k3IMT0005x6_74O5tXGN5fb7oyT3Mx_NZ5dKzlYAA_V8oOpNslaFhV5K5Q_-hRkUsEPWdaD5s2uS9Z7l7ot39CzzTKDj65f2eCTWFReFKOjhabCL4ZiFXbElB3dA3y5FdxXPAfe6N31G9ynalx1JIcrEaRb8sdqk6U6uC3s3DpkoRSnp3osBJOxxuk_Lgb-ZM9d8UuRVj4W78-qjfX_lcG1RlRmlYoDIU03ly0UfRWi-7HmpPECrGTsGZEfULg.J-txckmMXEi-bZVh.Rbw.D7UpSkticmDCGiNyLVggLg" iex> JOSE.JWE.block_decrypt(jwk_rsa_sk, encrypted_rsaoaep256) |> elem(0) "{}" ## Encryption Examples All of the examples below will use `"alg"` set to `"dir"` passing the key directly to the Encryption Algorithm. The octet key used will typically be all zeroes of the required size in the form of `<<0::128>>` (for a 128-bit key). All of the example keys generated below can be found here: [https://gist.github.com/potatosalad/dd140560b2bdbdab886d](https://gist.github.com/potatosalad/dd140560b2bdbdab886d) # octet keys we'll use below jwk_oct128 = JOSE.JWK.from_oct(<<0::128>>) jwk_oct192 = JOSE.JWK.from_oct(<<0::192>>) jwk_oct256 = JOSE.JWK.from_oct(<<0::256>>) jwk_oct384 = JOSE.JWK.from_oct(<<0::384>>) jwk_oct512 = JOSE.JWK.from_oct(<<0::512>>) ### A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 # A128CBC-HS256 iex> encrypted_a128cbchs256 = JOSE.JWE.block_encrypt(jwk_oct256, "{}", %{ "alg" => "dir", "enc" => "A128CBC-HS256" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..bxps64-UIQoFvhkjr05e9A.HrtJ3AqrqJ4f5PHjGseHYw.kopJoTDxk34IVhheoToLSA" iex> JOSE.JWE.block_decrypt(jwk_oct256, encrypted_a128cbchs256) |> elem(0) "{}" # A192CBC-HS384 iex> encrypted_a192cbchs384 = JOSE.JWE.block_encrypt(jwk_oct384, "{}", %{ "alg" => "dir", "enc" => "A192CBC-HS384" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0In0..3zSCHwvHrcxsNyssIgEBRA.XB70tUoQZlnOgY5ygMxfKA.Avl7Z8jCpShh3_iTcPcU3Woh6E9ykNyB" iex> JOSE.JWE.block_decrypt(jwk_oct384, encrypted_a192cbchs384) |> elem(0) "{}" # A256CBC-HS512 iex> encrypted_a256cbchs512 = JOSE.JWE.block_encrypt(jwk_oct512, "{}", %{ "alg" => "dir", "enc" => "A256CBC-HS512" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0..mqMhkWAMF7HmW_Nu1ERUzQ.bzd-tmykuru0Lu_rsNZ2ow.mlOFO8JcC_UJ35TsZgiUeEwAjRDs6cwfN7Umyzm7mmY" iex> JOSE.JWE.block_decrypt(jwk_oct512, encrypted_a256cbchs512) |> elem(0) "{}" ### A128GCM, A192GCM, and A256GCM # A128GCM iex> encrypted_a128gcm = JOSE.JWE.block_encrypt(jwk_oct128, "{}", %{ "alg" => "dir", "enc" => "A128GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..pPF4SbzGZwxS1J-M.Ic0.qkHuC-hOO44HPlykBJLSsA" iex> JOSE.JWE.block_decrypt(jwk_oct128, encrypted_a128gcm) |> elem(0) "{}" # A192GCM iex> encrypted_a192gcm = JOSE.JWE.block_encrypt(jwk_oct192, "{}", %{ "alg" => "dir", "enc" => "A192GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTkyR0NNIn0..muNgk2GFW9ATwqqZ.bvE.gYvC0G6DAodJdyrUqLw7Iw" iex> JOSE.JWE.block_decrypt(jwk_oct192, encrypted_a192gcm) |> elem(0) "{}" # A256GCM iex> encrypted_a256gcm = JOSE.JWE.block_encrypt(jwk_oct256, "{}", %{ "alg" => "dir", "enc" => "A256GCM" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..rDTJhd5ja5pDAYtn.PrM.MQdLgiVXQsG_cLas93ZEHw" iex> JOSE.JWE.block_decrypt(jwk_oct256, encrypted_a256gcm) |> elem(0) "{}" ### ChaCha20/Poly1305 and XChaCha20/Poly1305 This is experimental and based on [RFC 7539](https://tools.ietf.org/html/rfc7539) and [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01). # C20P iex> encrypted_c20p = JOSE.JWE.block_encrypt(jwk_oct256, "{}", %{ "alg" => "dir", "enc" => "C20P" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJDMjBQIn0..W3qFkCKCEJz5H5jt.Hag.2TUFobBK_TYdtC2auoiiKA" iex> JOSE.JWE.block_decrypt(jwk_oct256, encrypted_c20p) |> elem(0) "{}" # XC20P iex> encrypted_xc20p = JOSE.JWE.block_encrypt(jwk_oct256, "{}", %{ "alg" => "dir", "enc" => "XC20P" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJYQzIwUCJ9..aMrioLxn-KO8Dyy8LcYD2mSNY7yPE_yf.Wxg.PJgIuI0ZADBE6Gi5-f7Tfg" iex> JOSE.JWE.block_decrypt(jwk_oct256, encrypted_xc20p) |> elem(0) "{}" ## Compression Examples All of the examples below will use `"alg"` set to `"dir"` passing the key directly to the Encryption Algorithm (`"enc"` is set to `"A128GCM"`). The octet key used will typically be all zeroes of the required size in the form of `<<0::128>>` (for a 128-bit key). All of the example keys generated below can be found here: [https://gist.github.com/potatosalad/dd140560b2bdbdab886d](https://gist.github.com/potatosalad/dd140560b2bdbdab886d) # octet keys we'll use below jwk_oct128 = JOSE.JWK.from_oct(<<0::128>>) ### DEF # DEF iex> encrypted_def = JOSE.JWE.block_encrypt(jwk_oct128, "{}", %{ "alg" => "dir", "enc" => "A128GCM", "zip" => "DEF" }) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0..Vvr0vlKWE9rAJ8CR.UpOz7w10Uc9pMg.Pctxzz0ijPSOY8zyRcbjww" iex> JOSE.JWE.block_decrypt(jwk_oct128, encrypted_def) |> elem(0) "{}" """ record = Record.extract(:jose_jwe, from_lib: "jose/include/jose_jwe.hrl") keys = :lists.map(&elem(&1, 0), record) vals = :lists.map(&{&1, [], nil}, keys) pairs = :lists.zip(keys, vals) defstruct keys @type t :: %__MODULE__{} @doc """ Converts a `JOSE.JWE` struct to a `:jose_jwe` record. """ def to_record(%JOSE.JWE{unquote_splicing(pairs)}) do {:jose_jwe, unquote_splicing(vals)} end def to_record(list) when is_list(list), do: for(element <- list, into: [], do: to_record(element)) @doc """ Converts a `:jose_jwe` record into a `JOSE.JWE`. """ def from_record(jose_jwe) def from_record({:jose_jwe, unquote_splicing(vals)}) do %JOSE.JWE{unquote_splicing(pairs)} end def from_record(list) when is_list(list), do: for(element <- list, into: [], do: from_record(element)) ## Decode API @doc """ Converts a binary or map into a `JOSE.JWE`. iex> JOSE.JWE.from(%{ "alg" => "dir" }) %JOSE.JWE{alg: {:jose_jwe_alg_dir, :dir}, enc: :undefined, fields: %{}, zip: :undefined} iex> JOSE.JWE.from("{\"alg\":\"dir\"}") %JOSE.JWE{alg: {:jose_jwe_alg_dir, :dir}, enc: :undefined, fields: %{}, zip: :undefined} There are 3 keys which can have custom modules defined for them: * `"alg"` - must implement `:jose_jwe` and `:jose_jwe_alg` behaviours * `"enc"` - must implement `:jose_jwe` and `:jose_jwe_enc` behaviours * `"zip"` - must implement `:jose_jwe` and `:jose_jwe_zip` behaviours For example: iex> JOSE.JWE.from({%{ zip: MyCustomCompress }, %{ "alg" => "dir", "zip" => "custom" }}) %JOSE.JWE{alg: {:jose_jwe_alg_dir, :dir}, enc: :undefined, fields: %{}, zip: {MyCustomCompress, :state}} """ def from(list) when is_list(list), do: for(element <- list, into: [], do: from(element)) def from(jwe = %JOSE.JWE{}), do: from(to_record(jwe)) def from(any), do: :jose_jwe.from(any) |> from_record() @doc """ Converts a binary into a `JOSE.JWE`. """ def from_binary(list) when is_list(list), do: for(element <- list, into: [], do: from_binary(element)) def from_binary(binary), do: :jose_jwe.from_binary(binary) |> from_record() @doc """ Reads file and calls `from_binary/1` to convert into a `JOSE.JWE`. """ def from_file(file), do: :jose_jwe.from_file(file) |> from_record() @doc """ Converts a map into a `JOSE.JWE`. """ def from_map(list) when is_list(list), do: for(element <- list, into: [], do: from_map(element)) def from_map(map), do: :jose_jwe.from_map(map) |> from_record() ## Encode API @doc """ Converts a `JOSE.JWE` into a binary. """ def to_binary(list) when is_list(list), do: for(element <- list, into: [], do: to_binary(element)) def to_binary(jwe = %JOSE.JWE{}), do: to_binary(to_record(jwe)) def to_binary(any), do: :jose_jwe.to_binary(any) @doc """ Calls `to_binary/1` on a `JOSE.JWE` and then writes the binary to file. """ def to_file(file, jwe = %JOSE.JWE{}), do: to_file(file, to_record(jwe)) def to_file(file, any), do: :jose_jwe.to_file(file, any) @doc """ Converts a `JOSE.JWE` into a map. """ def to_map(list) when is_list(list), do: for(element <- list, into: [], do: to_map(element)) def to_map(jwe = %JOSE.JWE{}), do: to_map(to_record(jwe)) def to_map(any), do: :jose_jwe.to_map(any) ## API @doc """ Decrypts the `encrypted` binary or map using the `jwk`. iex> jwk = JOSE.JWK.from(%{"k" => "STlqtIOhWJjoVnYjUjxFLZ6oN1oB70QARGSTWQ_5XgM", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<73, 57, 106, 180, 131, 161, 88, 152, 232, 86, 118, 35, 82, 60, 69, 45, 158, 168, 55, 90, 1, 239, 68, 0, 68, 100, 147, 89, 15, 249, 94, 3>>}} iex> JOSE.JWE.block_decrypt(jwk, "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..jBt5tTa1Q0N3uFPEkf30MQ.Ei49MvTLLje7bsZ5EZCZMA.gMWOAmhZSq9ksHCZm6VSoA") {"{}", %JOSE.JWE{alg: {:jose_jwe_alg_dir, :dir}, enc: {:jose_jwe_enc_aes, {:jose_jwe_enc_aes, {:aes_cbc, 128}, 256, 32, 16, 16, 16, 16, :sha256}}, fields: %{}, zip: :undefined}} See `block_encrypt/2`. """ def block_decrypt(jwk = %JOSE.JWK{}, encrypted), do: block_decrypt(JOSE.JWK.to_record(jwk), encrypted) def block_decrypt({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, encrypted), do: block_decrypt({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, encrypted) def block_decrypt({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, encrypted), do: block_decrypt({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, encrypted) def block_decrypt(jwk, encrypted) do case :jose_jwe.block_decrypt(jwk, encrypted) do {plain_text, jwe} when is_tuple(jwe) -> {plain_text, from_record(jwe)} error -> error end end @doc """ Encrypts `plain_text` using the `jwk` and algorithm specified by the `jwe` by getting the `cek` for `block_encrypt/4`. """ def block_encrypt(jwk = %JOSE.JWK{}, plain_text, jwe), do: block_encrypt(JOSE.JWK.to_record(jwk), plain_text, jwe) def block_encrypt({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, plain_text, jwe), do: block_encrypt({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, plain_text, jwe) def block_encrypt({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, plain_text, jwe), do: block_encrypt({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, plain_text, jwe) def block_encrypt(jwk, plain_text, jwe = %JOSE.JWE{}), do: block_encrypt(jwk, plain_text, to_record(jwe)) def block_encrypt(jwk, plain_text, jwe), do: :jose_jwe.block_encrypt(jwk, plain_text, jwe) @doc """ Encrypts `plain_text` using the `jwk`, `cek`, and algorithm specified by the `jwe` by getting the `iv` for `block_encrypt/5`. """ def block_encrypt(jwk = %JOSE.JWK{}, plain_text, cek, jwe), do: block_encrypt(JOSE.JWK.to_record(jwk), plain_text, cek, jwe) def block_encrypt({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, plain_text, cek, jwe), do: block_encrypt({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, plain_text, cek, jwe) def block_encrypt({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, plain_text, cek, jwe), do: block_encrypt({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, plain_text, cek, jwe) def block_encrypt(jwk, plain_text, cek, jwe = %JOSE.JWE{}), do: block_encrypt(jwk, plain_text, cek, to_record(jwe)) def block_encrypt(jwk, plain_text, cek, jwe), do: :jose_jwe.block_encrypt(jwk, plain_text, cek, jwe) @doc """ Encrypts the `plain_text` using the `jwk`, `cek`, `iv`, and algorithm specified by the `jwe`. iex> jwk = JOSE.JWK.from(%{"k" => "STlqtIOhWJjoVnYjUjxFLZ6oN1oB70QARGSTWQ_5XgM", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<73, 57, 106, 180, 131, 161, 88, 152, 232, 86, 118, 35, 82, 60, 69, 45, 158, 168, 55, 90, 1, 239, 68, 0, 68, 100, 147, 89, 15, 249, 94, 3>>}} iex> JOSE.JWE.block_encrypt(jwk, "{}", %{ "alg" => "dir", "enc" => "A128CBC-HS256" }) {%{alg: :jose_jwe_alg_dir, enc: :jose_jwe_enc_aes}, %{"ciphertext" => "Ei49MvTLLje7bsZ5EZCZMA", "encrypted_key" => "", "iv" => "jBt5tTa1Q0N3uFPEkf30MQ", "protected" => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0", "tag" => "gMWOAmhZSq9ksHCZm6VSoA"}} See `block_decrypt/2`. """ def block_encrypt(jwk = %JOSE.JWK{}, plain_text, cek, iv, jwe), do: block_encrypt(JOSE.JWK.to_record(jwk), plain_text, cek, iv, jwe) def block_encrypt({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, plain_text, cek, iv, jwe), do: block_encrypt({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, plain_text, cek, iv, jwe) def block_encrypt({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, plain_text, cek, iv, jwe), do: block_encrypt({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, plain_text, cek, iv, jwe) def block_encrypt(jwk, plain_text, cek, iv, jwe = %JOSE.JWE{}), do: block_encrypt(jwk, plain_text, cek, iv, to_record(jwe)) def block_encrypt(jwk, plain_text, cek, iv, jwe), do: :jose_jwe.block_encrypt(jwk, plain_text, cek, iv, jwe) @doc """ Compacts an expanded encrypted map into a binary. iex> JOSE.JWE.compact(%{"ciphertext" => "Ei49MvTLLje7bsZ5EZCZMA", "encrypted_key" => "", "iv" => "jBt5tTa1Q0N3uFPEkf30MQ", "protected" => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0", "tag" => "gMWOAmhZSq9ksHCZm6VSoA"}) {%{}, "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..jBt5tTa1Q0N3uFPEkf30MQ.Ei49MvTLLje7bsZ5EZCZMA.gMWOAmhZSq9ksHCZm6VSoA"} See `expand/1`. """ defdelegate compact(encrypted), to: :jose_jwe @doc """ Compresses the `plain_text` using the `"zip"` algorithm specified by the `jwe`. iex> JOSE.JWE.compress("{}", %{ "alg" => "dir", "zip" => "DEF" }) <<120, 156, 171, 174, 5, 0, 1, 117, 0, 249>> See `uncompress/2`. """ def compress(plain_text, jwe = %JOSE.JWE{}), do: compress(plain_text, to_record(jwe)) def compress(plain_text, jwe), do: :jose_jwe.compress(plain_text, jwe) @doc """ Expands a compacted encrypted binary into a map. iex> JOSE.JWE.expand("eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..jBt5tTa1Q0N3uFPEkf30MQ.Ei49MvTLLje7bsZ5EZCZMA.gMWOAmhZSq9ksHCZm6VSoA") {%{}, %{"ciphertext" => "Ei49MvTLLje7bsZ5EZCZMA", "encrypted_key" => "", "iv" => "jBt5tTa1Q0N3uFPEkf30MQ", "protected" => "eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0", "tag" => "gMWOAmhZSq9ksHCZm6VSoA"}} See `compact/1`. """ defdelegate expand(encrypted), to: :jose_jwe @doc """ Generates a new `JOSE.JWK` based on the algorithms of the specified `JOSE.JWE`. iex> JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A128GCM"}) %JOSE.JWK{fields: %{"alg" => "dir", "enc" => "A128GCM", "use" => "enc"}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<188, 156, 171, 224, 232, 231, 41, 250, 210, 117, 112, 219, 134, 218, 94, 50>>}} """ def generate_key(list) when is_list(list), do: for(element <- list, into: [], do: generate_key(element)) def generate_key(jwe = %JOSE.JWE{}), do: generate_key(to_record(jwe)) def generate_key(any), do: JOSE.JWK.from_record(:jose_jwe.generate_key(any)) @doc """ Decrypts the `encrypted_key` using the `jwk` and the `"alg"` and `"enc"` specified by the `jwe`. # let's define our jwk and encrypted_key jwk = JOSE.JWK.from(%{"k" => "idN_YyeYZqEE7BkpexhA2Q", "kty" => "oct"}) enc = <<27, 123, 126, 121, 56, 105, 105, 81, 140, 76, 30, 2, 14, 92, 231, 174, 203, 196, 110, 204, 57, 238, 248, 73>> iex> JOSE.JWE.key_decrypt(jwk, enc, %{ "alg" => "A128KW", "enc" => "A128CBC-HS256" }) <<134, 82, 15, 176, 181, 115, 173, 19, 13, 44, 189, 185, 187, 125, 28, 240>> See `key_encrypt/3`. """ def key_decrypt(jwk = %JOSE.JWK{}, encrypted_key, jwe), do: key_decrypt(JOSE.JWK.to_record(jwk), encrypted_key, jwe) def key_decrypt({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, encrypted_key, jwe), do: key_decrypt({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, encrypted_key, jwe) def key_decrypt({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, encrypted_key, jwe), do: key_decrypt({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, encrypted_key, jwe) def key_decrypt(jwk, encrypted_key, jwe = %JOSE.JWE{}), do: key_decrypt(jwk, encrypted_key, to_record(jwe)) def key_decrypt(jwk, encrypted_key, jwe), do: :jose_jwe.key_decrypt(jwk, encrypted_key, jwe) @doc """ Encrypts the `decrypted_key` using the `jwk` and the `"alg"` and `"enc"` specified by the `jwe`. # let's define our jwk and cek (or decrypted_key) jwk = JOSE.JWK.from(%{"k" => "idN_YyeYZqEE7BkpexhA2Q", "kty" => "oct"}) # JOSE.JWK.generate_key({:oct, 16}) cek = <<134, 82, 15, 176, 181, 115, 173, 19, 13, 44, 189, 185, 187, 125, 28, 240>> # :crypto.rand_bytes(16) iex> JOSE.JWE.key_encrypt(jwk, cek, %{ "alg" => "A128KW", "enc" => "A128CBC-HS256" }) {<<27, 123, 126, 121, 56, 105, 105, 81, 140, 76, 30, 2, 14, 92, 231, 174, 203, 196, 110, 204, 57, 238, 248, 73>>, %JOSE.JWE{alg: {:jose_jwe_alg_aes_kw, {:jose_jwe_alg_aes_kw, 128, false, :undefined, :undefined}}, enc: {:jose_jwe_enc_aes, {:jose_jwe_enc_aes, {:aes_cbc, 128}, 256, 32, 16, 16, 16, 16, :sha256}}, fields: %{}, zip: :undefined}} See `key_decrypt/3`. """ def key_encrypt(jwk = %JOSE.JWK{}, decrypted_key, jwe), do: key_encrypt(JOSE.JWK.to_record(jwk), decrypted_key, jwe) def key_encrypt({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, decrypted_key, jwe), do: key_encrypt({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, decrypted_key, jwe) def key_encrypt({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, decrypted_key, jwe), do: key_encrypt({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, decrypted_key, jwe) def key_encrypt(jwk, decrypted_key, jwe = %JOSE.JWE{}), do: key_encrypt(jwk, decrypted_key, to_record(jwe)) def key_encrypt(jwk, decrypted_key, jwe) do case :jose_jwe.key_encrypt(jwk, decrypted_key, jwe) do {encrypted_key, jwe} when is_tuple(jwe) -> {encrypted_key, from_record(jwe)} error -> error end end @doc """ Merges map on right into map on left. """ def merge(left = %JOSE.JWE{}, right), do: merge(left |> to_record, right) def merge(left, right = %JOSE.JWE{}), do: merge(left, right |> to_record) def merge(left, right), do: :jose_jwe.merge(left, right) |> from_record @doc """ Returns the next `cek` using the `jwk` and the `"alg"` and `"enc"` specified by the `jwe`. # let's define our jwk jwk = JOSE.JWK.from(%{"k" => "idN_YyeYZqEE7BkpexhA2Q", "kty" => "oct"}) # JOSE.JWK.generate_key({:oct, 16}) iex> JOSE.JWE.next_cek(jwk, %{ "alg" => "A128KW", "enc" => "A128CBC-HS256" }) <<37, 83, 139, 165, 44, 23, 163, 186, 255, 155, 183, 17, 220, 211, 80, 247, 239, 149, 194, 53, 134, 41, 254, 176, 0, 247, 66, 38, 217, 252, 82, 233>> # when using the "dir" algorithm, the jwk itself will be used iex> JOSE.JWE.next_cek(jwk, %{ "alg" => "dir", "enc" => "A128GCM" }) <<137, 211, 127, 99, 39, 152, 102, 161, 4, 236, 25, 41, 123, 24, 64, 217>> """ def next_cek(jwk = %JOSE.JWK{}, jwe), do: next_cek(JOSE.JWK.to_record(jwk), jwe) def next_cek({your_public_jwk = %JOSE.JWK{}, my_private_jwk}, jwe), do: next_cek({JOSE.JWK.to_record(your_public_jwk), my_private_jwk}, jwe) def next_cek({your_public_jwk, my_private_jwk = %JOSE.JWK{}}, jwe), do: next_cek({your_public_jwk, JOSE.JWK.to_record(my_private_jwk)}, jwe) def next_cek(jwk, jwe = %JOSE.JWE{}), do: next_cek(jwk, to_record(jwe)) def next_cek(jwk, jwe), do: :jose_jwe.next_cek(jwk, jwe) @doc """ Returns the next `iv` the `"alg"` and `"enc"` specified by the `jwe`. # typically just returns random bytes for the specified "enc" algorithm iex> bit_size(JOSE.JWE.next_iv(%{ "alg" => "dir", "enc" => "A128CBC-HS256" })) 128 iex> bit_size(JOSE.JWE.next_iv(%{ "alg" => "dir", "enc" => "A128GCM" })) 96 """ def next_iv(jwe = %JOSE.JWE{}), do: next_iv(to_record(jwe)) def next_iv(jwe), do: :jose_jwe.next_iv(jwe) @doc """ Uncompresses the `cipher_text` using the `"zip"` algorithm specified by the `jwe`. iex> JOSE.JWE.uncompress(<<120, 156, 171, 174, 5, 0, 1, 117, 0, 249>>, %{ "alg" => "dir", "zip" => "DEF" }) "{}" See `compress/2`. """ def uncompress(cipher_text, jwe = %JOSE.JWE{}), do: uncompress(cipher_text, to_record(jwe)) def uncompress(cipher_text, jwe), do: :jose_jwe.uncompress(cipher_text, jwe) end erlang-jose-1.10.1/lib/jose/poison.ex0000644000232200023220000000055213605433351017726 0ustar debalancedebalancedefmodule JOSE.Poison do alias JOSE.Poison.LexicalEncoder @spec lexical_encode!(LexicalEncoder.t(), LexicalEncoder.options()) :: iodata | no_return def lexical_encode!(value, options \\ %{}) do iodata = LexicalEncoder.encode(value, options) unless options[:iodata] do iodata |> IO.iodata_to_binary() else iodata end end end erlang-jose-1.10.1/lib/jose/jwk.ex0000644000232200023220000010761213605433351017217 0ustar debalancedebalancerequire Record defmodule JOSE.JWK do @moduledoc ~S""" JWK stands for JSON Web Key which is defined in [RFC 7517](https://tools.ietf.org/html/rfc7517). """ record = Record.extract(:jose_jwk, from_lib: "jose/include/jose_jwk.hrl") keys = :lists.map(&elem(&1, 0), record) vals = :lists.map(&{&1, [], nil}, keys) pairs = :lists.zip(keys, vals) defstruct keys @type t :: %__MODULE__{} @doc """ Converts a `JOSE.JWK` struct to a `:jose_jwk` record. """ def to_record(%JOSE.JWK{unquote_splicing(pairs)}) do {:jose_jwk, unquote_splicing(vals)} end def to_record(list) when is_list(list), do: for(element <- list, into: [], do: to_record(element)) @doc """ Converts a `:jose_jwk` record into a `JOSE.JWK`. """ def from_record(jose_jwk) def from_record({:jose_jwk, unquote_splicing(vals)}) do %JOSE.JWK{unquote_splicing(pairs)} end def from_record(list) when is_list(list), do: for(element <- list, into: [], do: from_record(element)) ## Decode API @doc """ Converts a binary or map into a `JOSE.JWK`. iex> JOSE.JWK.from(%{"k" => "", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, ""}} iex> JOSE.JWK.from("{\"k\":\"\",\"kty\":\"oct\"}") %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, ""}} The `"kty"` field may be overridden with a custom module that implements the `:jose_jwk` and `:jose_jwk_kty` behaviours. For example: iex> JOSE.JWK.from({%{ kty: MyCustomKey }, %{ "kty" => "custom" }}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {MyCustomKey, :state}} """ def from(list) when is_list(list), do: for(element <- list, into: [], do: from(element)) def from(jwk = %JOSE.JWK{}), do: from(to_record(jwk)) def from(any), do: :jose_jwk.from(any) |> from_record() @doc """ Decrypts an encrypted binary or map into a `JOSE.JWK` using the specified `password`. iex> JOSE.JWK.from("password", "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkExMjhHQ00iLCJwMmMiOjQwOTYsInAycyI6Im5OQ1ZNQUktNTU5UVFtbWRFcnBsZFEifQ.Ucye69ii4dxd1ykNFlJyBVeA6xeNu4aV.2pZ4nBoxBjmdrneS.boqwdFZVNAFHk1M5P6kPYgBUgGwW32QuKzHuFA.wL9Hy6dcE_DPkUW9s5iwKA") {%JOSE.JWE{alg: {:jose_jwe_alg_pbes2, {:jose_jwe_alg_pbes2, :sha256, 128, <<80, 66, 69, 83, 50, 45, 72, 83, 50, 53, 54, 43, 65, 49, 50, 56, 75, 87, 0, 156, 208, 149, 48, 2, 62, 231, 159, 80, 66, 105, 157, 18, 186, 101, 117>>, 4096}}, enc: {:jose_jwe_enc_aes, {:jose_jwe_enc_aes, {:aes_gcm, 128}, 128, 16, 12, :undefined, :undefined, :undefined, :undefined}}, fields: %{"cty" => "jwk+json"}, zip: :undefined}, %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, "secret"}}} """ def from(password, list) when is_list(list), do: for(element <- list, into: [], do: from(password, element)) def from(password, jwk = %JOSE.JWK{}), do: from(password, to_record(jwk)) def from(password, any), do: :jose_jwk.from(password, any) |> from_encrypted_record() @doc """ Converts a binary into a `JOSE.JWK`. """ def from_binary(list) when is_list(list), do: for(element <- list, into: [], do: from_binary(element)) def from_binary(binary), do: :jose_jwk.from_binary(binary) |> from_record() @doc """ Decrypts an encrypted binary into a `JOSE.JWK` using `password`. See `from/2`. """ def from_binary(password, list) when is_list(list), do: for(element <- list, into: [], do: from_binary(password, element)) def from_binary(password, binary), do: :jose_jwk.from_binary(password, binary) |> from_encrypted_record() @doc """ Converts a DER (Distinguished Encoding Rules) binary into a `JOSE.JWK`. """ def from_der(list) when is_list(list), do: for(element <- list, into: [], do: from_der(element)) def from_der(pem), do: :jose_jwk.from_der(pem) |> from_record() @doc """ Decrypts an encrypted DER (Distinguished Encoding Rules) binary into a `JOSE.JWK` using `password`. """ def from_der(password, list) when is_list(list), do: for(element <- list, into: [], do: from_der(password, element)) def from_der(password, pem), do: :jose_jwk.from_der(password, pem) |> from_record() @doc """ Reads file and calls `from_der/1` to convert into a `JOSE.JWK`. """ def from_der_file(file), do: :jose_jwk.from_der_file(file) |> from_record() @doc """ Reads encrypted file and calls `from_der/2` to convert into a `JOSE.JWK` using `password`. """ def from_der_file(password, file), do: :jose_jwk.from_der_file(password, file) |> from_record() @doc """ Reads file and calls `from_binary/1` to convert into a `JOSE.JWK`. """ def from_file(file), do: :jose_jwk.from_file(file) |> from_record() @doc """ Reads encrypted file and calls `from_binary/2` to convert into a `JOSE.JWK` using `password`. See `from/2`. """ def from_file(password, file), do: :jose_jwk.from_file(password, file) |> from_encrypted_record() @doc """ Converts Firebase certificate public keys into a map of `JOSE.JWK`. """ def from_firebase(any), do: :maps.fold(fn k, v, a -> :maps.put(k, from_record(v), a) end, %{}, :jose_jwk.from_firebase(any)) @doc """ Converts Erlang records for `:ECPrivateKey`, `:ECPublicKey`, `:RSAPrivateKey`, and `:RSAPublicKey` into a `JOSE.JWK`. """ def from_key(list) when is_list(list), do: for(element <- list, into: [], do: from_key(element)) def from_key(key), do: :jose_jwk.from_key(key) |> from_record() @doc """ Converts a map into a `JOSE.JWK`. """ def from_map(list) when is_list(list), do: for(element <- list, into: [], do: from_map(element)) def from_map(map), do: :jose_jwk.from_map(map) |> from_record() @doc """ Decrypts an encrypted map into a `JOSE.JWK` using `password`. See `from/2`. """ def from_map(password, list) when is_list(list), do: for(element <- list, into: [], do: from_map(password, element)) def from_map(password, map), do: :jose_jwk.from_map(password, map) |> from_encrypted_record() @doc """ Converts an arbitrary binary into a `JOSE.JWK` with `"kty"` of `"oct"`. """ def from_oct(list) when is_list(list), do: for(element <- list, into: [], do: from_oct(element)) def from_oct(oct), do: :jose_jwk.from_oct(oct) |> from_record() @doc """ Decrypts an encrypted arbitrary binary into a `JOSE.JWK` with `"kty"` of `"oct"` using `password`. See `from/2`. """ def from_oct(password, list) when is_list(list), do: for(element <- list, into: [], do: from_oct(password, element)) def from_oct(password, oct), do: :jose_jwk.from_oct(password, oct) |> from_encrypted_record() @doc """ Reads file and calls `from_oct/1` to convert into a `JOSE.JWK`. """ def from_oct_file(file), do: :jose_jwk.from_oct_file(file) |> from_record() @doc """ Reads encrypted file and calls `from_oct/2` to convert into a `JOSE.JWK` using `password`. See `from/2`. """ def from_oct_file(password, file), do: :jose_jwk.from_oct_file(password, file) |> from_encrypted_record() @doc """ Converts an octet key pair into a `JOSE.JWK` with `"kty"` of `"OKP"`. """ def from_okp(list) when is_list(list), do: for(element <- list, into: [], do: from_okp(element)) def from_okp(okp), do: :jose_jwk.from_okp(okp) |> from_record() @doc """ Converts an openssh key into a `JOSE.JWK` with `"kty"` of `"OKP"`. """ def from_openssh_key(list) when is_list(list), do: for(element <- list, into: [], do: from_openssh_key(element)) def from_openssh_key(openssh_key), do: :jose_jwk.from_openssh_key(openssh_key) |> from_record() @doc """ Reads file and calls `from_openssh_key/1` to convert into a `JOSE.JWK`. """ def from_openssh_key_file(file), do: :jose_jwk.from_openssh_key_file(file) |> from_record() @doc """ Converts a PEM (Privacy Enhanced Email) binary into a `JOSE.JWK`. """ def from_pem(list) when is_list(list), do: for(element <- list, into: [], do: from_pem(element)) def from_pem(pem), do: :jose_jwk.from_pem(pem) |> from_record() @doc """ Decrypts an encrypted PEM (Privacy Enhanced Email) binary into a `JOSE.JWK` using `password`. """ def from_pem(password, list) when is_list(list), do: for(element <- list, into: [], do: from_pem(password, element)) def from_pem(password, pem), do: :jose_jwk.from_pem(password, pem) |> from_record() @doc """ Reads file and calls `from_pem/1` to convert into a `JOSE.JWK`. """ def from_pem_file(file), do: :jose_jwk.from_pem_file(file) |> from_record() @doc """ Reads encrypted file and calls `from_pem/2` to convert into a `JOSE.JWK` using `password`. """ def from_pem_file(password, file), do: :jose_jwk.from_pem_file(password, file) |> from_record() defp from_encrypted_record({jwe, jwk}) when is_tuple(jwe) and is_tuple(jwk), do: {JOSE.JWE.from_record(jwe), from_record(jwk)} defp from_encrypted_record(any), do: any ## Encode API @doc """ Converts a `JOSE.JWK` into a binary. """ def to_binary(list) when is_list(list), do: for(element <- list, into: [], do: to_binary(element)) def to_binary(jwk = %JOSE.JWK{}), do: to_binary(to_record(jwk)) def to_binary(jwk), do: :jose_jwk.to_binary(jwk) @doc """ Encrypts a `JOSE.JWK` into a binary using `password` and the default `jwe` for the key type. See `to_binary/3`. """ def to_binary(password, list) when is_list(list), do: for(element <- list, into: [], do: to_binary(password, element)) def to_binary(password, jwk = %JOSE.JWK{}), do: to_binary(password, to_record(jwk)) def to_binary(password, jwk), do: :jose_jwk.to_binary(password, jwk) @doc """ Encrypts a `JOSE.JWK` into a binary using `password` and `jwe`. """ def to_binary(password, jwe = %JOSE.JWE{}, jwk), do: to_binary(password, JOSE.JWE.to_record(jwe), jwk) def to_binary(password, jwe, jwk = %JOSE.JWK{}), do: to_binary(password, jwe, to_record(jwk)) def to_binary(password, jwe, jwk), do: :jose_jwk.to_binary(password, jwe, jwk) @doc """ Converts a `JOSE.JWK` into a DER (Distinguished Encoding Rules) binary. """ def to_der(list) when is_list(list), do: for(element <- list, into: [], do: to_der(element)) def to_der(jwk = %JOSE.JWK{}), do: to_der(to_record(jwk)) def to_der(jwk), do: :jose_jwk.to_der(jwk) @doc """ Encrypts a `JOSE.JWK` into a DER (Distinguished Encoding Rules) encrypted binary using `password`. """ def to_der(password, list) when is_list(list), do: for(element <- list, into: [], do: to_der(password, element)) def to_der(password, jwk = %JOSE.JWK{}), do: to_der(password, to_record(jwk)) def to_der(password, jwk), do: :jose_jwk.to_der(password, jwk) @doc """ Calls `to_der/1` on a `JOSE.JWK` and then writes the binary to file. """ def to_der_file(file, jwk = %JOSE.JWK{}), do: to_der_file(file, to_record(jwk)) def to_der_file(file, jwk), do: :jose_jwk.to_der_file(file, jwk) @doc """ Calls `to_der/2` on a `JOSE.JWK` and then writes the encrypted binary to file. """ def to_der_file(password, file, jwk = %JOSE.JWK{}), do: to_der_file(password, file, to_record(jwk)) def to_der_file(password, file, jwk), do: :jose_jwk.to_der_file(password, file, jwk) @doc """ Calls `to_binary/1` on a `JOSE.JWK` and then writes the binary to file. """ def to_file(file, jwk = %JOSE.JWK{}), do: to_file(file, to_record(jwk)) def to_file(file, jwk), do: :jose_jwk.to_file(file, jwk) @doc """ Calls `to_binary/2` on a `JOSE.JWK` and then writes the encrypted binary to file. """ def to_file(password, file, jwk = %JOSE.JWK{}), do: to_file(password, file, to_record(jwk)) def to_file(password, file, jwk), do: :jose_jwk.to_file(password, file, jwk) @doc """ Calls `to_binary/3` on a `JOSE.JWK` and then writes the encrypted binary to file. """ def to_file(password, file, jwe = %JOSE.JWE{}, jwk), do: to_file(password, file, JOSE.JWE.to_record(jwe), jwk) def to_file(password, file, jwe, jwk = %JOSE.JWK{}), do: to_file(password, file, jwe, to_record(jwk)) def to_file(password, file, jwe, jwk), do: :jose_jwk.to_file(password, file, jwe, jwk) @doc """ Converts a `JOSE.JWK` into the raw key format. """ def to_key(list) when is_list(list), do: for(element <- list, into: [], do: to_key(element)) def to_key(jwk = %JOSE.JWK{}), do: to_key(to_record(jwk)) def to_key(jwk), do: :jose_jwk.to_key(jwk) @doc """ Converts a `JOSE.JWK` into a map. """ def to_map(list) when is_list(list), do: for(element <- list, into: [], do: to_map(element)) def to_map(jwk = %JOSE.JWK{}), do: to_map(to_record(jwk)) def to_map(jwk), do: :jose_jwk.to_map(jwk) @doc """ Encrypts a `JOSE.JWK` into a map using `password` and the default `jwe` for the key type. See `to_map/3`. """ def to_map(password, list) when is_list(list), do: for(element <- list, into: [], do: to_map(password, element)) def to_map(password, jwk = %JOSE.JWK{}), do: to_map(password, to_record(jwk)) def to_map(password, jwk), do: :jose_jwk.to_map(password, jwk) @doc """ Encrypts a `JOSE.JWK` into a map using `password` and `jwe`. """ def to_map(password, jwe = %JOSE.JWE{}, jwk), do: to_map(password, JOSE.JWE.to_record(jwe), jwk) def to_map(password, jwe, jwk = %JOSE.JWK{}), do: to_map(password, jwe, to_record(jwk)) def to_map(password, jwe, jwk), do: :jose_jwk.to_map(password, jwe, jwk) @doc """ Converts a `JOSE.JWK` into a raw binary octet. """ def to_oct(list) when is_list(list), do: for(element <- list, into: [], do: to_oct(element)) def to_oct(jwk = %JOSE.JWK{}), do: to_oct(to_record(jwk)) def to_oct(jwk), do: :jose_jwk.to_oct(jwk) @doc """ Encrypts a `JOSE.JWK` into a raw binary octet using `password` and the default `jwe` for the key type. See `to_oct/3`. """ def to_oct(password, list) when is_list(list), do: for(element <- list, into: [], do: to_oct(password, element)) def to_oct(password, jwk = %JOSE.JWK{}), do: to_oct(password, to_record(jwk)) def to_oct(password, jwk), do: :jose_jwk.to_oct(password, jwk) @doc """ Encrypts a `JOSE.JWK` into a raw binary octet using `password` and `jwe`. """ def to_oct(password, jwe = %JOSE.JWE{}, jwk), do: to_oct(password, JOSE.JWE.to_record(jwe), jwk) def to_oct(password, jwe, jwk = %JOSE.JWK{}), do: to_oct(password, jwe, to_record(jwk)) def to_oct(password, jwe, jwk), do: :jose_jwk.to_oct(password, jwe, jwk) @doc """ Calls `to_oct/1` on a `JOSE.JWK` and then writes the binary to file. """ def to_oct_file(file, jwk = %JOSE.JWK{}), do: to_oct_file(file, to_record(jwk)) def to_oct_file(file, jwk), do: :jose_jwk.to_oct_file(file, jwk) @doc """ Calls `to_oct/2` on a `JOSE.JWK` and then writes the encrypted binary to file. """ def to_oct_file(password, file, jwk = %JOSE.JWK{}), do: to_oct_file(password, file, to_record(jwk)) def to_oct_file(password, file, jwk), do: :jose_jwk.to_oct_file(password, file, jwk) @doc """ Calls `to_oct/3` on a `JOSE.JWK` and then writes the encrypted binary to file. """ def to_oct_file(password, file, jwe = %JOSE.JWE{}, jwk), do: to_oct_file(password, file, JOSE.JWE.to_record(jwe), jwk) def to_oct_file(password, file, jwe, jwk = %JOSE.JWK{}), do: to_oct_file(password, file, jwe, to_record(jwk)) def to_oct_file(password, file, jwe, jwk), do: :jose_jwk.to_oct_file(password, file, jwe, jwk) @doc """ Converts a `JOSE.JWK` into an octet key pair. """ def to_okp(list) when is_list(list), do: for(element <- list, into: [], do: to_okp(element)) def to_okp(jwk = %JOSE.JWK{}), do: to_okp(to_record(jwk)) def to_okp(jwk), do: :jose_jwk.to_okp(jwk) @doc """ Converts a `JOSE.JWK` into an OpenSSH key binary. """ def to_openssh_key(list) when is_list(list), do: for(element <- list, into: [], do: to_openssh_key(element)) def to_openssh_key(jwk = %JOSE.JWK{}), do: to_openssh_key(to_record(jwk)) def to_openssh_key(jwk), do: :jose_jwk.to_openssh_key(jwk) @doc """ Calls `to_openssh_key/1` on a `JOSE.JWK` and then writes the binary to file. """ def to_openssh_key_file(file, jwk = %JOSE.JWK{}), do: to_openssh_key_file(file, to_record(jwk)) def to_openssh_key_file(file, jwk), do: :jose_jwk.to_openssh_key_file(file, jwk) @doc """ Converts a `JOSE.JWK` into a PEM (Privacy Enhanced Email) binary. """ def to_pem(list) when is_list(list), do: for(element <- list, into: [], do: to_pem(element)) def to_pem(jwk = %JOSE.JWK{}), do: to_pem(to_record(jwk)) def to_pem(jwk), do: :jose_jwk.to_pem(jwk) @doc """ Encrypts a `JOSE.JWK` into a PEM (Privacy Enhanced Email) encrypted binary using `password`. """ def to_pem(password, list) when is_list(list), do: for(element <- list, into: [], do: to_pem(password, element)) def to_pem(password, jwk = %JOSE.JWK{}), do: to_pem(password, to_record(jwk)) def to_pem(password, jwk), do: :jose_jwk.to_pem(password, jwk) @doc """ Calls `to_pem/1` on a `JOSE.JWK` and then writes the binary to file. """ def to_pem_file(file, jwk = %JOSE.JWK{}), do: to_pem_file(file, to_record(jwk)) def to_pem_file(file, jwk), do: :jose_jwk.to_pem_file(file, jwk) @doc """ Calls `to_pem/2` on a `JOSE.JWK` and then writes the encrypted binary to file. """ def to_pem_file(password, file, jwk = %JOSE.JWK{}), do: to_pem_file(password, file, to_record(jwk)) def to_pem_file(password, file, jwk), do: :jose_jwk.to_pem_file(password, file, jwk) @doc """ Converts a private `JOSE.JWK` into a public `JOSE.JWK`. iex> jwk_rsa = JOSE.JWK.generate_key({:rsa, 256}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_rsa, {:RSAPrivateKey, :"two-prime", 89657271283923333213688956979801646886488725937927826421780028977595670900943, 65537, 49624301670095289515744590467755999498582844809776145284365095264133428741569, 336111124810514302695156165996294214367, 266748895426976520545002702829665062929, 329628611699439793965634256329704106687, 266443630200356088742496100410997365601, 145084675516165292189647528713269147163, :asn1_NOVALUE}}} iex> JOSE.JWK.to_public(jwk_rsa) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_rsa, {:RSAPublicKey, 89657271283923333213688956979801646886488725937927826421780028977595670900943, 65537}}} """ def to_public(list) when is_list(list), do: for(element <- list, into: [], do: to_public(element)) def to_public(jwk = %JOSE.JWK{}), do: to_public(to_record(jwk)) def to_public(jwk), do: :jose_jwk.to_public(jwk) |> from_record() @doc """ Calls `to_public/1` and then `to_file/2` on a `JOSE.JWK`. """ def to_public_file(file, jwk = %JOSE.JWK{}), do: to_public_file(file, to_record(jwk)) def to_public_file(file, jwk), do: :jose_jwk.to_public_file(file, jwk) @doc """ Calls `to_public/1` and then `to_key/1` on a `JOSE.JWK`. """ def to_public_key(list) when is_list(list), do: for(element <- list, into: [], do: to_public_key(element)) def to_public_key(jwk = %JOSE.JWK{}), do: to_public_key(to_record(jwk)) def to_public_key(jwk), do: :jose_jwk.to_public_key(jwk) @doc """ Calls `to_public/1` and then `to_map/1` on a `JOSE.JWK`. """ def to_public_map(list) when is_list(list), do: for(element <- list, into: [], do: to_public_map(element)) def to_public_map(jwk = %JOSE.JWK{}), do: to_public_map(to_record(jwk)) def to_public_map(jwk), do: :jose_jwk.to_public_map(jwk) @doc """ Converts a `JOSE.JWK` into a map that can be used by `thumbprint/1` and `thumbprint/2`. """ def to_thumbprint_map(list) when is_list(list), do: for(element <- list, into: [], do: to_thumbprint_map(element)) def to_thumbprint_map(jwk = %JOSE.JWK{}), do: to_thumbprint_map(to_record(jwk)) def to_thumbprint_map(jwk), do: :jose_jwk.to_thumbprint_map(jwk) ## API @doc """ Decrypts the `encrypted` binary or map using the `jwk`. See `JOSE.JWE.block_decrypt/2`. """ def block_decrypt(encrypted, jwk = %JOSE.JWK{}), do: block_decrypt(encrypted, to_record(jwk)) def block_decrypt(encrypted, {your_public_jwk = %JOSE.JWK{}, my_private_jwk}), do: block_decrypt(encrypted, {to_record(your_public_jwk), my_private_jwk}) def block_decrypt(encrypted, {your_public_jwk, my_private_jwk = %JOSE.JWK{}}), do: block_decrypt(encrypted, {your_public_jwk, to_record(my_private_jwk)}) def block_decrypt(encrypted, jwk) do case :jose_jwk.block_decrypt(encrypted, jwk) do {plain_text, jwe} when is_tuple(jwe) -> {plain_text, JOSE.JWE.from_record(jwe)} error -> error end end @doc """ Encrypts the `plain_text` using the `jwk` and the default `jwe` based on the key type. See `block_encrypt/3`. """ def block_encrypt(plain_text, jwk = %JOSE.JWK{}), do: block_encrypt(plain_text, to_record(jwk)) def block_encrypt(plain_text, {your_public_jwk = %JOSE.JWK{}, my_private_jwk}), do: block_encrypt(plain_text, {to_record(your_public_jwk), my_private_jwk}) def block_encrypt(plain_text, {your_public_jwk, my_private_jwk = %JOSE.JWK{}}), do: block_encrypt(plain_text, {your_public_jwk, to_record(my_private_jwk)}) def block_encrypt(plain_text, jwk), do: :jose_jwk.block_encrypt(plain_text, jwk) @doc """ Encrypts the `plain_text` using the `jwk` and algorithms specified by the `jwe`. See `JOSE.JWE.block_encrypt/3`. """ def block_encrypt(plain_text, jwe = %JOSE.JWE{}, jwk), do: block_encrypt(plain_text, JOSE.JWE.to_record(jwe), jwk) def block_encrypt(plain_text, jwe, jwk = %JOSE.JWK{}), do: block_encrypt(plain_text, jwe, to_record(jwk)) def block_encrypt(plain_text, jwe, {your_public_jwk = %JOSE.JWK{}, my_private_jwk}), do: block_encrypt(plain_text, jwe, {to_record(your_public_jwk), my_private_jwk}) def block_encrypt(plain_text, jwe, {your_public_jwk, my_private_jwk = %JOSE.JWK{}}), do: block_encrypt(plain_text, jwe, {your_public_jwk, to_record(my_private_jwk)}) def block_encrypt(plain_text, jwe, jwk), do: :jose_jwk.block_encrypt(plain_text, jwe, jwk) @doc """ Returns a block encryptor map for the key type. """ def block_encryptor(list) when is_list(list), do: for(element <- list, into: [], do: block_encryptor(element)) def block_encryptor(jwk = %JOSE.JWK{}), do: block_encryptor(to_record(jwk)) def block_encryptor(jwk), do: :jose_jwk.block_encryptor(jwk) @doc """ Key Agreement decryption of the `encrypted` binary or map using `my_private_jwk`. See `box_encrypt/2` and `JOSE.JWE.block_decrypt/2`. """ def box_decrypt(encrypted, my_private_jwk = %JOSE.JWK{}), do: box_decrypt(encrypted, to_record(my_private_jwk)) def box_decrypt(encrypted, {your_public_jwk = %JOSE.JWK{}, my_private_jwk}), do: box_decrypt(encrypted, {to_record(your_public_jwk), my_private_jwk}) def box_decrypt(encrypted, {your_public_jwk, my_private_jwk = %JOSE.JWK{}}), do: box_decrypt(encrypted, {your_public_jwk, to_record(my_private_jwk)}) def box_decrypt(encrypted, my_private_jwk) do case :jose_jwk.box_decrypt(encrypted, my_private_jwk) do {plain_text, jwe} when is_tuple(jwe) -> {plain_text, JOSE.JWE.from_record(jwe)} error -> error end end @doc """ Key Agreement encryption of `plain_text` by generating an ephemeral private key based on `other_public_jwk` curve. See `box_encrypt/3`. # bob wants alice to send him a secret, so he first sends alice his public key: bob_public_jwk = JOSE.JWK.from(%{"crv" => "P-256", "kty" => "EC", "x" => "6pwDpICQ8JBWdvuLuXeWILAxSEUNB_BBAswikgYKKmY", "y" => "fEHj1ehsIJ7PP-qon-oONl_J2yZLWpUncNRedZT7xqs"}) # alice uses bob's public key to generate an ephemeral private key used to encrypt the secret: iex> {enc_alice2bob_tuple, alice_private_jwk} = JOSE.JWK.box_encrypt("secret", bob_public_jwk) {{%{alg: :jose_jwe_alg_ecdh_es, enc: :jose_jwe_enc_aes}, %{"ciphertext" => "zcIIZLDB", "encrypted_key" => "", "iv" => "9p8c7YJV5htz8zLI", "protected" => "eyJhbGciOiJFQ0RILUVTIiwiYXB1IjoiaEhibEsxZlNWQ1FjTE5NQkpXMjB5Mko0VHMzcUhqR2c4ZDlocmFfc2QyZyIsImFwdiI6IlU4MkpJbFFNS0FWYWY5bXVwU0I2c0JERWpIQ1Qxdl9JU00xMUNsZHpVUGMiLCJlbmMiOiJBMTI4R0NNIiwiZXBrIjp7ImNydiI6IlAtMjU2Iiwia3R5IjoiRUMiLCJ4IjoiSUY3RTFza0hJMjBwQjRwbi0tMVZ4dVF4Vkl4Sjkzd21IaFl4VEp0VkZOVSIsInkiOiJiVDdidzdhRjVlM1hLNUh6YVM4MEFVbktKVGE2eWdYbkJDVDFxNERHSWNrIn19", "tag" => "MHtfyNub8vG84ER0MPynuA"}}, %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_ec, {:ECPrivateKey, 1, <<138, 8, 179, 41, 203, 0, 127, 144, 178, 132, 66, 96, 50, 161, 103, 50, 4, 119, 71, 57, 63, 63, 33, 29, 69, 201, 182, 210, 106, 37, 196, 183>>, {:namedCurve, {1, 2, 840, 10045, 3, 1, 7}}, <<4, 32, 94, 196, 214, 201, 7, 35, 109, 41, 7, 138, 103, 251, 237, 85, 198, 228, 49, 84, 140, 73, 247, 124, 38, 30, 22, 49, 76, 155, 85, 20, 213, 109, 62, 219, 195, 182, 133, 229, 237, 215, ...>>}}}} # alice compacts the encrypted message and sends it to bob which contains alice's public key: iex> enc_alice2bob_binary = JOSE.JWE.compact(enc_alice2bob_tuple) |> elem(1) "eyJhbGciOiJFQ0RILUVTIiwiYXB1IjoiaEhibEsxZlNWQ1FjTE5NQkpXMjB5Mko0VHMzcUhqR2c4ZDlocmFfc2QyZyIsImFwdiI6IlU4MkpJbFFNS0FWYWY5bXVwU0I2c0JERWpIQ1Qxdl9JU00xMUNsZHpVUGMiLCJlbmMiOiJBMTI4R0NNIiwiZXBrIjp7ImNydiI6IlAtMjU2Iiwia3R5IjoiRUMiLCJ4IjoiSUY3RTFza0hJMjBwQjRwbi0tMVZ4dVF4Vkl4Sjkzd21IaFl4VEp0VkZOVSIsInkiOiJiVDdidzdhRjVlM1hLNUh6YVM4MEFVbktKVGE2eWdYbkJDVDFxNERHSWNrIn19..9p8c7YJV5htz8zLI.zcIIZLDB.MHtfyNub8vG84ER0MPynuA" # bob can then decrypt the encrypted message using his private key: bob_private_jwk = JOSE.JWK.from(%{"crv" => "P-256", "d" => "69sPu8znGIFuysKso-RemObfFs8bMBmkF0dfI1h6S1E", "kty" => "EC", "x" => "6pwDpICQ8JBWdvuLuXeWILAxSEUNB_BBAswikgYKKmY", "y" => "fEHj1ehsIJ7PP-qon-oONl_J2yZLWpUncNRedZT7xqs"}) iex> JOSE.JWK.box_decrypt(enc_alice2bob_binary, bob_private_jwk) {"secret", %JOSE.JWE{alg: {:jose_jwe_alg_ecdh_es, {:jose_jwe_alg_ecdh_es, {{{:ECPoint, <<4, 32, 94, 196, 214, 201, 7, 35, 109, 41, 7, 138, 103, 251, 237, 85, 198, 228, 49, 84, 140, 73, 247, 124, 38, 30, 22, 49, 76, 155, 85, 20, 213, 109, 62, 219, 195, 182, 133, 229, 237, 215, ...>>}, {:namedCurve, {1, 2, 840, 10045, 3, 1, 7}}}, %{}}, <<132, 118, 229, 43, 87, 210, 84, 36, 28, 44, 211, 1, 37, 109, 180, 203, 98, 120, 78, 205, 234, 30, 49, 160, 241, 223, 97, 173, 175, 236, 119, 104>>, <<83, 205, 137, 34, 84, 12, 40, 5, 90, 127, 217, 174, 165, 32, 122, 176, 16, 196, 140, 112, 147, 214, 255, 200, 72, 205, 117, 10, 87, 115, 80, 247>>, :undefined}}, enc: {:jose_jwe_enc_aes, {:jose_jwe_enc_aes, {:aes_gcm, 128}, 128, 16, 12, :undefined, :undefined, :undefined, :undefined}}, fields: %{}, zip: :undefined}} """ def box_encrypt(plain_text, other_public_jwk = %JOSE.JWK{}), do: box_encrypt(plain_text, to_record(other_public_jwk)) def box_encrypt(plain_text, other_public_jwk) do case :jose_jwk.box_encrypt(plain_text, other_public_jwk) do {encrypted, my_private_jwk} when is_tuple(my_private_jwk) -> {encrypted, from_record(my_private_jwk)} error -> error end end @doc """ Key Agreement encryption of `plain_text` using `my_private_jwk`, `other_public_jwk`, and the default `jwe` based on the key types. See `box_encrypt/4`. """ def box_encrypt(plain_text, other_public_jwk = %JOSE.JWK{}, my_private_jwk), do: box_encrypt(plain_text, to_record(other_public_jwk), my_private_jwk) def box_encrypt(plain_text, other_public_jwk, my_private_jwk = %JOSE.JWK{}), do: box_encrypt(plain_text, other_public_jwk, to_record(my_private_jwk)) def box_encrypt(plain_text, other_public_jwk, my_private_jwk), do: :jose_jwk.box_encrypt(plain_text, other_public_jwk, my_private_jwk) @doc """ Key Agreement encryption of `plain_text` using `my_private_jwk`, `other_public_jwk`, and the algorithms specified by the `jwe`. # let's """ def box_encrypt(plain_text, jwe = %JOSE.JWE{}, other_public_jwk, my_private_jwk), do: box_encrypt(plain_text, JOSE.JWE.to_record(jwe), other_public_jwk, my_private_jwk) def box_encrypt(plain_text, jwe, other_public_jwk = %JOSE.JWK{}, my_private_jwk), do: box_encrypt(plain_text, jwe, to_record(other_public_jwk), my_private_jwk) def box_encrypt(plain_text, jwe, other_public_jwk, my_private_jwk = %JOSE.JWK{}), do: box_encrypt(plain_text, jwe, other_public_jwk, to_record(my_private_jwk)) def box_encrypt(plain_text, jwe, other_public_jwk, my_private_jwk), do: :jose_jwk.box_encrypt(plain_text, jwe, other_public_jwk, my_private_jwk) @doc """ Generates a new `JOSE.JWK` based on another `JOSE.JWK` or from initialization params provided. Passing another `JOSE.JWK` results in different behavior depending on the `"kty"`: * `"EC"` - uses the same named curve to generate a new key * `"oct"` - uses the byte size to generate a new key * `"OKP"` - uses the same named curve to generate a new key * `"RSA"` - uses the same modulus and exponent sizes to generate a new key The following initialization params may also be used: * `{:ec, "P-256" | "P-384" | "P-521"}` - generates an `"EC"` key using the `"P-256"`, `"P-384"`, or `"P-521"` curves * `{:oct, bytes}` - generates an `"oct"` key made of a random `bytes` number of bytes * `{:okp, :Ed25519 | :Ed25519ph | :Ed448 | :Ed448ph | :X25519 | :X448}` - generates an `"OKP"` key using the specified EdDSA or ECDH edwards curve * `{:rsa, modulus_size} | {:rsa, modulus_size, exponent_size}` - generates an `"RSA"` key using the `modulus_size` and `exponent_size` """ def generate_key(jwk = %JOSE.JWK{}), do: jwk |> to_record() |> generate_key() def generate_key(parameters), do: :jose_jwk.generate_key(parameters) |> from_record() @doc """ Merges map on right into map on left. """ def merge(left = %JOSE.JWK{}, right), do: merge(left |> to_record(), right) def merge(left, right = %JOSE.JWK{}), do: merge(left, right |> to_record()) def merge(left, right), do: :jose_jwk.merge(left, right) |> from_record() @doc """ Computes the shared secret between two keys. Currently only works for `"EC"` keys and `"OKP"` keys with `"crv"` set to `"X25519"` or `"X448"`. """ def shared_secret(your_jwk = %JOSE.JWK{}, my_jwk), do: shared_secret(to_record(your_jwk), my_jwk) def shared_secret(your_jwk, my_jwk = %JOSE.JWK{}), do: shared_secret(your_jwk, to_record(my_jwk)) def shared_secret(your_jwk, my_jwk), do: :jose_jwk.shared_secret(your_jwk, my_jwk) @doc """ Signs the `plain_text` using the `jwk` and the default signer algorithm `jws` for the key type. See `sign/3`. """ def sign(plain_text, jwk = %JOSE.JWK{}), do: sign(plain_text, to_record(jwk)) def sign(plain_text, key_list) when is_list(key_list) do keys = for key <- key_list, into: [] do case key do %JOSE.JWK{} -> JOSE.JWK.to_record(key) _ -> key end end :jose_jwk.sign(plain_text, keys) end def sign(plain_text, jwk), do: :jose_jwk.sign(plain_text, jwk) @doc """ Signs the `plain_text` using the `jwk` and the algorithm specified by the `jws`. See `JOSE.JWS.sign/3`. """ def sign(plain_text, jws = %JOSE.JWS{}, jwk), do: sign(plain_text, JOSE.JWS.to_record(jws), jwk) def sign(plain_text, jws, jwk = %JOSE.JWK{}), do: sign(plain_text, jws, to_record(jwk)) def sign(plain_text, signer_list, key_list) when is_list(signer_list) and is_list(key_list) and length(signer_list) === length(key_list) do signers = for signer <- signer_list, into: [] do case signer do %JOSE.JWS{} -> JOSE.JWS.to_record(signer) _ -> signer end end keys = for key <- key_list, into: [] do case key do %JOSE.JWK{} -> JOSE.JWK.to_record(key) _ -> key end end :jose_jwk.sign(plain_text, signers, keys) end def sign(plain_text, jws, key_list) when is_list(key_list) and not is_list(jws) do keys = for key <- key_list, into: [] do case key do %JOSE.JWK{} -> JOSE.JWK.to_record(key) _ -> key end end :jose_jwk.sign(plain_text, jws, keys) end def sign(plain_text, jws, jwk), do: :jose_jwk.sign(plain_text, jws, jwk) @doc """ Returns a signer map for the key type. """ def signer(list) when is_list(list), do: for(element <- list, into: [], do: signer(element)) def signer(jwk = %JOSE.JWK{}), do: signer(to_record(jwk)) def signer(jwk), do: :jose_jwk.signer(jwk) @doc """ Returns the unique thumbprint for a `JOSE.JWK` using the `:sha256` digest type. See `thumbprint/2`. """ def thumbprint(list) when is_list(list), do: for(element <- list, into: [], do: thumbprint(element)) def thumbprint(jwk = %JOSE.JWK{}), do: thumbprint(to_record(jwk)) def thumbprint(jwk), do: :jose_jwk.thumbprint(jwk) @doc """ Returns the unique thumbprint for a `JOSE.JWK` using the `digest_type`. # let's define two different keys that will have the same thumbprint jwk1 = JOSE.JWK.from_oct("secret") jwk2 = JOSE.JWK.from(%{ "use" => "sig", "k" => "c2VjcmV0", "kty" => "oct" }) iex> JOSE.JWK.thumbprint(jwk1) "DWBh0SEIAPYh1x5uvot4z3AhaikHkxNJa3Ada2fT-Cg" iex> JOSE.JWK.thumbprint(jwk2) "DWBh0SEIAPYh1x5uvot4z3AhaikHkxNJa3Ada2fT-Cg" iex> JOSE.JWK.thumbprint(:md5, jwk1) "Kldz8k5PQm7y1E3aNBlMiA" iex> JOSE.JWK.thumbprint(:md5, jwk2) "Kldz8k5PQm7y1E3aNBlMiA" See JSON Web Key (JWK) Thumbprint [RFC 7638](https://tools.ietf.org/html/rfc7638) for more information. """ def thumbprint(digest_type, list) when is_list(list), do: for(element <- list, into: [], do: thumbprint(digest_type, element)) def thumbprint(digest_type, jwk = %JOSE.JWK{}), do: thumbprint(digest_type, to_record(jwk)) def thumbprint(digest_type, jwk), do: :jose_jwk.thumbprint(digest_type, jwk) @doc """ Returns a verifier algorithm list for the key type. """ def verifier(list) when is_list(list), do: for(element <- list, into: [], do: verifier(element)) def verifier(jwk = %JOSE.JWK{}), do: verifier(to_record(jwk)) def verifier(jwk), do: :jose_jwk.verifier(jwk) @doc """ Verifies the `signed` using the `jwk`. See `JOSE.JWS.verify_strict/3`. """ def verify(signed, jwk = %JOSE.JWK{}), do: verify(signed, to_record(jwk)) def verify(signed, jwk = [%JOSE.JWK{} | _]) do verify( signed, for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end ) end def verify(signed, jwk) do try do case :jose_jwk.verify(signed, jwk) do {verified, payload, jws} when is_tuple(jws) -> {verified, payload, JOSE.JWS.from_record(jws)} list when is_list(list) -> for {jwk, verifications} <- list do {JOSE.JWK.from_record(jwk), Enum.map(verifications, fn {verified, jwt, jws} when is_tuple(jwt) and is_tuple(jws) -> {verified, from_record(jwt), JOSE.JWS.from_record(jws)} other -> other end)} end error -> error end catch class, reason -> {class, reason} end end @doc """ Verifies the `signed` using the `jwk` and whitelists the `"alg"` using `allow`. See `JOSE.JWS.verify/2`. """ def verify_strict(signed, allow, jwk = %JOSE.JWK{}), do: verify_strict(signed, allow, to_record(jwk)) def verify_strict(signed, allow, jwk = [%JOSE.JWK{} | _]) do verify_strict( signed, allow, for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end ) end def verify_strict(signed, allow, jwk) do try do case :jose_jwk.verify_strict(signed, allow, jwk) do {verified, payload, jws} when is_tuple(jws) -> {verified, payload, JOSE.JWS.from_record(jws)} list when is_list(list) -> for {jwk, verifications} <- list do {JOSE.JWK.from_record(jwk), Enum.map(verifications, fn {verified, jwt, jws} when is_tuple(jwt) and is_tuple(jws) -> {verified, from_record(jwt), JOSE.JWS.from_record(jws)} other -> other end)} end error -> error end catch class, reason -> {class, reason} end end end erlang-jose-1.10.1/lib/jose/jwa.ex0000644000232200023220000002152113605433351017177 0ustar debalancedebalancedefmodule JOSE.JWA do @moduledoc ~S""" JWA stands for JSON Web Algorithms which is defined in [RFC 7518](https://tools.ietf.org/html/rfc7518). ## Cryptographic Algorithm Fallback Native implementations of all cryptographic and public key algorithms required by the JWA specifications are not present in current versions of Elixir and OTP. JOSE will detect whether a specific algorithm is natively supported or not and, by default, it will mark the algorithm as unsupported if a native implementation is not found. However, JOSE also has pure Erlang versions of many of the missing algorithms which can be used as a fallback by calling `JOSE.crypto_fallback/1` and passing `true`. """ ## Crypto API @doc """ Decrypts `cipher_text` according to `cipher` block cipher. Currently supported block ciphers: * `{:aes_ecb, 128}` - AES ECB with 128-bit `key` size * `{:aes_ecb, 192}` - AES ECB with 192-bit `key` size * `{:aes_ecb, 256}` - AES ECB with 256-bit `key` size """ defdelegate block_decrypt(cipher, key, cipher_text), to: :jose_jwa @doc """ Decrypts `cipher_text` according to `cipher` block cipher. Currently supported block ciphers: * `{:aes_cbc, 128}` - AES CBC with 128-bit `key` size and 128-bit `iv` size * `{:aes_cbc, 192}` - AES CBC with 192-bit `key` size and 128-bit `iv` size * `{:aes_cbc, 256}` - AES CBC with 256-bit `key` size and 128-bit `iv` size * `{:aes_gcm, 128}` - AES GCM with 128-bit `key` size and variable `iv` size * `{:aes_gcm, 192}` - AES GCM with 192-bit `key` size and variable `iv` size * `{:aes_gcm, 256}` - AES GCM with 256-bit `key` size and variable `iv` size * `{:chacha20_poly1305, 256}` - ChaCha20/Poly1305 with 256-bit `key` size and 96-bit `iv` size """ defdelegate block_decrypt(cipher, key, iv, cipher_text), to: :jose_jwa @doc """ Encrypts `plain_text` according to `cipher` block cipher. Currently supported block ciphers: * `{:aes_ecb, 128}` - AES ECB with 128-bit `key` size * `{:aes_ecb, 192}` - AES ECB with 192-bit `key` size * `{:aes_ecb, 256}` - AES ECB with 256-bit `key` size """ defdelegate block_encrypt(cipher, key, plain_text), to: :jose_jwa @doc """ Encrypts `plain_text` according to `cipher` block cipher. Currently supported block ciphers: * `{:aes_cbc, 128}` - AES CBC with 128-bit `key` size and 128-bit `iv` size * `{:aes_cbc, 192}` - AES CBC with 192-bit `key` size and 128-bit `iv` size * `{:aes_cbc, 256}` - AES CBC with 256-bit `key` size and 128-bit `iv` size * `{:aes_gcm, 128}` - AES GCM with 128-bit `key` size and variable `iv` size * `{:aes_gcm, 192}` - AES GCM with 192-bit `key` size and variable `iv` size * `{:aes_gcm, 256}` - AES GCM with 256-bit `key` size and variable `iv` size * `{:chacha20_poly1305, 256}` - ChaCha20/Poly1305 with 256-bit `key` size and 96-bit `iv` size """ defdelegate block_encrypt(cipher, key, iv, plain_text), to: :jose_jwa ## Public Key API @doc """ Decrypts `cipher_text` using the `private_key`. ## Options * `:rsa_padding` - one of `:rsa_pkcs1_oaep_padding` or `:rsa_pkcs1_padding` * `:rsa_oaep_md` - sets the hashing algorithm for `:rsa_pkcs1_oaep_padding`, defaults to `:sha` * `:rsa_oaep_label` - sets the label for `:rsa_pkcs1_oaep_padding`, defaults to `<<>>` """ defdelegate decrypt_private(cipher_text, private_key, options), to: :jose_jwa @doc """ Encrypts `plain_text` using the `public_key`. ## Options * `:rsa_padding` - one of `:rsa_pkcs1_oaep_padding` or `:rsa_pkcs1_padding` * `:rsa_oaep_md` - sets the hashing algorithm for `:rsa_pkcs1_oaep_padding`, defaults to `:sha` * `:rsa_oaep_label` - sets the label for `:rsa_pkcs1_oaep_padding`, defaults to `<<>>` """ defdelegate encrypt_public(plain_text, public_key, options), to: :jose_jwa @doc """ Signs the digested `message` using the `digest_type` and `private_key`. ## Options * `:rsa_padding` - one of `:rsa_pkcs1_pss_padding` or `:rsa_pkcs1_padding` * `:rsa_pss_saltlen` - sets the salt length for `:rsa_pkcs1_pss_padding`, defaults to `-1` * `-2` - use maximum for salt length * `-1` - use hash length for salt length * any number higher than `-1` is used as the actual salt length """ defdelegate sign(message, digest_type, private_key, options), to: :jose_jwa @doc """ Verifies the `signature` with the digested `message` using the `digest_type` and `public_key`. ## Options * `:rsa_padding` - one of `:rsa_pkcs1_pss_padding` or `:rsa_pkcs1_padding` * `:rsa_pss_saltlen` - sets the salt length for `:rsa_pkcs1_pss_padding`, defaults to `-1` * `-2` - automatically determine based on the PSS block structure * `-1` - use hash length for salt length * any number higher than `-1` is used as the actual salt length """ defdelegate verify(message, digest_type, signature, public_key, options), to: :jose_jwa ## API @doc """ Returns the current module and first argument for the specified `cipher`. iex> JOSE.JWA.block_cipher({:aes_cbc, 128}) {:crypto, :aes_cbc128} iex> JOSE.JWA.block_cipher({:aes_cbc, 192}) {:jose_jwa_unsupported, {:aes_cbc, 192}} iex> JOSE.crypto_fallback(true) :ok iex> JOSE.JWA.block_cipher({:aes_cbc, 192}) {:jose_jwa_aes, {:aes_cbc, 192}} """ defdelegate block_cipher(cipher), to: :jose_jwa @doc """ Returns the current block ciphers and their associated modules. iex> JOSE.JWA.crypto_ciphers() [{{:aes_cbc, 128}, :crypto}, {{:aes_cbc, 192}, :crypto}, {{:aes_cbc, 256}, :crypto}, {{:aes_ecb, 128}, :crypto}, {{:aes_ecb, 192}, :crypto}, {{:aes_ecb, 256}, :crypto}, {{:aes_gcm, 128}, :crypto}, {{:aes_gcm, 192}, :crypto}, {{:aes_gcm, 256}, :crypto}, {{:chacha20_poly1305, 256}, :jose_chacha20_poly1305}] """ defdelegate crypto_ciphers(), to: :jose_jwa @doc """ See `JOSE.crypto_fallback/0` """ defdelegate crypto_fallback(), to: :jose_jwa @doc """ See `JOSE.crypto_fallback/1` """ defdelegate crypto_fallback(boolean), to: :jose_jwa @doc """ Returns the current listing of supported `:crypto` and `:public_key` algorithms. iex> JOSE.JWA.crypto_supports() [ciphers: [aes_cbc: 128, aes_cbc: 192, aes_cbc: 256, aes_ecb: 128, aes_ecb: 192, aes_ecb: 256, aes_gcm: 128, aes_gcm: 192, aes_gcm: 256, chacha20_poly1305: 256], hashs: [:md5, :poly1305, :sha, :sha256, :sha384, :sha512, :shake256], public_keys: [:ec_gf2m, :ecdh, :ecdsa, :ed25519, :ed25519ph, :ed448, :ed448ph, :rsa, :x25519, :x448], rsa_crypt: [:rsa1_5, :rsa_oaep, :rsa_oaep_256], rsa_sign: [:rsa_pkcs1_padding, :rsa_pkcs1_pss_padding]] """ defdelegate crypto_supports(), to: :jose_jwa @doc """ Performs a constant time comparison between two binaries to help avoid [timing attacks](https://en.wikipedia.org/wiki/Timing_attack). """ defdelegate constant_time_compare(a, b), to: :jose_jwa @doc """ Returns either `:binary` or `:list` depending on the detected runtime behavior for EC keys. """ defdelegate ec_key_mode(), to: :jose_jwa @doc """ Checks whether the `cipher` is natively supported by `:crypto` or not. """ defdelegate is_block_cipher_supported(cipher), to: :jose_jwa @doc """ Checks whether ChaCha20/Poly1305 support is available or not. """ defdelegate is_chacha20_poly1305_supported(), to: :jose_jwa @doc """ Checks whether the `padding` is natively supported by `:public_key` or not. """ defdelegate is_rsa_crypt_supported(padding), to: :jose_jwa @doc """ Checks whether the `padding` is natively supported by `:public_key` or not. """ defdelegate is_rsa_sign_supported(padding), to: :jose_jwa @doc """ Returns the current listing of supported JOSE algorithms. iex> JOSE.JWA.supports() [{:jwe, {:alg, ["A128GCMKW", "A128KW", "A192GCMKW", "A192KW", "A256GCMKW", "A256KW", "ECDH-ES", "ECDH-ES+A128KW", "ECDH-ES+A192KW", "ECDH-ES+A256KW", "PBES2-HS256+A128KW", "PBES2-HS384+A192KW", "PBES2-HS512+A256KW", "RSA-OAEP", "RSA-OAEP-256", "RSA1_5", "dir"]}, {:enc, ["A128CBC-HS256", "A128GCM", "A192CBC-HS384", "A192GCM", "A256CBC-HS512", "A256GCM", "ChaCha20/Poly1305"]}, {:zip, ["DEF"]}}, {:jwk, {:kty, ["EC", "OKP", "RSA", "oct"]}, {:kty_OKP_crv, ["Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "X25519", "X448"]}}, {:jws, {:alg, ["ES256", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512", "Poly1305", "RS256", "RS384", "RS512", "none"]}}] """ defdelegate supports(), to: :jose_jwa @doc """ See `JOSE.unsecured_signing/0` """ defdelegate unsecured_signing(), to: :jose_jwa @doc """ See `JOSE.unsecured_signing/1` """ defdelegate unsecured_signing(boolean), to: :jose_jwa end erlang-jose-1.10.1/lib/jose/jws.ex0000644000232200023220000007704413605433351017234 0ustar debalancedebalancerequire Record defmodule JOSE.JWS do @moduledoc ~S""" JWS stands for JSON Web Signature which is defined in [RFC 7515](https://tools.ietf.org/html/rfc7515). ## Unsecured Signing Vulnerability The [`"none"`](https://tools.ietf.org/html/rfc7515#appendix-A.5) signing algorithm is disabled by default to prevent accidental verification of empty signatures (read about the vulnerability [here](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/)). You may also enable the `"none"` algorithm as an application environment variable for `:jose` or by using `JOSE.unsecured_signing/1`. ## Strict Verification Recommended `JOSE.JWS.verify_strict/3` is recommended over `JOSE.JWS.verify/2` so that signing algorithms may be whitelisted during verification of signed input. ## Algorithms The following algorithms are currently supported by `JOSE.JWS` (some may need the `JOSE.crypto_fallback/1` option to be enabled): * `"Ed25519"` * `"Ed25519ph"` * `"Ed448"` * `"Ed448ph"` * `"EdDSA"` * `"ES256"` * `"ES384"` * `"ES512"` * `"HS256"` * `"HS384"` * `"HS512"` * `"Poly1305"` * `"PS256"` * `"PS384"` * `"PS512"` * `"RS256"` * `"RS384"` * `"RS512"` * `"none"` (disabled by default, enable with `JOSE.unsecured_signing/1`) ## Examples All of the example keys generated below can be found here: [https://gist.github.com/potatosalad/925a8b74d85835e285b9](https://gist.github.com/potatosalad/925a8b74d85835e285b9) ### Ed25519 and Ed25519ph # let's generate the 2 keys we'll use below jwk_ed25519 = JOSE.JWK.generate_key({:okp, :Ed25519}) jwk_ed25519ph = JOSE.JWK.generate_key({:okp, :Ed25519ph}) # Ed25519 iex> signed_ed25519 = JOSE.JWS.sign(jwk_ed25519, "{}", %{ "alg" => "Ed25519" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJFZDI1NTE5In0.e30.xyg2LTblm75KbLFJtROZRhEgAFJdlqH9bhx8a9LO1yvLxNLhO9fLqnFuU3ojOdbObr8bsubPkPqUfZlPkGHXCQ" iex> JOSE.JWS.verify(jwk_ed25519, signed_ed25519) |> elem(0) true # Ed25519ph iex> signed_ed25519ph = JOSE.JWS.sign(jwk_ed25519ph, "{}", %{ "alg" => "Ed25519ph" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJFZDI1NTE5cGgifQ.e30.R3je4TTxQvoBOupIKkel_b8eW-G8KaWmXuC14NMGSCcHCTalURtMmVqX2KbcIpFBeI-OKP3BLHNIpt1keKveDg" iex> JOSE.JWS.verify(jwk_ed25519ph, signed_ed25519ph) |> elem(0) true ### Ed448 and Ed448ph # let's generate the 2 keys we'll use below jwk_ed448 = JOSE.JWK.generate_key({:okp, :Ed448}) jwk_ed448ph = JOSE.JWK.generate_key({:okp, :Ed448ph}) # Ed448 iex> signed_ed448 = JOSE.JWS.sign(jwk_ed448, "{}", %{ "alg" => "Ed448" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJFZDQ0OCJ9.e30.UlqTx962FvZP1G5pZOrScRXlAB0DJI5dtZkknNTm1E70AapkONi8vzpvKd355czflQdc7uyOzTeAz0-eLvffCKgWm_zebLly7L3DLBliynQk14qgJgz0si-60mBFYOIxRghk95kk5hCsFpxpVE45jRIA" iex> JOSE.JWS.verify(jwk_ed448, signed_ed448) |> elem(0) true # Ed448ph iex> signed_ed448ph = JOSE.JWS.sign(jwk_ed448ph, "{}", %{ "alg" => "Ed448ph" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJFZDQ0OHBoIn0.e30._7wxQF8Am-Fg3E-KgREXBv3Gr2vqLM6ja_7hs6kA5EakCrJVQ2QiAHrr4NriLABmiPbVd7F7IiaAApyR3Ud4ak3lGcHVxSyksjJjvBUbKnSB_xkT6v_QMmx27hV08JlxskUkfvjAG0-yKGC8BXoT9R0A" iex> JOSE.JWS.verify(jwk_ed448ph, signed_ed448ph) |> elem(0) true ### EdDSA # EdDSA works with Ed25519, Ed25519ph, Ed448, and Ed448ph keys. # However, it defaults to Ed25519 for key generation. jwk_eddsa = JOSE.JWS.generate_key(%{ "alg" => "EdDSA" }) # EdDSA iex> signed_eddsa = JOSE.JWS.sign(jwk_eddsa, "{}", %{ "alg" => "EdDSA" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJFZERTQSJ9.e30.rhb5ZY7MllNbW9q-SCn_NglhYtaRGMXEUDj6BvJjltOt19tEI_1wFrVK__jL91i9hO7WtVqRH_OfHiilnO1CAQ" iex> JOSE.JWS.verify(jwk_eddsa, signed_eddsa) |> elem(0) true ### ES256, ES384, and ES512 # let's generate the 3 keys we'll use below jwk_es256 = JOSE.JWK.generate_key({:ec, :secp256r1}) jwk_es384 = JOSE.JWK.generate_key({:ec, :secp384r1}) jwk_es512 = JOSE.JWK.generate_key({:ec, :secp521r1}) # ES256 iex> signed_es256 = JOSE.JWS.sign(jwk_es256, "{}", %{ "alg" => "ES256" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJFUzI1NiJ9.e30.nb7cEQQuIi2NgcP5A468FHGG8UZg8gWZjloISyVIwNh3X6FiTTFZsvc0mL3RnulWoNJzKF6xwhae3botI1LbRg" iex> JOSE.JWS.verify(jwk_es256, signed_es256) |> elem(0) true # ES384 iex> signed_es384 = JOSE.JWS.sign(jwk_es384, "{}", %{ "alg" => "ES384" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJFUzM4NCJ9.e30.-2kZkNe66y2SprhgvvtMa0qBrSb2imPhMYkbi_a7vx-vpEHuVKsxCpUyNVLe5_CXaHWhHyc2rNi4uEfU73c8XQB3e03rg_JOj0H5XGIGS5G9f4RmNMSCiYGwqshLSDFI" iex> JOSE.JWS.verify(jwk_es384, signed_es384) |> elem(0) true # ES512 iex> signed_es512 = JOSE.JWS.sign(jwk_es512, "{}", %{ "alg" => "ES512" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJFUzUxMiJ9.e30.AOIw4KTq5YDu6QNrAYKtFP8R5IljAbhqXuPK1dUARPqlfc5F3mM0kmSh5KOVNHDmdCdapBv0F3b6Hl6glFDPlxpiASuSWtvvs9K8_CRfSkEzvToj8wf3WLGOarQHDwYXtlZoki1zMPGeWABwafTZNQaItNSpqYd_P9GtN0XM3AALdua0" iex> JOSE.JWS.verify(jwk_es512, signed_es512) |> elem(0) true ### HS256, HS384, and HS512 # let's generate the 3 keys we'll use below jwk_hs256 = JOSE.JWK.generate_key({:oct, 16}) jwk_hs384 = JOSE.JWK.generate_key({:oct, 24}) jwk_hs512 = JOSE.JWK.generate_key({:oct, 32}) # HS256 iex> signed_hs256 = JOSE.JWS.sign(jwk_hs256, "{}", %{ "alg" => "HS256" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJIUzI1NiJ9.e30.r2JwwMFHECoDZlrETLT-sgFT4qN3w0MLee9MrgkDwXs" iex> JOSE.JWS.verify(jwk_hs256, signed_hs256) |> elem(0) true # HS384 iex> signed_hs384 = JOSE.JWS.sign(jwk_hs384, "{}", %{ "alg" => "HS384" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJIUzM4NCJ9.e30.brqQFXXM0XtMWDdKf0foEQcvK18swcoDkxBqCPeed_IO317_tisr60H2mz79SlNR" iex> JOSE.JWS.verify(jwk_hs384, signed_hs384) |> elem(0) true # HS512 iex> signed_hs512 = JOSE.JWS.sign(jwk_hs512, "{}", %{ "alg" => "HS512" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJIUzUxMiJ9.e30.ge1JYomO8Fyl6sgxLbc4g3AMPbaMHLmeTl0jrUYAJZSloN9j4VyhjucX8d-RWIlMjzdG0xyklw53k1-kaTlRVQ" iex> JOSE.JWS.verify(jwk_hs512, signed_hs512) |> elem(0) true ### Poly1305 This is highly experimental and based on [RFC 7539](https://tools.ietf.org/html/rfc7539). Every signed message has a new 96-bit nonce generated which is used to generate a one-time key from the secret. # let's generate the key we'll use below jwk_poly1305 = JOSE.JWK.generate_key({:oct, 32}) # Poly1305 iex> signed_poly1305 = JOSE.JWS.sign(jwk_poly1305, "{}", %{ "alg" => "Poly1305" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJQb2x5MTMwNSIsIm5vbmNlIjoiTjhiR3A1QXdob0Y3Yk1YUiJ9.e30.XWcCkV1WU72cTO-XuiNRAQ" iex> JOSE.JWS.verify(jwk_poly1305, signed_poly1305) |> elem(0) true # let's inspect the protected header to see the generated nonce iex> JOSE.JWS.peek_protected(signed_poly1305) "{\"alg\":\"Poly1305\",\"nonce\":\"N8bGp5AwhoF7bMXR\"}" ### PS256, PS384, and PS512 # let's generate the 3 keys we'll use below (cutkey must be installed as a dependency) jwk_ps256 = JOSE.JWK.generate_key({:rsa, 2048}) jwk_ps384 = JOSE.JWK.generate_key({:rsa, 4096}) jwk_ps512 = JOSE.JWK.generate_key({:rsa, 8192}) # this may take a few seconds # PS256 iex> signed_ps256 = JOSE.JWS.sign(jwk_ps256, "{}", %{ "alg" => "PS256" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJQUzI1NiJ9.e30.RY5A3rG2TjmdlARE57eSSSFE6plkuQPKLKsyqz3WrqKRWZgSrvROACRTzoGyrx1sNvQEZJLZ-xVhrFvP-80Q14XzQbPfYLubvn-2wcMNCmih3OVQNVtFdFjA5U2NG-sF-SWAUmm9V_DvMShFGG0qHxLX7LqT83lAIgEulgsytb0xgOjtJObBru5jLjN_uEnc7fCfnxi3my1GAtnrs9NiKvMfuIVlttvOORDFBTO2aFiCv1F-S6Xgj16rc0FGImG0x3amQcmFAD9g41KY0_KsCXgUfoiVpC6CqO6saRC4UDykks91B7Nuoxjsm3nKWa_4vKh9QJy-V8Sf0gHxK58j8Q" iex> JOSE.JWS.verify(jwk_ps256, signed_ps256) |> elem(0) true # PS384 iex> signed_ps384 = JOSE.JWS.sign(jwk_ps384, "{}", %{ "alg" => "PS384" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJQUzM4NCJ9.e30.xmYVenIhi75hDMy3bnL6WVpVlTzYmO1ejOZeq9AkSjkp_STrdIp6uUEs9H_y7CLD9LrGYYHDNDl9WmoH6cn95WZT9KJgAVNFFYd8owY6JUHGKU1jUbLkptAgvdphVpWZ1C5fVCRt4vmp8K9f6jy3er9jCBNjl9gSBdmToFwYdXI26ZKSBjfoVm2tFFQIOThye4YQWCWHbzSho6J7d5ATje72L30zDvWXavJ-XNvof5Tkju4WQQB-ukFoqTw4yV8RVwCa-DX61I1hNrq-Zr75_iWmHak3GqNkg5ACBEjDtvtyxJizqy9KINKSlbB9jGztiWoEiXZ6wJ5sSJ6ZrSFJuQVEmns_dLqzpSHEFkWfczEV_gj9Eu_EXwMp9YQlQ3GktfXaz-mzH_jUaLmudEUskQGCiR92gK9KR6_ROQPJfD54Tkqdh6snwg6y17k8GdlTc5qMM3V84q3R6zllmhrRhV1Dlduc0MEqKcsQSX_IX21-sfiVMIcUsW73dIPXVZI2jsNlEHKqwMjWdSfjYUf3YApxSGERU3u4lRS3F0yRrZur8KWS3ToilApjg0cNg9jKas8g8C8ZPgGFYM6StVxUnXRmsJILDnsZMIPjbUDAPHhB0DwLwOB7OqGUBcItX-zwur1OVnHR7aIh1DbfWfyTIml8VIhYfGfazgXfgQVcGEM" iex> JOSE.JWS.verify(jwk_ps384, signed_ps384) |> elem(0) true # PS512 iex> signed_ps512 = JOSE.JWS.sign(jwk_ps512, "{}", %{ "alg" => "PS512" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJQUzUxMiJ9.e30.fJe52-PF3I7UrpQamLCnmVAGkBhP0HVeJi48qZqaFc1-_tQEiYTfxuwQBDlt01GQWpjTZRb097bZF6RcrKWwRHyAo3otOZdR32emWfOHddWLL3qotj_fTaDR2-OhLixwce6mFjnHqppHH1zjCmgbKPG8S2cAadNd5w10VR-IS6LdnFRhNZOahuuB7dzCEJaSjkGfm3_9xdj3I0ZRl4fauR_LO9NQIyvMMeCFevowz1sVGG1G-I2njPrEXvxhAMp7y2mao5Yik8UUORXRjcn2Wai3umy8Yh4nHYU5qqruHjLjDwudCPNDjxjg294z1uAUpt7S0v7VbrkgUvgutTFAT-bcHywFODiycajQuqIpFp1TCUAq3Xe2yk4DTRduvPIKcPkJQnFrVkClJAU9A4D4602xpdK-z2uCgWsBVHVokf5-9ba5EqVb8BJx2xYZUIA5CdrIiTBfoe_cI5Jh92uprcWC_llio2ZJvGdQpPgwCgca7-RQ94LAmIA4u3mAndrZj_z48T2GjHbaKzl18FOPQH0XEvK_W5oypUe5NOGlz9mMGZigbFqBY2lM-7oVVYc4ZA3VFy8Dv1nWhU6DGb2NnDnQUyChllyBREuZbwrkOTQEvqqdV-6lM6VwXNu1gqc3YHly9W6u5CmsnxtvlIxsUVg679HiqdtdWxLSaIJObd9Xji56-eEkWMEA08SNy9p-F9AgHOxzoZqgrAQDEwqyEwqoAW681xLc5Vck580AQDxO9Ha4IqLIPirpO5EODQjOd8-S_SlAP5o_wz1Oh38MC5T5V13PqPuZ70dbggB4bUgVaHYC4FE4XHCqP7W3xethaPc68cY9-g9f1RUvthmnEYXSRpvyaMY3iX0txZazWIS_Jg7pNTCEaWr9JCLTZd1MiLbFowPvKYGM-z-39K31OUbq5PIScy0I9OOz9joecm8KsCesA2ysPph1E7cL7Etiw5tGhCFzcdQwm8Gm6SDwj8vCEcZUkXeZJfhlS1cJtZk1sNu3KZNndevtZjRWaXi2m4WNKVxVE-nuaF7V3GWfDemh9RXxyFK8OC8aYLIqcc2pAKJM47ANVty2ll1xaCIB3q3CKdnk5fmsnzKkQI9SjKy70p9TWT-NNoYU682KG_mZo-ByEs5CvJ8w7qysmX8Xpb2I6oSJf7S3qjbqkqtXQcV5MuQ232vk7-g42CcQGL82xvRc09TuvwnmykpKHmjUaJ4U9k9zTN3g2iTdpkvl6vbnND9uG1SBaieVeFYWCT-6VdhovEiD9bvIdA7D_R7NZO8YHBt_lfBQRle_jDyLzHSlkP6kt9dYRhrc2SNMzF_4i3iEUAihbaQYvbNsGwWrHqyGofnva20pRXwc4GxOlw" iex> JOSE.JWS.verify(jwk_ps512, signed_ps512) |> elem(0) true ### RS256, RS384, and RS512 # let's generate the 3 keys we'll use below jwk_rs256 = JOSE.JWK.generate_key({:rsa, 1024}) jwk_rs384 = JOSE.JWK.generate_key({:rsa, 2048}) jwk_rs512 = JOSE.JWK.generate_key({:rsa, 4096}) # RS256 iex> signed_rs256 = JOSE.JWS.sign(jwk_rs256, "{}", %{ "alg" => "RS256" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJSUzI1NiJ9.e30.C0J8v5R-sEe9-g_s0SMgPorCh8VDdaZ9gLpWNm1Tn1Cv2xRph1Xn9Rzm10ZCEs84sj7kxA4v28fVShQ_P1AHN83yQ2mvstkKwsuwXxr-cludx_NLQL5CKKQtTR0ITD_pxUowjfAkBYuJv0677jUj-8lGKs1P5e2dbwW9IqFe4uE" iex> JOSE.JWS.verify(jwk_rs256, signed_rs256) |> elem(0) true # RS384 iex> signed_rs384 = JOSE.JWS.sign(jwk_rs384, "{}", %{ "alg" => "RS384" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJSUzM4NCJ9.e30.fvPxeNhO0oitOsdqFmrBgpGE7Gn_NdJ1J8F5ArKon54pdHB2v30hua9wbG4V2Hr-hNAyflaBJtoGAwIpKVkfHn-IW7d06hKw_Hv0ecG-VvZr60cK2IJnHS149Htz_652egThZh1GIKRZN1IrRVlraLMozFcWP0Ojc-L-g5XjcTFafesmV0GFGfFubAiQWEiWIgNV3822L-wPe7ZGeFe5yYsZ70WMHQQ1tSuNsm5QUOUVInOThAhJ30FRTCNFgv46l4TEF9aaI9443cKAbwzd_EavD0FpvgpwEhGyNTVx0sxiCZIYUE_jN53aSaHXB82d0xwIr2-GXlr3Y-dLwERIMw" iex> JOSE.JWS.verify(jwk_rs384, signed_rs384) |> elem(0) true # RS512 iex> signed_rs512 = JOSE.JWS.sign(jwk_rs512, "{}", %{ "alg" => "RS512" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJSUzUxMiJ9.e30.le2_kCnmj6Y02bl16Hh5EPqmLsFkB3YZpiEfvmA6xfdg9I3QJ5uSgOejs_HpuIbItuMFUdcqtkfW45_6YKlI7plB49iWiNnWY0PLxsvbiZaSmT4R4dOUWx9KlO_Ui5SE94XkigUoFanDTHTr9bh4NpvoIaNdi_xLdC7FYA-AqZspegRcgY-QZQv4kbD3NQJtxsEiAXk8-C8CX3lF6haRlh7s4pyAmgj7SJeElsPjhPNVZ7EduhTLZfVwiLrRmzLKQ6dJ_PrZDig1lgl9jf2NjzcsFpt6lvfrMsDdIQEGyJoh53-zXiD_ltyAZGS3pX-_tHRxoAZ1SyAPkkC4cCra6wc-03sBQPoUa26xyyhrgf4h7E2l-JqhKPXT7pJv6AbRPgKUH4prEH636gpoWQrRc-JxbDIJHR0ShdL8ssf5e-rKpcVVAZKnRI64NbSKXTg-JtDxhU9QG8JVEkHqOxSeo-VSXOoExdmm8lCfqylrw7qmDxjEwOq7TGjhINyjVaK1Op_64BWVuCzgooea6G2ZvCTIEl0-k8wY8s9VC7hxSrsgCAnpWeKpIcbLQoDIoyasG-6Qb5OuSLR367eg9NAQ8WMTbrrQkm-KLNCYvMFaxmlWzBFST2JDmIr0VH9BzXRAdfG81SymuyFA7_FdpiVYwAwEGR4Q5HYEpequ38tHu3Y" iex> JOSE.JWS.verify(jwk_rs512, signed_rs512) |> elem(0) true """ record = Record.extract(:jose_jws, from_lib: "jose/include/jose_jws.hrl") keys = :lists.map(&elem(&1, 0), record) vals = :lists.map(&{&1, [], nil}, keys) pairs = :lists.zip(keys, vals) defstruct keys @type t :: %__MODULE__{} @doc """ Converts a `JOSE.JWS` struct to a `:jose_jws` record. """ def to_record(%JOSE.JWS{unquote_splicing(pairs)}) do {:jose_jws, unquote_splicing(vals)} end def to_record(list) when is_list(list), do: for(element <- list, into: [], do: to_record(element)) @doc """ Converts a `:jose_jws` record into a `JOSE.JWS`. """ def from_record(jose_jws) def from_record({:jose_jws, unquote_splicing(vals)}) do %JOSE.JWS{unquote_splicing(pairs)} end def from_record(list) when is_list(list), do: for(element <- list, into: [], do: from_record(element)) ## Decode API @doc """ Converts a binary or map into a `JOSE.JWS`. iex> JOSE.JWS.from(%{ "alg" => "HS256" }) %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined, fields: %{}} iex> JOSE.JWS.from("{\"alg\":\"HS256\"}") %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined, fields: %{}} Support for custom algorithms may be added by specifying a map tuple: iex> JOSE.JWS.from({%{ alg: MyCustomAlgorithm }, %{ "alg" => "custom" }}) %JOSE.JWS{alg: {MyCustomAlgorithm, :state}, b64: :undefined, fields: %{}} *Note:* `MyCustomAlgorithm` must implement the `:jose_jws` and `:jose_jws_alg` behaviours. """ def from(list) when is_list(list), do: for(element <- list, into: [], do: from(element)) def from(jws = %JOSE.JWS{}), do: from(to_record(jws)) def from(any), do: :jose_jws.from(any) |> from_record() @doc """ Converts a binary into a `JOSE.JWS`. """ def from_binary(list) when is_list(list), do: for(element <- list, into: [], do: from_binary(element)) def from_binary(binary), do: :jose_jws.from_binary(binary) |> from_record() @doc """ Reads file and calls `from_binary/1` to convert into a `JOSE.JWS`. """ def from_file(file), do: :jose_jws.from_file(file) |> from_record() @doc """ Converts a map into a `JOSE.JWS`. """ def from_map(list) when is_list(list), do: for(element <- list, into: [], do: from_map(element)) def from_map(map), do: :jose_jws.from_map(map) |> from_record() ## Encode API @doc """ Converts a `JOSE.JWS` into a binary. """ def to_binary(list) when is_list(list), do: for(element <- list, into: [], do: to_binary(element)) def to_binary(jws = %JOSE.JWS{}), do: to_binary(to_record(jws)) def to_binary(any), do: :jose_jws.to_binary(any) @doc """ Calls `to_binary/1` on a `JOSE.JWS` and then writes the binary to file. """ def to_file(file, jws = %JOSE.JWS{}), do: to_file(file, to_record(jws)) def to_file(file, any), do: :jose_jws.to_file(file, any) @doc """ Converts a `JOSE.JWS` into a map. """ def to_map(list) when is_list(list), do: for(element <- list, into: [], do: to_map(element)) def to_map(jws = %JOSE.JWS{}), do: to_map(to_record(jws)) def to_map(any), do: :jose_jws.to_map(any) ## API @doc """ Compacts an expanded signed map or signed list into a binary. iex> JOSE.JWS.compact(%{"payload" => "e30", "protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}) {%{}, "eyJhbGciOiJIUzI1NiJ9.e30.5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"} iex> JOSE.JWS.compact(%{"payload" => "e30", "signatures" => [ %{"protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}, %{"protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "himAUXqVJnW2ZWOD8zaOZr0YzsA61lo48wu6-WP-Ks0"}]}) {%{}, ["eyJhbGciOiJIUzI1NiJ9.e30.5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU", "eyJhbGciOiJIUzI1NiJ9.e30.himAUXqVJnW2ZWOD8zaOZr0YzsA61lo48wu6-WP-Ks0"]}} See `expand/1`. """ defdelegate compact(signed), to: :jose_jws @doc """ Expands a compacted signed binary or list of signed binaries into a map. iex> JOSE.JWS.expand("eyJhbGciOiJIUzI1NiJ9.e30.5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU") {%{}, %{"payload" => "e30", "protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}} iex> JOSE.JWS.expand([ "eyJhbGciOiJIUzI1NiJ9.e30.5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU", "eyJhbGciOiJIUzI1NiJ9.e30.himAUXqVJnW2ZWOD8zaOZr0YzsA61lo48wu6-WP-Ks0"]) {%{}, %{"payload" => "e30", "signatures" => [ %{"protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}, %{"protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "himAUXqVJnW2ZWOD8zaOZr0YzsA61lo48wu6-WP-Ks0"}]}} See `compact/1`. """ defdelegate expand(signed), to: :jose_jws @doc """ Generates a new `JOSE.JWK` based on the algorithms of the specified `JOSE.JWS`. iex> JOSE.JWS.generate_key(%{"alg" => "HS256"}) %JOSE.JWK{fields: %{"alg" => "HS256", "use" => "sig"}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<150, 71, 29, 79, 228, 32, 218, 4, 111, 250, 212, 129, 226, 173, 86, 205, 72, 48, 98, 100, 66, 68, 113, 13, 43, 60, 122, 248, 179, 44, 140, 24>>}} """ def generate_key(list) when is_list(list), do: for(element <- list, into: [], do: generate_key(element)) def generate_key(jws = %JOSE.JWS{}), do: generate_key(to_record(jws)) def generate_key(any), do: JOSE.JWK.from_record(:jose_jws.generate_key(any)) @doc """ Merges map on right into map on left. """ def merge(left = %JOSE.JWS{}, right), do: merge(left |> to_record(), right) def merge(left, right = %JOSE.JWS{}), do: merge(left, right |> to_record()) def merge(left, right), do: :jose_jws.merge(left, right) |> from_record() @doc """ See `peek_payload/1`. """ defdelegate peek(signed), to: :jose_jws @doc """ Returns the decoded payload portion of a signed binary or map without verifying the signature. iex> JOSE.JWS.peek_payload("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.dMAojPMVbFvvkouYUSI9AxIRBxgqretQMCvNF7KmTHU") "{}" """ defdelegate peek_payload(signed), to: :jose_jws @doc """ Returns the decoded protected portion of a signed binary or map without verifying the signature. iex> JOSE.JWS.peek_protected("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.dMAojPMVbFvvkouYUSI9AxIRBxgqretQMCvNF7KmTHU") "{\"alg\":\"HS256\",\"typ\":\"JWT\"}" """ defdelegate peek_protected(signed), to: :jose_jws @doc """ Returns the decoded signature portion of a signed binary or map without verifying the signature. iex> JOSE.JWS.peek_signature("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.dMAojPMVbFvvkouYUSI9AxIRBxgqretQMCvNF7KmTHU") <<116, 192, 40, 140, 243, 21, 108, 91, 239, 146, 139, 152, 81, 34, 61, 3, 18, 17, 7, 24, 42, 173, 235, 80, 48, 43, 205, 23, 178, 166, 76, 117>> """ defdelegate peek_signature(signed), to: :jose_jws @doc """ Signs the `plain_text` using the `jwk` and algorithm specified by the `jws`. iex> jwk = JOSE.JWK.from(%{"k" => "qUg4Yw", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<169, 72, 56, 99>>}} iex> JOSE.JWS.sign(jwk, "{}", %{ "alg" => "HS256" }) {%{alg: :jose_jws_alg_hmac}, %{"payload" => "e30", "protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}} If the `jwk` has a `"kid"` assigned, it will be added to the `"header"` on the signed map: iex> jwk = JOSE.JWK.from(%{"k" => "qUg4Yw", "kid" => "eyHC48MN26DvoBpkaudvOVXuI5Sy8fKMxQMYiRWmjFw", "kty" => "oct"}) %JOSE.JWK{fields: %{"kid" => "eyHC48MN26DvoBpkaudvOVXuI5Sy8fKMxQMYiRWmjFw"}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<169, 72, 56, 99>>}} iex> JOSE.JWS.sign(jwk, "test", %{ "alg" => "HS256" }) {%{alg: :jose_jws_alg_hmac}, %{"header" => %{"kid" => "eyHC48MN26DvoBpkaudvOVXuI5Sy8fKMxQMYiRWmjFw"}, "payload" => "e30", "protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}} A list of `jwk` keys can also be specified to produce a signed list: iex> jwk1 = JOSE.JWK.from(%{"k" => "qUg4Yw", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<169, 72, 56, 99>>}} iex> jwk2 = JOSE.JWK.from_map(%{"k" => "H-v_Nw", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<31, 235, 255, 55>>}} iex> JOSE.JWS.sign([jwk1, jwk2], "{}", %{ "alg" => "HS256" }) {%{alg: :jose_jws_alg_hmac}, %{"payload" => "e30", "signatures" => [ %{"protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}, %{"protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "himAUXqVJnW2ZWOD8zaOZr0YzsA61lo48wu6-WP-Ks0"}]}} *Note:* Signed maps with a `"header"` or other fields will have data loss when used with `compact/1`. """ def sign(jwk = %JOSE.JWK{}, plain_text, jws), do: sign(JOSE.JWK.to_record(jwk), plain_text, jws) def sign(jwk, plain_text, jws = %JOSE.JWS{}), do: sign(jwk, plain_text, to_record(jws)) def sign(key_list, plain_text, signer_list) when is_list(key_list) and is_list(signer_list) and length(key_list) === length(signer_list) do keys = for key <- key_list, into: [] do case key do %JOSE.JWK{} -> JOSE.JWK.to_record(key) _ -> key end end signers = for signer <- signer_list, into: [] do case signer do %JOSE.JWS{} -> JOSE.JWS.to_record(signer) _ -> signer end end :jose_jws.sign(keys, plain_text, signers) end def sign(key_list, plain_text, jws) when is_list(key_list) and not is_list(jws) do keys = for key <- key_list, into: [] do case key do %JOSE.JWK{} -> JOSE.JWK.to_record(key) _ -> key end end :jose_jws.sign(keys, plain_text, jws) end def sign(jwk, plain_text, signer_list) when is_list(signer_list) and not is_list(jwk) do signers = for signer <- signer_list, into: [] do case signer do %JOSE.JWS{} -> JOSE.JWS.to_record(signer) _ -> signer end end :jose_jws.sign(jwk, plain_text, signers) end def sign(jwk, plain_text, jws), do: :jose_jws.sign(jwk, plain_text, jws) @doc """ Signs the `plain_text` using the `jwk` and algorithm specified by the `jws` and adds the `header` to the signed map. iex> jwk = JOSE.JWK.from(%{"k" => "qUg4Yw", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<169, 72, 56, 99>>}} iex> JOSE.JWS.sign(jwk, "{}", %{ "test" => true }, %{ "alg" => "HS256" }) {%{alg: :jose_jws_alg_hmac}, %{"header" => %{"test" => true}, "payload" => "e30", "protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}} If the `jwk` has a `"kid"` assigned, it will be added to the `"header"` on the signed map. See `sign/3`. """ def sign(jwk = %JOSE.JWK{}, plain_text, header, jws), do: sign(JOSE.JWK.to_record(jwk), plain_text, header, jws) def sign(jwk, plain_text, header, jws = %JOSE.JWS{}), do: sign(jwk, plain_text, header, to_record(jws)) def sign(key_list, plain_text, header, signer) when is_list(key_list) and is_map(header) and not is_list(signer) do headers = for _ <- key_list, into: [], do: header signers = for _ <- key_list, into: [], do: signer sign(key_list, plain_text, headers, signers) end def sign(key_list, plain_text, header, signer_list) when is_list(key_list) and is_map(header) and is_list(signer_list) and length(key_list) === length(signer_list) do headers = for _ <- key_list, into: [], do: header sign(key_list, plain_text, headers, signer_list) end def sign(key_list, plain_text, header_list, signer) when is_list(key_list) and is_list(header_list) and not is_list(signer) and length(key_list) === length(header_list) do signers = for _ <- key_list, into: [], do: signer sign(key_list, plain_text, header_list, signers) end def sign(key_list, plain_text, header_list, signer_list) when is_list(key_list) and is_list(header_list) and is_list(signer_list) and length(key_list) === length(signer_list) and length(key_list) === length(header_list) do keys = for key <- key_list, into: [] do case key do %JOSE.JWK{} -> JOSE.JWK.to_record(key) _ -> key end end signers = for signer <- signer_list, into: [] do case signer do %JOSE.JWS{} -> JOSE.JWS.to_record(signer) _ -> signer end end :jose_jws.sign(keys, plain_text, header_list, signers) end def sign(jwk = [%JOSE.JWK{} | _], plain_text, header, jws) do sign( for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end, plain_text, header, jws ) end def sign(jwk, plain_text, header, jws), do: :jose_jws.sign(jwk, plain_text, header, jws) @doc """ Converts the `jws` to the `protected` argument used by `signing_input/3`. """ def signing_input(payload, jws = %JOSE.JWS{}), do: signing_input(payload, to_record(jws)) def signing_input(payload, jws), do: :jose_jws.signing_input(payload, jws) @doc """ Combines `payload` and `protected` based on the `"b64"` setting on the `jws` for the signing input used by `sign/3` and `sign/4`. If `"b64"` is set to `false` on the `jws`, the raw `payload` will be used: iex> JOSE.JWS.signing_input("{}", %{ "alg" => "HS256" }) "eyJhbGciOiJIUzI1NiJ9.e30" iex> JOSE.JWS.signing_input("{}", %{ "alg" => "HS256", "b64" => false }) "eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2V9.{}" See [JWS Unencoded Payload Option](https://tools.ietf.org/html/draft-ietf-jose-jws-signing-input-options-04) for more information. """ def signing_input(payload, protected, jws = %JOSE.JWS{}), do: signing_input(payload, protected, to_record(jws)) def signing_input(payload, protected, jws), do: :jose_jws.signing_input(payload, protected, jws) @doc """ Verifies the `signed` using the `jwk`. iex> jwk = JOSE.JWK.from(%{"k" => "qUg4Yw", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<169, 72, 56, 99>>}} iex> JOSE.JWS.verify(jwk, "eyJhbGciOiJIUzI1NiJ9.e30.5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU") {true, "{}", %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined, fields: %{}}} A list of `jwk` keys can also be specified where each key will be used to verify every entry in a signed list: iex> jwk1 = JOSE.JWK.from(%{"k" => "qUg4Yw", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<169, 72, 56, 99>>}} iex> jwk2 = JOSE.JWK.from_map(%{"k" => "H-v_Nw", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<31, 235, 255, 55>>}} iex> JOSE.JWS.verify([jwk1, jwk2], %{"payload" => "e30", "signatures" => [ %{"protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU"}, %{"protected" => "eyJhbGciOiJIUzI1NiJ9", "signature" => "himAUXqVJnW2ZWOD8zaOZr0YzsA61lo48wu6-WP-Ks0"}]}) [{%JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<169, 72, 56, 99>>}}, [{true, "{}", %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined, fields: %{}}}, {false, "{}", %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined, fields: %{}}}]}, {%JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<31, 235, 255, 55>>}}, [{false, "{}", %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined, fields: %{}}}, {true, "{}", %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined, fields: %{}}}]}] """ def verify(jwk = %JOSE.JWK{}, signed), do: verify(JOSE.JWK.to_record(jwk), signed) def verify(jwk = [%JOSE.JWK{} | _], signed) do verify( for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end, signed ) end def verify(key, signed) do try do case :jose_jws.verify(key, signed) do {verified, payload, jws} when is_tuple(jws) -> {verified, payload, from_record(jws)} list when is_list(list) -> for {jwk, verifications} <- list do {JOSE.JWK.from_record(jwk), for {verified, payload, jws} <- verifications do {verified, payload, from_record(jws)} end} end error -> error end catch class, reason -> {class, reason} end end @doc """ Same as `verify/2`, but uses `allow` as a whitelist for `"alg"` which are allowed to verify against. If the detected algorithm is not present in `allow`, then `false` is returned. iex> jwk = JOSE.JWK.from(%{"k" => "qUg4Yw", "kty" => "oct"}) %JOSE.JWK{fields: %{}, keys: :undefined, kty: {:jose_jwk_kty_oct, <<169, 72, 56, 99>>}} iex> signed_hs256 = JOSE.JWS.sign(jwk, "{}", %{ "alg" => "HS256" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJIUzI1NiJ9.e30.5paAJxaOXSqRUIXrP_vJXUZu2SCBH-ojgP4D6Xr6GPU" iex> signed_hs512 = JOSE.JWS.sign(jwk, "{}", %{ "alg" => "HS512" }) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJIUzUxMiJ9.e30.DN_JCks5rzQiDJJ15E6uJFskAMw-KcasGINKK_4S8xKo7W6tZ-a00ZL8UWOWgE7oHpcFrYnvSpNRldAMp19iyw" iex> JOSE.JWS.verify_strict(jwk, ["HS256"], signed_hs256) |> elem(0) true iex> JOSE.JWS.verify_strict(jwk, ["HS256"], signed_hs512) |> elem(0) false iex> JOSE.JWS.verify_strict(jwk, ["HS256", "HS512"], signed_hs512) |> elem(0) true """ def verify_strict(jwk = %JOSE.JWK{}, allow, signed), do: verify_strict(JOSE.JWK.to_record(jwk), allow, signed) def verify_strict(jwk = [%JOSE.JWK{} | _], allow, signed) do verify_strict( for k <- jwk do case k do %JOSE.JWK{} -> JOSE.JWK.to_record(k) _ -> k end end, allow, signed ) end def verify_strict(key, allow, signed) do try do case :jose_jws.verify_strict(key, allow, signed) do {verified, payload, jws} when is_tuple(jws) -> {verified, payload, from_record(jws)} list when is_list(list) -> for {jwk, verifications} <- list do {JOSE.JWK.from_record(jwk), for {verified, payload, jws} <- verifications do {verified, payload, from_record(jws)} end} end error -> error end catch class, reason -> {class, reason} end end end erlang-jose-1.10.1/mix.lock0000644000232200023220000000365513605433351016031 0ustar debalancedebalance%{ "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "jsone": {:hex, :jsone, "1.5.2", "87adea283c9cf24767b4deed44602989a5331156df5d60a2660e9c9114d54046", [:rebar3], [], "hexpm"}, "jsx": {:hex, :jsx, "2.10.0", "77760560d6ac2b8c51fd4c980e9e19b784016aa70be354ce746472c33beb0b1c", [:rebar3], [], "hexpm"}, "libdecaf": {:hex, :libdecaf, "1.0.0", "3003f64cbdaf534f62f4489ba4b911b8fa7c9bee6c325ffbc372fc11357cc174", [:rebar3], [], "hexpm"}, "libsodium": {:hex, :libsodium, "0.0.10", "24584e6f5a60aed53542054c15fb31719bbf2d811d9a84f626734faf64d41304", [:rebar3], [], "hexpm"}, "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"}, "ojson": {:hex, :ojson, "1.0.0", "fd28614eadaec00a15cdb2f53f29d8717a812a508ddb80d202f2f2e2aaeabbcc", [:mix, :rebar3], [], "hexpm"}, "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm"}, } erlang-jose-1.10.1/README.md0000644000232200023220000005574413605433351015647 0ustar debalancedebalance# JOSE [![Build Status](https://travis-ci.org/potatosalad/erlang-jose.svg?branch=master)](https://travis-ci.org/potatosalad/erlang-jose) [![Hex.pm](https://img.shields.io/hexpm/v/jose.svg)](https://hex.pm/packages/jose) JSON Object Signing and Encryption (JOSE) for Erlang and Elixir. ## Installation Add `jose` to your project's dependencies in `mix.exs` ```elixir defp deps() do [ {:jose, "~> 1.10.1"} ] end ``` If you are using deployment tools (`exrm`, etc.) and your app depends on `jose` directly, you will need to include `jose` in your applications list in `mix.exs` to ensure they get compiled into your release: ```elixir def application() do [ mod: {YourApp, []}, applications: [:jose] ] end ``` Add `jose` to your project's dependencies in your `Makefile` for [`erlang.mk`](https://github.com/ninenines/erlang.mk) or the following to your `rebar.config` ```erlang {deps, [ {jose, ".*", {git, "git://github.com/potatosalad/erlang-jose.git", {branch, "master"}}} ]}. ``` #### JSON Encoder/Decoder You will also need to specify either [jiffy](https://github.com/davisp/jiffy), [jsone](https://github.com/sile/jsone), [jsx](https://github.com/talentdeficit/jsx), [ojson](https://github.com/potatosalad/erlang-ojson), [Poison](https://github.com/devinus/poison), or [Jason](https://github.com/michalmuskala/jason) as a dependency. For example, with Elixir and `mix.exs` ```elixir defp deps() do [ {:jose, "~> 1.10.1"}, {:ojson, "~> 1.0"} ] end ``` Or with Erlang and `rebar.config` ```erlang {deps, [ {jose, ".*", {git, "git://github.com/potatosalad/erlang-jose.git", {branch, "master"}}}, {ojson, ".*", {git, "git://github.com/potatosalad/erlang-ojson.git", {branch, "master"}}} ]}. ``` `jose` will attempt to find a suitable JSON encoder/decoder and will try to use (in order) ojson, Jason, Poison, jiffy, jsone, or jsx. You may also specify a different `json_module` as an application environment variable to `jose` or by using `jose:json_module/1` or `JOSE.json_module/1`. #### ChaCha20/Poly1305 Support ChaCha20/Poly1305 encryption and one-time message authentication functions are experimentally supported based on [RFC 7539](https://tools.ietf.org/html/rfc7539). Fallback support for `ChaCha20/Poly1305` encryption and `Poly1305` signing is also provided. See [`crypto_fallback`](#cryptographic-algorithm-fallback) below. External support is also provided by the following libraries: * [libsodium](https://github.com/potatosalad/erlang-libsodium) - `ChaCha20/Poly1305` encryption and `Poly1305` signing Other modules which implement the `jose_chacha20_poly1305` behavior may also be used as follows: ```elixir # ChaCha20/Poly1305 JOSE.chacha20_poly1305_module(:libsodium) # uses a fast Erlang port driver for libsodium JOSE.chacha20_poly1305_module(:jose_jwa_chacha20_poly1305) # uses the pure Erlang implementation (slow) ``` #### Curve25519 and Curve448 Support Curve25519 and Curve448 and their associated signing/key exchange functions are supported now that [RFC 8037](https://tools.ietf.org/html/rfc8037) has been published. Fallback support for `Ed25519`, `Ed25519ph`, `Ed448`, `Ed448ph`, `X25519`, and `X448` is provided. See [`crypto_fallback`](#cryptographic-algorithm-fallback) below. External support is also provided by the following libraries: * [libdecaf](https://github.com/potatosalad/erlang-libdecaf) - `Ed25519`, `Ed25519ph`, `Ed448`, `Ed448ph`, `X25519`, `X448` * [libsodium](https://github.com/potatosalad/erlang-libsodium) - `Ed25519`, `Ed25519ph`, `X25519` If both libraries are present, libdecaf will be used by default. Other modules which implement the `jose_curve25519` or `jose_curve448` behaviors may also be used as follows: ```elixir # Curve25519 JOSE.curve25519_module(:libdecaf) # uses a fast Erlang NIF for libdecaf JOSE.curve25519_module(:jose_jwa_curve25519) # uses the pure Erlang implementation (slow) # Curve448 JOSE.curve448_module(:libdecaf) # uses a fast Erlang NIF for libdecaf JOSE.curve448_module(:jose_jwa_curve448) # uses the pure Erlang implementation (slow) ``` #### SHA-3 Support SHA-3 is experimentally supported for use with `Ed448` and `Ed448ph` signing functions. Fallback support for SHA-3 is provided. See [`crypto_fallback`](#cryptographic-algorithm-fallback) below. External support for SHA-3 is provided by the [keccakf1600](https://github.com/potatosalad/erlang-keccakf1600) and [libdecaf](https://github.com/potatosalad/erlang-libdecaf) libraries. If present, keccakf1600 will be used by default. Other modules which implement the `jose_sha3` behaviors may also be used as follows: ```elixir JOSE.sha3_module(:keccakf1600) # uses a NIF written in C with timeslice reductions JOSE.sha3_module(:jose_jwa_sha3) # uses the pure Erlang implementation (slow) ``` #### Cryptographic Algorithm Fallback `jose` strives to support [all](#algorithm-support) of the cryptographic algorithms specified in the [JOSE RFCs](https://tools.ietf.org/wg/jose/). However, not all of the required algorithms are supported natively by Erlang/Elixir. For algorithms unsupported by the native [`crypto`](http://www.erlang.org/doc/man/crypto.html) and [`public_key`](http://www.erlang.org/doc/man/public_key.html), `jose` has a pure Erlang implementation that may be used as a fallback. See [ALGORITHMS.md](https://github.com/potatosalad/erlang-jose/blob/master/ALGORITHMS.md) for more information about algorithm support for specific OTP versions. By default, the algorithm fallback is disabled, but can be enabled by setting the `crypto_fallback` application environment variable for `jose` to `true` or by calling `jose:crypto_fallback/1` or `JOSE.crypto_fallback/1` with `true`. You may also review which algorithms are currently supported with the `jose_jwa:supports/0` or `JOSE.JWA.supports/0` functions. For example, on Elixir 1.9.4 and OTP 22: ```elixir # crypto_fallback defaults to false JOSE.JWA.supports() [ {:jwe, {:alg, ["A128GCMKW", "A128KW", "A192GCMKW", "A192KW", "A256GCMKW", "A256KW", "C20PKW", "ECDH-1PU", "ECDH-1PU+A128GCMKW", "ECDH-1PU+A128KW", "ECDH-1PU+A192GCMKW", "ECDH-1PU+A192KW", "ECDH-1PU+A256GCMKW", "ECDH-1PU+A256KW", "ECDH-1PU+C20PKW", "ECDH-ES", "ECDH-ES+A128GCMKW", "ECDH-ES+A128KW", "ECDH-ES+A192GCMKW", "ECDH-ES+A192KW", "ECDH-ES+A256GCMKW", "ECDH-ES+A256KW", "ECDH-ES+C20PKW", "PBES2-HS256+A128GCMKW", "PBES2-HS256+A128KW", "PBES2-HS384+A192GCMKW", "PBES2-HS384+A192KW", "PBES2-HS512+A256GCMKW", "PBES2-HS512+A256KW", "PBES2-HS512+C20PKW", "RSA-OAEP", "RSA-OAEP-256", "RSA1_5", "dir"]}, {:enc, ["A128CBC-HS256", "A128GCM", "A192CBC-HS384", "A192GCM", "A256CBC-HS512", "A256GCM", "C20P"]}, {:zip, ["DEF"]}}, {:jwk, {:kty, ["EC", "OKP", "RSA", "oct"]}, {:kty_OKP_crv, []}}, {:jws, {:alg, ["ES256", "ES384", "ES512", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512", "Poly1305", "RS256", "RS384", "RS512"]}} ] # setting crypto_fallback to true JOSE.crypto_fallback(true) # additional algorithms are now available for use JOSE.JWA.supports() [ {:jwe, {:alg, ["A128GCMKW", "A128KW", "A192GCMKW", "A192KW", "A256GCMKW", "A256KW", "C20PKW", "ECDH-1PU", "ECDH-1PU+A128GCMKW", "ECDH-1PU+A128KW", "ECDH-1PU+A192GCMKW", "ECDH-1PU+A192KW", "ECDH-1PU+A256GCMKW", "ECDH-1PU+A256KW", "ECDH-1PU+C20PKW", "ECDH-1PU+XC20PKW", "ECDH-ES", "ECDH-ES+A128GCMKW", "ECDH-ES+A128KW", "ECDH-ES+A192GCMKW", "ECDH-ES+A192KW", "ECDH-ES+A256GCMKW", "ECDH-ES+A256KW", "ECDH-ES+C20PKW", "ECDH-ES+XC20PKW", "PBES2-HS256+A128GCMKW", "PBES2-HS256+A128KW", "PBES2-HS384+A192GCMKW", "PBES2-HS384+A192KW", "PBES2-HS512+A256GCMKW", "PBES2-HS512+A256KW", "PBES2-HS512+C20PKW", "PBES2-HS512+XC20PKW", "RSA-OAEP", "RSA-OAEP-256", "RSA1_5", "XC20PKW", "dir"]}, {:enc, ["A128CBC-HS256", "A128GCM", "A192CBC-HS384", "A192GCM", "A256CBC-HS512", "A256GCM", "C20P", "XC20P"]}, {:zip, ["DEF"]}}, {:jwk, {:kty, ["EC", "OKP", "RSA", "oct"]}, {:kty_OKP_crv, ["Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "X25519", "X448"]}}, {:jws, {:alg, ["ES256", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512", "Poly1305", "RS256", "RS384", "RS512"]}} ] ``` #### Unsecured Signing Vulnerability The [`"none"`](https://tools.ietf.org/html/rfc7515#appendix-A.5) signing algorithm is disabled by default to prevent accidental verification of empty signatures (read about the vulnerability [here](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/)). If you want to further restrict the signature algorithms allowed for a token, use `JOSE.JWT.verify_strict/3`: ```elixir # Signed Compact JSON Web Token (JWT) with HS256 token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM" # JSON Web Key (JWK) jwk = %{ "kty" => "oct", "k" => :jose_base64url.encode("symmetric key") } {verified, _, _} = JOSE.JWT.verify_strict(jwk, ["HS256"], token) # {true, _, _} {verified, _, _} = JOSE.JWT.verify_strict(jwk, ["RS256"], token) # {false, _, _} ``` If you need to inspect the contents of a JSON Web token (JWT) prior to verifying it, use `JOSE.JWT.peek_payload/1` or `JOSE.JWT.peek_protected/1`: ```elixir token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM" payload = JOSE.JWT.peek_payload(token) # %JOSE.JWT{fields: %{"exp" => 1300819380, "http://example.com/is_root" => true, # "iss" => "joe"}} protected = JOSE.JWT.peek_protected(token) # %JOSE.JWS{alg: {:jose_jws_alg_hmac, {:jose_jws_alg_hmac, :sha256}}, # b64: :undefined, fields: %{"typ" => "JWT"}} # If you want to inspect the JSON, you can convert it back to a regular map: {_, protected_map} = JOSE.JWS.to_map(protected) # {_, %{"alg" => "HS256", "typ" => "JWT"}} ``` You may also enable the `"none"` algorithm as an application environment variable for `jose` or by using `jose:unsecured_signing/1` or `JOSE.unsecured_signing/1`. ```elixir # unsecured_signing defaults to false JOSE.JWA.supports[:jws] {:alg, ["ES256", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512", "Poly1305", "RS256", "RS384", "RS512"]} # setting unsecured_signing to true JOSE.unsecured_signing(true) # the "none" algorithm is now available for use JOSE.JWA.supports[:jws] {:alg, ["ES256", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448", "Ed448ph", "HS256", "HS384", "HS512", "PS256", "PS384", "PS512", "Poly1305", "RS256", "RS384", "RS512", "none"]} ``` ## Usage ##### JSON Web Signature (JWS) of JSON Web Token (JWT) using HMAC using SHA-256 (HS256) with JSON Web Key (JWK) _Elixir_ ```elixir # JSON Web Key (JWK) jwk = %{ "kty" => "oct", "k" => :jose_base64url.encode("symmetric key") } # JSON Web Signature (JWS) jws = %{ "alg" => "HS256" } # JSON Web Token (JWT) jwt = %{ "iss" => "joe", "exp" => 1300819380, "http://example.com/is_root" => true } signed = JOSE.JWT.sign(jwk, jws, jwt) # {%{alg: :jose_jws_alg_hmac}, # %{"payload" => "eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ", # "protected" => "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", # "signature" => "shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM"}} compact_signed = JOSE.JWS.compact(signed) # {%{alg: :jose_jws_alg_hmac}, # "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM"} verified = JOSE.JWT.verify(jwk, compact_signed) # {true, # %JOSE.JWT{fields: %{"exp" => 1300819380, "http://example.com/is_root" => true, # "iss" => "joe"}}, # %JOSE.JWS{alg: {:jose_jws_alg_hmac, :HS256}, b64: :undefined, # fields: %{"typ" => "JWT"}}} verified == JOSE.JWT.verify(jwk, signed) # true ``` _Erlang_ ```erlang % JSON Web Key (JWK) JWK = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_base64url:encode(<<"symmetric key">>) }. % JSON Web Signature (JWS) JWS = #{ <<"alg">> => <<"HS256">> }. % JSON Web Token (JWT) JWT = #{ <<"iss">> => <<"joe">>, <<"exp">> => 1300819380, <<"http://example.com/is_root">> => true }. Signed = jose_jwt:sign(JWK, JWS, JWT). % {#{alg => jose_jws_alg_hmac}, % #{<<"payload">> => <<"eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ">>, % <<"protected">> => <<"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9">>, % <<"signature">> => <<"shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM">>}} CompactSigned = jose_jws:compact(Signed). % {#{alg => jose_jws_alg_hmac}, % <<"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM">>} Verified = jose_jwt:verify(JWK, CompactSigned). % {true, % #jose_jwt{ % fields = % #{<<"exp">> => 1300819380, % <<"http://example.com/is_root">> => true, % <<"iss">> => <<"joe">>}}, % #jose_jws{ % alg = {jose_jws_alg_hmac,'HS256'}, % b64 = undefined, % fields = #{<<"typ">> => <<"JWT">>}}} Verified =:= jose_jwt:verify(JWK, Signed). % true ``` ##### Reading JSON Web Keys (JWK) from PEM files The examples below use three keys created with `openssl`: ```bash # RSA Private Key openssl genrsa -out rsa-2048.pem 2048 # EC Private Key (Alice) openssl ecparam -name secp256r1 -genkey -noout -out ec-secp256r1-alice.pem # EC Private Key (Bob) openssl ecparam -name secp256r1 -genkey -noout -out ec-secp256r1-bob.pem ``` _Elixir_ ```elixir # RSA examples rsa_private_jwk = JOSE.JWK.from_pem_file("rsa-2048.pem") rsa_public_jwk = JOSE.JWK.to_public(rsa_private_jwk) ## Sign and Verify (defaults to PS256) message = "my message" signed = JOSE.JWK.sign(message, rsa_private_jwk) {true, ^message, _} = JOSE.JWK.verify(signed, rsa_public_jwk) ## Sign and Verify (specify RS256) signed = JOSE.JWK.sign(message, %{ "alg" => "RS256" }, rsa_private_jwk) {true, ^message, _} = JOSE.JWK.verify(signed, rsa_public_jwk) ## Encrypt and Decrypt (defaults to RSA-OAEP with A128CBC-HS256) plain_text = "my plain text" encrypted = JOSE.JWK.block_encrypt(plain_text, rsa_public_jwk) {^plain_text, _} = JOSE.JWK.block_decrypt(encrypted, rsa_private_jwk) ## Encrypt and Decrypt (specify RSA-OAEP-256 with A128GCM) encrypted = JOSE.JWK.block_encrypt(plain_text, %{ "alg" => "RSA-OAEP-256", "enc" => "A128GCM" }, rsa_public_jwk) {^plain_text, _} = JOSE.JWK.block_decrypt(encrypted, rsa_private_jwk) # EC examples alice_private_jwk = JOSE.JWK.from_pem_file("ec-secp256r1-alice.pem") alice_public_jwk = JOSE.JWK.to_public(alice_private_jwk) bob_private_jwk = JOSE.JWK.from_pem_file("ec-secp256r1-bob.pem") bob_public_jwk = JOSE.JWK.to_public(bob_private_jwk) ## Sign and Verify (defaults to ES256) message = "my message" signed = JOSE.JWK.sign(message, alice_private_jwk) {true, ^message, _} = JOSE.JWK.verify(signed, alice_public_jwk) ## Encrypt and Decrypt (defaults to ECDH-ES with A128GCM) ### Alice sends Bob a secret message using Bob's public key and Alice's private key alice_to_bob = "For Bob's eyes only." encrypted = JOSE.JWK.box_encrypt(alice_to_bob, bob_public_jwk, alice_private_jwk) ### Only Bob can decrypt the message using his private key (Alice's public key is embedded in the JWE header) {^alice_to_bob, _} = JOSE.JWK.box_decrypt(encrypted, bob_private_jwk) ``` _Erlang_ ```erlang % RSA examples RSAPrivateJWK = jose_jwk:from_pem_file("rsa-2048.pem"), RSAPublicJWK = jose_jwk:to_public(RSAPrivateJWK). %% Sign and Verify (defaults to PS256) Message = <<"my message">>, SignedPS256 = jose_jwk:sign(Message, RSAPrivateJWK), {true, Message, _} = jose_jwk:verify(SignedPS256, RSAPublicJWK). %% Sign and Verify (specify RS256) SignedRS256 = jose_jwk:sign(Message, #{ <<"alg">> => <<"RS256">> }, RSAPrivateJWK), {true, Message, _} = jose_jwk:verify(SignedRS256, RSAPublicJWK). %% Encrypt and Decrypt (defaults to RSA-OAEP with A128CBC-HS256) PlainText = <<"my plain text">>, EncryptedRSAOAEP = jose_jwk:block_encrypt(PlainText, RSAPublicJWK), {PlainText, _} = jose_jwk:block_decrypt(EncryptedRSAOAEP, RSAPrivateJWK). %% Encrypt and Decrypt (specify RSA-OAEP-256 with A128GCM) EncryptedRSAOAEP256 = jose_jwk:block_encrypt(PlainText, #{ <<"alg">> => <<"RSA-OAEP-256">>, <<"enc">> => <<"A128GCM">> }, RSAPublicJWK), {PlainText, _} = jose_jwk:block_decrypt(EncryptedRSAOAEP256, RSAPrivateJWK). % EC examples AlicePrivateJWK = jose_jwk:from_pem_file("ec-secp256r1-alice.pem"), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), BobPrivateJWK = jose_jwk:from_pem_file("ec-secp256r1-bob.pem"), BobPublicJWK = jose_jwk:to_public(BobPrivateJWK). %% Sign and Verify (defaults to ES256) Message = <<"my message">>, SignedES256 = jose_jwk:sign(Message, AlicePrivateJWK), {true, Message, _} = jose_jwk:verify(SignedES256, AlicePublicJWK). %% Encrypt and Decrypt (defaults to ECDH-ES with A128GCM) %%% Alice sends Bob a secret message using Bob's public key and Alice's private key AliceToBob = <<"For Bob's eyes only.">>, EncryptedECDHES = jose_jwk:box_encrypt(AliceToBob, BobPublicJWK, AlicePrivateJWK), %%% Only Bob can decrypt the message using his private key (Alice's public key is embedded in the JWE header) {AliceToBob, _} = jose_jwk:box_decrypt(EncryptedECDHES, BobPrivateJWK). ``` ## Algorithm Support ### JSON Web Encryption (JWE) [RFC 7516](https://tools.ietf.org/html/rfc7516) #### `"alg"` [RFC 7518 Section 4](https://tools.ietf.org/html/rfc7518#section-4) - [X] `A128GCMKW` - [X] `A192GCMKW` - [X] `A256GCMKW` - [X] `A128KW` - [X] `A192KW` - [X] `A256KW` - [X] `C20PKW` [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01) - [X] `dir` - [X] `ECDH-1PU` - [X] `ECDH-1PU+A128GCMKW` non-standard, [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02) - [X] `ECDH-1PU+A192GCMKW` non-standard, [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02) - [X] `ECDH-1PU+A256GCMKW` non-standard, [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02) - [X] `ECDH-1PU+A128KW` [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02) - [X] `ECDH-1PU+A192KW` [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02) - [X] `ECDH-1PU+A256KW` [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02) - [X] `ECDH-1PU+C20PKW` [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01), [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02) - [X] `ECDH-1PU+XC20PKW` [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01), [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02) - [X] `ECDH-ES` - [X] `ECDH-ES+A128GCMKW` non-standard - [X] `ECDH-ES+A192GCMKW` non-standard - [X] `ECDH-ES+A256GCMKW` non-standard - [X] `ECDH-ES+A128KW` - [X] `ECDH-ES+A192KW` - [X] `ECDH-ES+A256KW` - [X] `ECDH-ES+C20PKW` [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01) - [X] `ECDH-ES+XC20PKW` [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01) - [X] `PBES2-HS256+A128GCMKW` non-standard - [X] `PBES2-HS384+A192GCMKW` non-standard - [X] `PBES2-HS512+A256GCMKW` non-standard - [X] `PBES2-HS256+A128KW` - [X] `PBES2-HS384+A192KW` - [X] `PBES2-HS512+A256KW` - [X] `PBES2-HS512+C20PKW` non-standard - [X] `PBES2-HS512+XC20PKW` non-standard - [X] `RSA1_5` - [X] `RSA-OAEP` - [X] `RSA-OAEP-256` - [X] `XC20PKW` [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01) #### `"enc"` [RFC 7518 Section 5](https://tools.ietf.org/html/rfc7518#section-5) - [X] `A128CBC-HS256` - [X] `A192CBC-HS384` - [X] `A256CBC-HS512` - [X] `A128GCM` - [X] `A192GCM` - [X] `A256GCM` - [X] `C20P` [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01) - [X] `XC20P` [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01) #### `"zip"` [RFC 7518 Section 7.3](https://tools.ietf.org/html/rfc7518#section-7.3) - [X] `DEF` ### JSON Web Key (JWK) [RFC 7517](https://tools.ietf.org/html/rfc7517) #### `"alg"` [RFC 7518 Section 6](https://tools.ietf.org/html/rfc7518#section-6) - [X] `EC` - [X] `oct` - [X] `OKP` [RFC 8037](https://tools.ietf.org/html/rfc8037) - [X] `OKP` with `{"crv":"Ed25519"}` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032#section-5.1) - [X] `OKP` with `{"crv":"Ed25519ph"}` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032#section-5.1) - [X] `OKP` with `{"crv":"Ed448"}` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032#section-5.2) - [X] `OKP` with `{"crv":"Ed448ph"}` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032#section-5.2) - [X] `OKP` with `{"crv":"X25519"}` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 7748](https://tools.ietf.org/html/rfc7748#section-5) - [X] `OKP` with `{"crv":"X448"}` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 7748](https://tools.ietf.org/html/rfc7748#section-5) - [X] `RSA` ### JSON Web Signature (JWS) [RFC 7515](https://tools.ietf.org/html/rfc7515) #### `"alg"` [RFC 7518 Section 3](https://tools.ietf.org/html/rfc7518#section-3) - [X] `Ed25519` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032#section-5.1) - [X] `Ed25519ph` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032#section-5.1) - [X] `Ed448` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032#section-5.2) - [X] `Ed448ph` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032#section-5.2) - [X] `EdDSA` [RFC 8037](https://tools.ietf.org/html/rfc8037), [RFC 8032](https://tools.ietf.org/html/rfc8032) - [X] `ES256` - [X] `ES384` - [X] `ES512` - [X] `HS256` - [X] `HS384` - [X] `HS512` - [X] `Poly1305` non-standard - [X] `PS256` - [X] `PS384` - [X] `PS512` - [X] `RS256` - [X] `RS384` - [X] `RS512` - [X] `none` [unsecured](#footnote-unsecured) ### Additional Specifications - [X] JSON Web Key (JWK) Thumbprint [RFC 7638](https://tools.ietf.org/html/rfc7638) - [X] JWS Unencoded Payload Option [RFC 7797](https://tools.ietf.org/html/rfc7797) unsecured This algorithm is disabled by default due to the unsecured signing vulnerability. Use the [`unsecured_signing`](#unsecured-signing-vulnerability) setting to enable this algorithm. erlang-jose-1.10.1/CHANGELOG.md0000644000232200023220000004300013605433351016157 0ustar debalancedebalance# Changelog ## 1.10.1 (2020-01-08) * Fixes * Add PEM/DER compatibility layer for PKCS-8 incompatibilities with various versions of OTP, `crypto`, and `public_key`; see [#82](https://github.com/potatosalad/erlang-jose/issues/82) ## 1.10.0 (2020-01-03) * Enhancements * Remove [base64url](https://github.com/dvv/base64url) dependency and include embedded version. * Add support for `C20P` and `XC20P` encryption based on [draft-amringer-jose-chacha](https://tools.ietf.org/html/draft-amringer-jose-chacha-01) (ChaCha20/Poly1305 and XChaCha20/Poly1305). * Add support for ECDH-ES keywrapping for AES-GCM, ChaCha20/Poly1305, and XChaCha20/Poly1305. * Add support for PBES2 keywrapping for AES-GCM, ChaCha20/Poly1305, and XChaCha20/Poly1305. * Add support for `ECDH-1PU` encryption based on [draft-madden-jose-ecdh-1pu](https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02). * Add support for reading/writing DER format (or PKCS8 format). * Fixes * Fix PSS salt length (thanks to [@ntrepid8](https://github.com/ntrepid8), see [#65](https://github.com/potatosalad/erlang-jose/pull/65)) * Speed up and stabilize tests on CI environment. ## 1.9.0 (2018-12-31) * Enhancements * Add support for [Jason](https://github.com/michalmuskala/jason) JSON encoding and decoding. * Add support for Poison 4.x and lexical ordering. * Use `public_key` over `cutkey` for RSA key generation if available. * Drop support for older versions of OTP (19+ now required). * Relicense library under MIT license. * Fixes * Add macro so the application compiles without warnings after `erlang:get_stacktrace/0` has been deprecated. * Extra sanity check for RSA padding modes when falling back. ## 1.8.4 (2017-05-18) * Enhancements * Add support for reading and writing PEM files for Ed25519, Ed448, X25519, and X448 keys based on [draft-ietf-curdle-pkix](https://tools.ietf.org/html/draft-ietf-curdle-pkix). * Add support for [ojson](https://github.com/potatosalad/erlang-json) adapter for encoding/decoding JSON. ## 1.8.3 (2017-03-30) * Fixes * Regression fix from 1.8.2 for OTP-17 (thanks to [@alexandrejbr](https://github.com/alexandrejbr), see [#35](https://github.com/potatosalad/erlang-jose/issues/35) and [#36](https://github.com/potatosalad/erlang-jose/pull/36)) ## 1.8.2 (2017-03-15) * Enhancements * Add support for decoding firebase certificate public keys (thanks to [@noizu](https://github.com/noizu), see [#30](https://github.com/potatosalad/erlang-jose/issues/30)) * Fixes * Fix cross-platform issues with EC signatures (specifically S and R sizes, thanks to [@alexandrejbr](https://github.com/alexandrejbr), see [#32](https://github.com/potatosalad/erlang-jose/pull/32)) * Typo in documentation for `JOSE.encode/1` (thanks to [@DaveLampton](https://github.com/DaveLampton), see [#31](https://github.com/potatosalad/erlang-jose/issues/31)) * Tests * Tested against OTP 19.3, Elixir 1.4.x, and Poison 3.x ## 1.8.1 (2017-02-02) * Fixes * Parentheses to remove ambiguity on Elixir 1.4 [#26](https://github.com/potatosalad/erlang-jose/pull/26), thanks [@alexandrubagu](https://github.com/alexandrubagu) ## 1.8.0 (2016-08-08) * Enhancements * ChaCha20/Poly1305 encryption and one-time message authentication functions are experimentally supported based on [RFC 7539](https://tools.ietf.org/html/rfc7539). * Fixes * Handling invalid token without raising Exception [#22](https://github.com/potatosalad/erlang-jose/issues/22) * `JOSE.JWT.verify` uses CPU intensively when signed is nil [#23](https://github.com/potatosalad/erlang-jose/issues/23) Examples of new functionality: ```elixir iex> # Encrypt iex> jwe = %{"alg" => "dir", "enc" => "ChaCha20/Poly1305"} iex> jwk = JOSE.JWE.generate_key(jwe) |> JOSE.JWK.to_map |> elem(1) %{"alg" => "dir", "enc" => "ChaCha20/Poly1305", "k" => "EffEuY2nbShIVtizmek8AuR7ftSuY2e8XRxGjMc8QAc", "kty" => "oct", "use" => "enc"} iex> plain_text = "message to encrypt" iex> encrypted = JOSE.JWK.block_encrypt(plain_text, jwk) |> JOSE.JWE.compact |> elem(1) "eyJhbGciOiJkaXIiLCJlbmMiOiJDaGFDaGEyMC9Qb2x5MTMwNSJ9..lbsERynEgQS8CRXZ.D_kt8ChsaYWX9gL9tJlJ2n0E.y0o_TYjGlaB9sEEcA9o12A" iex> # Decrypt iex> plain_text == JOSE.JWK.block_decrypt(encrypted, jwk) |> elem(0) true iex> # Sign iex> jws = %{"alg" => "Poly1305"} iex> jwk = JOSE.JWS.generate_key(jws) |> JOSE.JWK.to_map |> elem(1) %{"alg" => "Poly1305", "k" => "2X-OZVLA41Wy7mAjqWRaZyOw8FLyL3O3_f8d16D_-tQ", "kty" => "oct", "use" => "sig"} iex> message = "message to sign" iex> signed = JOSE.JWK.sign(message, jwk) |> JOSE.JWS.compact |> elem(1) "eyJhbGciOiJQb2x5MTMwNSIsIm5vbmNlIjoicGExU1dlQzJVQzhwZlQ1NCJ9.bWVzc2FnZSB0byBzaWdu.IUI-PvN5bh_9jX-MeDtetw" iex> # Verify iex> JOSE.JWK.verify_strict(signed, ["Poly1305"], jwk) |> elem(0) true ``` ## 1.7.9 (2016-07-13) * Fixes * Fixed JSON encoding bug in `jose_json_poison_compat_encoder` for projects using Poison as the JSON encoder where Erlang loads Elixir as a dependency. ## 1.7.8 (2016-07-08) * Enhancements * Updated EdDSA tests to comply with draft 04 of [draft-ietf-jose-cfrg-curves-04](https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-04). * Fixes * Fixed compression encoding bug for `{"zip":"DEF"}` operations (thanks to [@amadden734](https://github.com/amadden734) see [potatosalad/ruby-jose#3](https://github.com/potatosalad/ruby-jose/pull/3)) ## 1.7.7 (2016-06-30) * Enhancements * Improved handling of RSA private keys in SMF (Straightforward Method) form to CRT (Chinese Remainder Theorem) form, see [#19](https://github.com/potatosalad/erlang-jose/issues/19) This is especially useful for keys produced by Java programs using the `RSAPrivateKeySpec` API as mentioned in [Section 9.3 of RFC 7517](https://tools.ietf.org/html/rfc7517#section-9.3). * Updated EdDSA operations to comply with draft 02 of [draft-ietf-jose-cfrg-curves-02](https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-02). Example RSA SMF to CRT usage: ```erlang %% The following map of an RSA secret key is in SMF (Straightforward Method) form. %% Notice that we only have d, e, and n for this secret key. JWK = jose_jwk:from(#{ <<"d">> => <<"WSAGFGM7fSyYn5NyBL0dp3kjHjQ3djjhQoOAFasoyeE">>, <<"e">> => <<"AQAB">>, <<"kty">> => <<"RSA">>, <<"n">> => <<"0PM6Aooi_KYkDA1r-S24SauFpfTRc5kiPLF3a1EhuY8">> }). %% If we convert it back to a map, it is now in CRT (Chinese Remainder Theorem) form. %% Notice that the dp, dq, p, q, and qi have been restored. element(2, jose_jwk:to_map(JWK)) =:= #{ <<"d">> => <<"WSAGFGM7fSyYn5NyBL0dp3kjHjQ3djjhQoOAFasoyeE">>, <<"dp">> => <<"G00J545ym1bqC9hnFDo3aQ">>, <<"dq">> => <<"tt0FvEZgKli6IL4rVKx3cw">>, <<"e">> => <<"AQAB">>, <<"kty">> => <<"RSA">>, <<"n">> => <<"0PM6Aooi_KYkDA1r-S24SauFpfTRc5kiPLF3a1EhuY8">>, <<"p">> => <<"9O5YQ0w6PIpDl6c6yqwyKQ">>, <<"q">> => <<"2mScgy86M3q6b301UAU09w">>, <<"qi">> => <<"Wrp0SgcGgTT5WmeuHD6Sqw">> }. ``` ## 1.7.6 (2016-06-29) * Fixes * Compatibility fixes for OTP 19 and Elixir 1.3 ## 1.7.5 (2016-05-13) * Fixes * Removed leftover development file accidentally included in last release. ## 1.7.4 (2016-05-13) * Enhancements * More detailed documentation on [key generation](https://hexdocs.pm/jose/key-generation.html). * Fixes * Replaced usage of `crypto:rand_bytes/1` with `crypto:strong_rand_bytes/1` in preparation for Elixir 1.3 and OTP 19 (thanks to [@asonge](https://github.com/asonge) for [#17](https://github.com/potatosalad/erlang-jose/pull/17)). ## 1.7.3 (2016-03-17) * Fixes * `JOSE.JWT.encrypt/2` now uses `JOSE.JWK.block_encryptor/1` properly. ## 1.7.2 (2016-03-16) * Enhancements * Better support for lists of terms. * Added merge functions: * `JOSE.JWE.merge/2` * `JOSE.JWK.merge/2` * `JOSE.JWS.merge/2` * `JOSE.JWT.merge/2` * Added signer, verifier, and block_encryptor functions: * `JOSE.JWK.signer/1` * `JOSE.JWK.verifier/1` * `JOSE.JWK.block_encryptor/1` * Support for `"alg"`, `"enc"`, and `"use"` on keys. Examples of new functionality: ```elixir iex> # Let's generate a 64 byte octet key iex> jwk = JOSE.JWK.generate_key({:oct, 64}) |> JOSE.JWK.to_map |> elem(1) %{"k" => "FXSy7PufOayusvfyKQzdxCegm7yWIMp1b0LD13v57Nq2wF_B-fcr7LDOkufDikmFFsVYWLgrA2zEB--_qqDn3g", "kty" => "oct"} iex> # Based on the key's size and type, a default signer (JWS) can be determined iex> JOSE.JWK.signer(jwk) %{"alg" => "HS512"} iex> # A list of algorithms for which this key type can be verified against can also be determined iex> JOSE.JWK.verifier(jwk) ["HS256", "HS384", "HS512"] iex> # Based on the key's size and type, a default enctypro (JWE) can be determined iex> JOSE.JWK.block_encryptor(jwk) %{"alg" => "dir", "enc" => "A256CBC-HS512"} iex> # Keys can be generated based on the signing algorithm (JWS) iex> JOSE.JWS.generate_key(%{"alg" => "HS256"}) |> JOSE.JWK.to_map |> elem(1) %{"alg" => "HS256", "k" => "UuP3Tw2xbGV5N3BGh34cJNzzC2R1zU7i4rOnF9A8nqY", "kty" => "oct", "use" => "sig"} iex> # Keys can be generated based on the encryption algorithm (JWE) iex> JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A128GCM"}) |> JOSE.JWK.to_map |> elem(1) %{"alg" => "dir", "enc" => "A128GCM", "k" => "8WNdBjXXwg6QTwrrOnvEPw", "kty" => "oct", "use" => "enc"} iex> # Example of merging a map into an existing JWS (also works with JWE, JWK, and JWT) iex> jws = JOSE.JWS.from(%{"alg" => "HS256"}) iex> JOSE.JWS.merge(jws, %{"typ" => "JWT"}) |> JOSE.JWS.to_map |> elem(1) %{"alg" => "HS256", "typ" => "JWT"} ``` ## 1.7.1 (2016-03-08) * Enhancements * New [Edwards-curve Digital Signature Algorithm (EdDSA) version 04](https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-04) is out, update test vectors and remove support for 32 byte secrets for Ed448 and Ed448ph. ## 1.7.0 (2016-03-01) * Enhancements * Add support for [libdecaf](https://github.com/potatosalad/erlang-libdecaf) NIF which provides support for; * `Ed25519` * `Ed25519ph` * `Ed448` * `Ed448ph` * `X25519` * `X448` * Fixes * Return 56 bytes instead of 57 bytes when converting between edwards448 and curve448. * EdDSA related refactoring/cleanup. ## 1.6.1 (2016-02-05) * Enhancements * Add support for NIF version of [keccakf1600](https://github.com/potatosalad/erlang-keccakf1600) library with `jose_sha3_keccakf1600_nif` (version 2 and up) for even faster SHA-3 operations. ## 1.6.0 (2016-01-20) * Enhancements * Add `Ed448` and `Ed448ph` standards from [draft-irtf-cfrg-eddsa](https://tools.ietf.org/html/draft-irtf-cfrg-eddsa). * Add support for [keccakf1600](https://github.com/potatosalad/erlang-keccakf1600) library with `jose_sha3_keccakf1600` for faster SHA-3 operations. * Many, many more tests. * Fixes * Fix pure Erlang implementation of SHA-3 algorithms. ## 1.5.2 (2016-01-19) * Enhancements * Documentation of the encryption algorithms, specifically [`JOSE.JWE`](https://hexdocs.pm/jose/JOSE.JWE.html). * Fixes * Corrected optional callbacks issue for Elixir. * More consistent behavior for ECDH related encryption and decryption. ## 1.5.1 (2016-01-16) * Fixes * Corrected formatting on some of the documentation. * Fixed optional callbacks for `jose_jwk_kty:sign/3` ## 1.5.0 (2016-01-16) * Enhancements * Support [OKP](https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves) key type with the following curves: * `Ed25519` (external [libsodium](https://github.com/potatosalad/erlang-libsodium) or fallback supported) * `Ed25519ph` (external [libsodium](https://github.com/potatosalad/erlang-libsodium) or fallback supported) * `X25519` (external [libsodium](https://github.com/potatosalad/erlang-libsodium) or fallback supported) * `Ed448` (no external, no fallback) * `Ed448ph` (no external, no fallback) * `X448` (no external, but fallback supported) * Support [SHA-3](https://en.wikipedia.org/wiki/SHA-3) functions for future use with `Ed448` and `Ed448ph`. * Add `jose_jwk:shared_secret/2` for computing the shared secret between two `EC` or `OKP` keys. ## 1.4.2 (2015-11-30) * Enhancements * Support [PKCS#8](https://www.openssl.org/docs/manmaster/apps/pkcs8.html) formatted private key PEM files. See #13 * Fixes * Add missing guards in `jose_jws:sign/4` #11 * Add missing guards in `jose_jwe:block_encrypt/5` ## 1.4.1 (2015-11-18) * Enhancements * Added `JOSE.JWS.peek_signature/1` for inspecting the signature parts of a signed binary. * `JOSE.JWS.compact/1` and `JOSE.JWS.expand/1` now work with signed lists. * First pass at documenting all of the major `JOSE` modules. `JOSE.JWE` still needs more examples. Closes #7 * Fixes * Fix infinite loop on `JOSE.JWE.key_decrypt/3` when no `"enc"` has been specified. * Fix various functions on `JOSE.JWE` that would fail due to `JOSE.JWE.from_record/1` on wrong terms. ## 1.4.0 (2015-11-17) * Enhancements * Added `JOSE.unsecured_signing/0` and `JOSE.unsecured_signing/1` for disabling the `"none"` algorithm due to the [unsecured signing vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/) and in relation to #10 * Added `JOSE.JWK.verify_strict/3`, `JOSE.JWS.verify_strict/3`, and `JOSE.JWT.verify_strict/3` for whitelisting which signing algorithms are allowed for verification. * Added `JOSE.JWT.peek_payload/1` and `JOSE.JWT.peek_protected/1` for inspecting the payload and protected parts of a signature. ## 1.3.0 (2015-09-22) * Enhancements * `oct` key management (see `JOSE.JWK.from_oct/1,2`) * Key generation functions for `EC`, `RSA`, and `oct` keys (see `JOSE.JWK.generate_key/1`) * Add `JOSE.JWK.box_encrypt/2` which generates an ephemeral private key based on the given key curve. * Add support for detecting OTP version 18 and up with optional_callbacks. * Document key generation under `examples/KEY-GENERATION.md` * jiffy and jsone JSON support * Begin documenting the Elixir API (thanks to #8) * Add support for `jose_jws:peek/1` and `jose_jwt:peek/1` * Preparations for future upstream OTP crypto changes. * Improved detection of AES CBC, ECB, and GCM support. * Improved detection of RSAES-OAEP, RSAES-PKCS1-v1_5, RSASSA-PKCS1-v1_5, and RSASSA-PSS support. * Implemented fallback RSAES-PKCS1-v1_5 and RSASSA-PKCS1-v1_5 algorithms. * Improved selection of encryptor for oct keys. * Improved algorithm support detection for jose_jwa. * Fixes * Remove "sph" from jose_jws (removed from [JWS Unencoded Payload Option](https://tools.ietf.org/html/draft-ietf-jose-jws-signing-input-options-02)). * Tests * Only run 1 in 10 for AES GCM and 1 in 5 for AES KW CAVP test vectors to speed up tests. * Additional tests for RSAES-PKCS1-v1_5 and RSASSA-PKCS1-v1_5 algorithms. ## 1.2.0 (2015-08-14) * Enhancements * Add RSA PKCS-1 algorithms to support detection. * Add support for `crypto_fallback` option to enable/disable non-native cryptographic algorithms. * Add support for `json_module` option for encoding/decoding of JSON. * Fixes * Fix AES GCM algorithm for non 96-bit IV values. * Allow RSA OAEP to specify Seed on encrypt. * Tests * NIST and EMC test vectors for AES, PKCS-1, and PKCS-5. * Concat KDF, PBKDF1, and PKCS-7 Padding informal verification. * AES Key Wrap informal verification with NIST test vectors. ## 1.1.3 (2015-08-10) * Fixes * Missed a case where jose was not starting automatically (see 1.1.2). ## 1.1.2 (2015-08-10) * Enhancements * Automatically start jose if one of the fallback algorithms is required. ## 1.1.1 (2015-08-07) * Fixes * Fix bit sizes for A128CBC-HS256, A192CBC-HS384, and A256CBC-HS512 algorithms. * Don't precompute the GHASH table (speeds up AES GCM fallback on OTP 17). * Use case statement instead of map pattern matching for block_decrypt (fixes map pattern matching bug on OTP 17). * Allow mostly empty EC keys to be converted back to JSON. * Add jose_jwk_props property test for full algorithm range of encryption and decryption. ## 1.1.0 (2015-08-06) * Enhancements * Detect supported `crypto` AES ciphers and use fallbacks when necessary. * Detect EC key mode (to support OTP 17.5). * Mostly pure Erlang implementation of AES GCM and GHASH functions. * Add `JOSE.JWA` module for Elixir. * Fixes * All tests now pass on OTP 17.5 and OTP 18. * Fallback to non-native crypto implementations for OTP 17.5. ## 1.0.1 (2015-08-05) * Dependencies * Use [`base64url`](https://hex.pm/packages/base64url) package from hex.pm ## 1.0.0 (2015-08-05) * Initial Release * Algorithm Support * JSON Web Encryption (JWE) [RFC 7516](https://tools.ietf.org/html/rfc7516) * `"alg"` [RFC 7518 Section 4](https://tools.ietf.org/html/rfc7518#section-4) * `RSA1_5` * `RSA-OAEP` * `RSA-OAEP-256` * `A128KW` * `A192KW` * `A256KW` * `dir` * `ECDH-ES` * `ECDH-ES+A128KW` * `ECDH-ES+A192KW` * `ECDH-ES+A256KW` * `A128GCMKW` * `A192GCMKW` * `A256GCMKW` * `PBES2-HS256+A128KW` * `PBES2-HS384+A192KW` * `PBES2-HS512+A256KW` * `"enc"` [RFC 7518 Section 5](https://tools.ietf.org/html/rfc7518#section-5) * `A128CBC-HS256` * `A192CBC-HS384` * `A256CBC-HS512` * `A128GCM` * `A192GCM` * `A256GCM` * `"zip"` [RFC 7518 Section 7.3](https://tools.ietf.org/html/rfc7518#section-7.3) * `DEF` * JSON Web Key (JWK) [RFC 7517](https://tools.ietf.org/html/rfc7517) * `"alg"` [RFC 7518 Section 6](https://tools.ietf.org/html/rfc7518#section-6) * `EC` * `RSA` * `oct` * JSON Web Signature (JWS) [RFC 7515](https://tools.ietf.org/html/rfc7515) * `"alg"` [RFC 7518 Section 3](https://tools.ietf.org/html/rfc7518#section-3) * `HS256` * `HS384` * `HS512` * `RS256` * `RS384` * `RS512` * `ES256` * `ES384` * `ES512` * `PS256` * `PS384` * `PS512` * `none` erlang-jose-1.10.1/Makefile0000644000232200023220000000573613605433351016024 0ustar debalancedebalancePROJECT = jose PROJECT_DESCRIPTION = JSON Object Signing and Encryption (JOSE) for Erlang and Elixir. PROJECT_VERSION = 1.9.0 TEST_DEPS = jiffy jsone jsx libdecaf libsodium ojson proper dep_jiffy = git git://github.com/davisp/jiffy.git master dep_jsone = git git://github.com/sile/jsone.git master dep_jsx = git git://github.com/talentdeficit/jsx.git master dep_keccakf1600 = git git://github.com/potatosalad/erlang-keccakf1600.git master dep_libdecaf = git git://github.com/potatosalad/erlang-libdecaf.git master dep_libsodium = git git://github.com/potatosalad/erlang-libsodium.git master dep_ojson = git git://github.com/potatosalad/erlang-ojson.git master dep_proper = git git://github.com/proper-testing/proper.git v1.3 include erlang.mk .PHONY: docker-build docker-load docker-setup docker-save docker-shell docker-test DOCKER_OTP_VERSION ?= 22.2.1 docker-build:: $(gen_verbose) docker build \ -t docker-otp-${DOCKER_OTP_VERSION} \ -f test/Dockerfile \ --build-arg OTP_VERSION=${DOCKER_OTP_VERSION} \ test docker-load:: $(gen_verbose) docker load \ -i "docker-otp-${DOCKER_OTP_VERSION}/image.tar" docker-save:: $(verbose) mkdir -p "docker-otp-${DOCKER_OTP_VERSION}" $(gen_verbose) docker save \ -o "docker-otp-${DOCKER_OTP_VERSION}/image.tar" \ docker-otp-${DOCKER_OTP_VERSION} docker-setup:: $(verbose) if [ -f "docker-otp-${DOCKER_OTP_VERSION}/image.tar" ]; then \ $(MAKE) docker-load; \ else \ $(MAKE) docker-build; \ $(MAKE) docker-save; \ fi docker-shell:: $(verbose) docker run \ -v "$(shell pwd)":"/build/jose" --rm -it "docker-otp-${DOCKER_OTP_VERSION}" \ /bin/bash -l docker-test:: $(gen_verbose) docker run \ -v "$(shell pwd)":"/build/jose" "docker-otp-${DOCKER_OTP_VERSION}" \ sh -c 'cd jose && make ct' # DOCKER_OTP_VERSION ?= 21.2 # DOCKER_ELIXIR_VERSION ?= 1.7.4 # docker-build:: # $(gen_verbose) docker build \ # -t docker-otp-${DOCKER_OTP_VERSION}-elixir-${DOCKER_ELIXIR_VERSION} \ # -f priv/Dockerfile \ # --build-arg OTP_VERSION=${DOCKER_OTP_VERSION} \ # --build-arg ELIXIR_VERSION=${DOCKER_ELIXIR_VERSION} priv # docker-load:: # $(gen_verbose) docker load \ # -i "docker-otp-${DOCKER_OTP_VERSION}-elixir-${DOCKER_ELIXIR_VERSION}/image.tar" # docker-save:: # $(verbose) mkdir -p "docker-otp-${DOCKER_OTP_VERSION}-elixir-${DOCKER_ELIXIR_VERSION}" # $(gen_verbose) docker save \ # -o "docker-otp-${DOCKER_OTP_VERSION}-elixir-${DOCKER_ELIXIR_VERSION}/image.tar" \ # docker-otp-${DOCKER_OTP_VERSION}-elixir-${DOCKER_ELIXIR_VERSION} # docker-setup:: # $(verbose) if [ -f "docker-otp-${DOCKER_OTP_VERSION}-elixir-${DOCKER_ELIXIR_VERSION}/image.tar" ]; then \ # $(MAKE) docker-load; \ # else \ # $(MAKE) docker-build; \ # $(MAKE) docker-save; \ # fi # docker-test:: # $(gen_verbose) docker run \ # -v "$(shell pwd)":"/build/jose" "docker-otp-${DOCKER_OTP_VERSION}-elixir-${DOCKER_ELIXIR_VERSION}" \ # sh -c 'cd jose && mix local.hex --force && mix local.rebar --force && mix deps.get && mix test && rm -rf _build deps ebin && make ct' erlang-jose-1.10.1/priv/0000755000232200023220000000000013605433351015331 5ustar debalancedebalanceerlang-jose-1.10.1/priv/Dockerfile0000644000232200023220000000136513605433351017330 0ustar debalancedebalanceFROM ubuntu:19.10 ARG DEBIAN_FRONTEND=noninteractive ARG OTP_VERSION=local ENV OTP_VERSION ${OTP_VERSION} ARG ELIXIR_VERSION=local ENV ELIXIR_VERSION ${ELIXIR_VERSION} RUN apt-get update && \ apt-get -y install curl gnupg2 && \ curl -O https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && \ dpkg -i erlang-solutions_1.0_all.deb && \ apt-get update && \ apt-get -y install esl-erlang=1:${OTP_VERSION}\* elixir=${ELIXIR_VERSION}\* git make clang-9 autoconf automake libtool locales openssl libssl-dev && \ sed -i 's/^# \(en_US.UTF-8 UTF-8\)/\1/' /etc/locale.gen && \ locale-gen ENV LANG en_US.UTF-8 ENV CC clang-9 ENV CXX clang++-9 ENV ARCHFLAGS -Wgcc-compat ENV MIX_ENV test RUN mkdir /build WORKDIR /build erlang-jose-1.10.1/src/0000755000232200023220000000000013605433351015140 5ustar debalancedebalanceerlang-jose-1.10.1/src/jose_curve448_unsupported.erl0000644000232200023220000000403313605433351022720 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 02 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_curve448_unsupported). -behaviour(jose_curve448). %% jose_curve448 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed448_sign/2]). -export([ed448_sign/3]). -export([ed448_verify/3]). -export([ed448_verify/4]). -export([ed448ph_sign/2]). -export([ed448ph_sign/3]). -export([ed448ph_verify/3]). -export([ed448ph_verify/4]). -export([x448_keypair/0]). -export([x448_keypair/1]). -export([x448_secret_to_public/1]). -export([x448_shared_secret/2]). %% Macros -define(unsupported, erlang:error(curve448_unsupported)). %%==================================================================== %% jose_curve448 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> ?unsupported. eddsa_keypair(_Seed) -> ?unsupported. eddsa_secret_to_public(_SecretKey) -> ?unsupported. % Ed448 ed448_sign(_Message, _SecretKey) -> ?unsupported. ed448_sign(_Message, _SecretKey, _Context) -> ?unsupported. ed448_verify(_Signature, _Message, _PublicKey) -> ?unsupported. ed448_verify(_Signature, _Message, _PublicKey, _Context) -> ?unsupported. % Ed448ph ed448ph_sign(_Message, _SecretKey) -> ?unsupported. ed448ph_sign(_Message, _SecretKey, _Context) -> ?unsupported. ed448ph_verify(_Signature, _Message, _PublicKey) -> ?unsupported. ed448ph_verify(_Signature, _Message, _PublicKey, _Context) -> ?unsupported. % X448 x448_keypair() -> ?unsupported. x448_keypair(_Seed) -> ?unsupported. x448_secret_to_public(_SecretKey) -> ?unsupported. x448_shared_secret(_MySecretKey, _YourPublicKey) -> ?unsupported. erlang-jose-1.10.1/src/jose_sha3_keccakf1600_driver.erl0000644000232200023220000000241713605433351023057 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 20 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_sha3_keccakf1600_driver). -behaviour(jose_sha3). %% jose_sha3 callbacks -export([sha3_224/1]). -export([sha3_256/1]). -export([sha3_384/1]). -export([sha3_512/1]). -export([shake128/2]). -export([shake256/2]). %%==================================================================== %% jose_sha3 callbacks %%==================================================================== sha3_224(InputBytes) -> keccakf1600_fips202:sha3_224(InputBytes). sha3_256(InputBytes) -> keccakf1600_fips202:sha3_256(InputBytes). sha3_384(InputBytes) -> keccakf1600_fips202:sha3_384(InputBytes). sha3_512(InputBytes) -> keccakf1600_fips202:sha3_512(InputBytes). shake128(InputBytes, OutputByteLen) -> keccakf1600_fips202:shake128(InputBytes, OutputByteLen). shake256(InputBytes, OutputByteLen) -> keccakf1600_fips202:shake256(InputBytes, OutputByteLen). erlang-jose-1.10.1/src/jose_chacha20_poly1305_crypto.erl0000644000232200023220000000366613605433351023224 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 08 Aug 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_chacha20_poly1305_crypto). -behaviour(jose_chacha20_poly1305). %% jose_chacha20_poly1305 callbacks -export([decrypt/5]). -export([encrypt/4]). -export([authenticate/3]). -export([verify/4]). %%==================================================================== %% jose_chacha20_poly1305 callbacks %%==================================================================== decrypt(CipherText, CipherTag, AAD, IV, CEK) -> %% NOTE: As of OTP 22, crypto does not seem to validate the CipherTag :-( MacData = << AAD/binary, (jose_jwa_chacha20_poly1305:pad16(AAD))/binary, CipherText/binary, (jose_jwa_chacha20_poly1305:pad16(CipherText))/binary, (byte_size(AAD)):64/unsigned-little-integer-unit:1, (byte_size(CipherText)):64/unsigned-little-integer-unit:1 >>, case verify(CipherTag, MacData, CEK, IV) of true -> crypto:crypto_one_time_aead(chacha20_poly1305, CEK, IV, CipherText, AAD, CipherTag, false); false -> error end. encrypt(PlainText, AAD, IV, CEK) -> crypto:crypto_one_time_aead(chacha20_poly1305, CEK, IV, PlainText, AAD, true). authenticate(Message, Key, Nonce) -> OTK = jose_jwa_chacha20_poly1305:poly1305_key_gen(Key, Nonce), crypto:poly1305(OTK, Message). verify(MAC, Message, Key, Nonce) -> Challenge = jose_jwa_chacha20_poly1305:authenticate(Message, Key, Nonce), jose_jwa:constant_time_compare(MAC, Challenge). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jose_xchacha20_poly1305.erl0000644000232200023220000000422413605433351022003 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_xchacha20_poly1305). -behaviour(jose_block_encryptor). -type digest() :: << _:16 >>. -type key() :: << _:32 >>. -type nonce() :: << _:24 >>. -callback decrypt(CipherText, CipherTag, AAD, IV, Key) -> PlainText | error when CipherText :: binary(), CipherTag :: digest(), AAD :: binary(), IV :: nonce(), Key :: key(), PlainText :: binary(). -callback encrypt(PlainText, AAD, IV, Key) -> CipherText when PlainText :: binary(), AAD :: binary(), IV :: nonce(), Key :: key(), CipherText :: binary(). -callback authenticate(Message, Key, Nonce) -> MAC when Message :: binary(), Key :: key(), Nonce :: nonce(), MAC :: digest(). -callback verify(MAC, Message, Key, Nonce) -> boolean() when MAC :: digest(), Message :: binary(), Key :: key(), Nonce :: nonce(). %% jose_block_encryptor callbacks -export([block_decrypt/4]). -export([block_encrypt/4]). -export([authenticate/3]). -export([verify/4]). %% Macros -define(JOSE_XCHACHA20_POLY1305, (jose:xchacha20_poly1305_module())). %%==================================================================== %% jose_block_encryptor callbacks %%==================================================================== block_decrypt({xchacha20_poly1305, 256}, Key, IV, {AAD, CipherText, CipherTag}) -> ?JOSE_XCHACHA20_POLY1305:decrypt(CipherText, CipherTag, AAD, IV, Key). block_encrypt({xchacha20_poly1305, 256}, Key, IV, {AAD, PlainText}) -> ?JOSE_XCHACHA20_POLY1305:encrypt(PlainText, AAD, IV, Key). authenticate(Message, Key, Nonce) -> ?JOSE_XCHACHA20_POLY1305:authenticate(Message, Key, Nonce). verify(MAC, Message, Key, Nonce) -> ?JOSE_XCHACHA20_POLY1305:verify(MAC, Message, Key, Nonce). erlang-jose-1.10.1/src/jose_curve25519_unsupported.erl0000644000232200023220000000330713605433351023071 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 02 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_curve25519_unsupported). -behaviour(jose_curve25519). %% jose_curve25519 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed25519_sign/2]). -export([ed25519_verify/3]). -export([ed25519ph_sign/2]). -export([ed25519ph_verify/3]). -export([x25519_keypair/0]). -export([x25519_keypair/1]). -export([x25519_secret_to_public/1]). -export([x25519_shared_secret/2]). %% Macros -define(unsupported, erlang:error(curve25519_unsupported)). %%==================================================================== %% jose_curve25519 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> ?unsupported. eddsa_keypair(_Seed) -> ?unsupported. eddsa_secret_to_public(_SecretKey) -> ?unsupported. % Ed25519 ed25519_sign(_Message, _SecretKey) -> ?unsupported. ed25519_verify(_Signature, _Message, _PublicKey) -> ?unsupported. % Ed25519ph ed25519ph_sign(_Message, _SecretKey) -> ?unsupported. ed25519ph_verify(_Signature, _Message, _PublicKey) -> ?unsupported. % X25519 x25519_keypair() -> ?unsupported. x25519_keypair(_Seed) -> ?unsupported. x25519_secret_to_public(_SecretKey) -> ?unsupported. x25519_shared_secret(_MySecretKey, _YourPublicKey) -> ?unsupported. erlang-jose-1.10.1/src/jose_sha3_libdecaf.erl0000644000232200023220000000240513605433351021334 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 01 Mar 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_sha3_libdecaf). -behaviour(jose_sha3). %% jose_sha3 callbacks -export([sha3_224/1]). -export([sha3_256/1]). -export([sha3_384/1]). -export([sha3_512/1]). -export([shake128/2]). -export([shake256/2]). %%==================================================================== %% jose_sha3 callbacks %%==================================================================== sha3_224(InputBytes) -> libdecaf_sha3:hash(sha3_224, InputBytes). sha3_256(InputBytes) -> libdecaf_sha3:hash(sha3_256, InputBytes). sha3_384(InputBytes) -> libdecaf_sha3:hash(sha3_384, InputBytes). sha3_512(InputBytes) -> libdecaf_sha3:hash(sha3_512, InputBytes). shake128(InputBytes, OutputByteLen) -> libdecaf_sha3:hash(shake128, InputBytes, OutputByteLen). shake256(InputBytes, OutputByteLen) -> libdecaf_sha3:hash(shake256, InputBytes, OutputByteLen). erlang-jose-1.10.1/src/json/0000755000232200023220000000000013605433351016111 5ustar debalancedebalanceerlang-jose-1.10.1/src/json/jose_json_jiffy.erl0000644000232200023220000000241213605433351021774 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 20 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json_jiffy). -behaviour(jose_json). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(Binary) -> jiffy:decode(Binary, [return_maps]). encode(Map) when is_map(Map) -> jiffy:encode(sort(Map)); encode(List) when is_list(List) -> jiffy:encode(sort(List)); encode(Term) -> jiffy:encode(Term). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private sort(Map) when is_map(Map) -> {[{sort(Key), sort(Val)} || {Key, Val} <- maps:to_list(Map)]}; sort(List) when is_list(List) -> [sort(Term) || Term <- List]; sort(Term) -> Term. erlang-jose-1.10.1/src/json/jose_json_jsone.erl0000644000232200023220000000172513605433351022011 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 20 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json_jsone). -behaviour(jose_json). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(Binary) -> jsone:decode(Binary). encode(Term) -> jsone:encode(Term, [canonical_form]). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/json/jose_json_poison_lexical_encoder.erl0000644000232200023220000000203113605433351025371 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json_poison_lexical_encoder). -behaviour(jose_json). -compile(inline_list_funcs). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(Binary) -> 'Elixir.Poison':'decode!'(Binary). encode(Term) -> 'Elixir.JOSE.Poison':'lexical_encode!'(Term). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/json/jose_json_poison.erl0000644000232200023220000000173613605433351022204 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json_poison). -behaviour(jose_json). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(Binary) -> 'Elixir.Poison':'decode!'(Binary). encode(Term) -> 'Elixir.Poison':'encode!'(Term). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/json/jose_json_ojson.erl0000644000232200023220000000171113605433351022016 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2017, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 18 May 2017 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json_ojson). -behaviour(jose_json). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(Binary) -> ojson:'decode!'(Binary). encode(Term) -> ojson:'encode!'(Term). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/json/jose_json_poison_compat_encoder.erl0000644000232200023220000001065413605433351025245 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json_poison_compat_encoder). -behaviour(jose_json). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(Binary) -> 'Elixir.Poison':'decode!'(Binary). encode(Term) -> 'Elixir.IO':'iodata_to_binary'(lexical_encode(Term)). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private lexical_encode(Atom) when is_atom(Atom) -> apply('Elixir.Poison.Encoder.Atom', 'encode', [Atom, #{}]); lexical_encode(BitString) when is_bitstring(BitString) -> apply('Elixir.Poison.Encoder.BitString', 'encode', [BitString, #{}]); lexical_encode(Integer) when is_integer(Integer) -> apply('Elixir.Poison.Encoder.Integer', 'encode', [Integer, #{}]); lexical_encode(Float) when is_float(Float) -> apply('Elixir.Poison.Encoder.Float', 'encode', [Float, #{}]); lexical_encode(Struct = #{ '__struct__' := Type }) -> lexical_encode_struct(Type, Struct); lexical_encode(Map) when is_map(Map) -> lexical_encode_map(Map); lexical_encode(List) when is_list(List) -> lexical_encode_list(List); lexical_encode(Any) -> erlang:error('Elixir.Poison.EncodeError':'exception'([{value, Any}])). %% @private lexical_encode_name(Binary) when is_binary(Binary) -> Binary; lexical_encode_name(Atom) when is_atom(Atom) -> 'Elixir.Atom':'to_string'(Atom); lexical_encode_name(Any) -> erlang:error('Elixir.Poison.EncodeError':'exception'([ {value, Any}, {message, << "expected string or atom key, got: ", ('Elixir.Kernel':'inspect'(Any))/binary >>} ])). %% @private lexical_encode_map(Map) when map_size(Map) < 1 -> <<"{}">>; lexical_encode_map(Map) when is_map(Map) -> Folder = fun (Key, Acc) -> [ $,, apply('Elixir.Poison.Encoder.BitString', 'encode', [lexical_encode_name(Key), #{}]), $:, lexical_encode(maps:get(Key, Map)) | Acc ] end, [ ${, tl(lists:foldr(Folder, [], lists:sort(maps:keys(Map)))), $} ]. %% @private lexical_encode_list([]) -> <<"[]">>; lexical_encode_list(List) when is_list(List) -> Folder = fun (Element, Acc) -> [ $,, lexical_encode(Element) | Acc ] end, [ $[, tl(lists:foldr(Folder, [], List)), $] ]. %% @private lexical_encode_struct(Type, Struct) when Type == 'Elixir.Range' orelse Type == 'Elixir.Stream' orelse Type == 'Elixir.MapSet' orelse Type == 'Elixir.HashSet' -> FlatMapper = fun (Element) -> [ $,, lexical_encode(Element) ] end, case 'Elixir.Enum':'flat_map'(Struct, FlatMapper) of [] -> <<"[]">>; [_ | Tail] -> [ $[, Tail, $] ] end; lexical_encode_struct('Elixir.HashDict', HashDict) -> case 'Elixir.HashDict':'size'(HashDict) < 1 of true -> <<"{}">>; false -> FlatMapper = fun ({Key, Value}) -> [ $,, apply('Elixir.Poison.Encoder.BitString', 'encode', [lexical_encode_name(Key), #{}]), $:, lexical_encode(Value) ] end, [ ${, tl('Elixir.Enum':'flat_map'(HashDict, FlatMapper)), $} ] end; lexical_encode_struct(Type, Struct) when Type == 'Elixir.Date' orelse Type == 'Elixir.Time' orelse Type == 'Elixir.NaiveDateTime' orelse Type == 'Elixir.DateTime' -> apply('Elixir.Poison.Encoder.BitString', 'encode', [Type:'to_iso8601'(Struct), #{}]); lexical_encode_struct(Type, Struct) -> case find_encoder(Type) of {true, Encoder} -> apply(Encoder, 'encode', [Struct, #{}]); false -> lexical_encode_map('Elixir.Map':'from_struct'(Struct)) end. %% @private find_encoder(ElixirType) -> case atom_to_binary(ElixirType, unicode) of << "Elixir.", Type/binary >> -> try binary_to_existing_atom(<< "Elixir.Poison.Encoder.", Type/binary >>, unicode) of EncoderType -> case code:ensure_loaded(EncoderType) of {module, EncoderType} -> {true, EncoderType}; _ -> false end catch _:_ -> false end; _ -> false end. erlang-jose-1.10.1/src/json/jose_json_jsx.erl0000644000232200023220000000171413605433351021475 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json_jsx). -behaviour(jose_json). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(Binary) -> jsx:decode(Binary, [return_maps]). encode(Term) -> jsx:encode(Term). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/json/jose_json_unsupported.erl0000644000232200023220000000175713605433351023270 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json_unsupported). -behaviour(jose_json). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(_Binary) -> erlang:error(unsupported_json_module). encode(_Term) -> erlang:error(unsupported_json_module). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/json/jose_json_jason.erl0000644000232200023220000000122513605433351022000 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_json_jason). -behaviour(jose_json). %% jose_json callbacks -export([decode/1]). -export([encode/1]). %%==================================================================== %% jose_json callbacks %%==================================================================== decode(Binary) -> 'Elixir.Jason':'decode!'(Binary). encode(Term) -> 'Elixir.Jason':'encode!'(Term). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/json/jose_json.erl0000644000232200023220000000102513605433351020604 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_json). -callback decode(binary()) -> term(). -callback encode(term()) -> binary(). erlang-jose-1.10.1/src/jose.erl0000644000232200023220000000701213605433351016604 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 20 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose). %% API -export([chacha20_poly1305_module/0]). -export([chacha20_poly1305_module/1]). -export([crypto_fallback/0]). -export([crypto_fallback/1]). -export([curve25519_module/0]). -export([curve25519_module/1]). -export([curve448_module/0]). -export([curve448_module/1]). -export([decode/1]). -export([encode/1]). -export([json_module/0]). -export([json_module/1]). -export([sha3_module/0]). -export([sha3_module/1]). -export([unsecured_signing/0]). -export([unsecured_signing/1]). -export([xchacha20_poly1305_module/0]). -export([xchacha20_poly1305_module/1]). %% Private API -export([start/0]). -define(TAB, jose_jwa). -define(MAYBE_START_JOSE(F), try F catch _:_ -> _ = jose:start(), F end). %%==================================================================== %% API functions %%==================================================================== chacha20_poly1305_module() -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, chacha20_poly1305_module, 2)). chacha20_poly1305_module(ChaCha20Poly1305Module) when is_atom(ChaCha20Poly1305Module) -> ?MAYBE_START_JOSE(jose_server:chacha20_poly1305_module(ChaCha20Poly1305Module)). crypto_fallback() -> jose_jwa:crypto_fallback(). crypto_fallback(Boolean) when is_boolean(Boolean) -> jose_jwa:crypto_fallback(Boolean). curve25519_module() -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, curve25519_module, 2)). curve25519_module(Curve25519Module) when is_atom(Curve25519Module) -> ?MAYBE_START_JOSE(jose_server:curve25519_module(Curve25519Module)). curve448_module() -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, curve448_module, 2)). curve448_module(Curve448Module) when is_atom(Curve448Module) -> ?MAYBE_START_JOSE(jose_server:curve448_module(Curve448Module)). decode(Binary) -> JSONModule = json_module(), JSONModule:decode(Binary). encode(Term) -> JSONModule = json_module(), JSONModule:encode(Term). json_module() -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, json_module, 2)). json_module(JSONModule) when is_atom(JSONModule) -> ?MAYBE_START_JOSE(jose_server:json_module(JSONModule)). sha3_module() -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, sha3_module, 2)). sha3_module(SHA3Module) when is_atom(SHA3Module) -> ?MAYBE_START_JOSE(jose_server:sha3_module(SHA3Module)). unsecured_signing() -> jose_jwa:unsecured_signing(). unsecured_signing(Boolean) when is_boolean(Boolean) -> jose_jwa:unsecured_signing(Boolean). xchacha20_poly1305_module() -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, xchacha20_poly1305_module, 2)). xchacha20_poly1305_module(XChaCha20Poly1305Module) when is_atom(XChaCha20Poly1305Module) -> ?MAYBE_START_JOSE(jose_server:xchacha20_poly1305_module(XChaCha20Poly1305Module)). %%==================================================================== %% Private API functions %%==================================================================== start() -> case application:ensure_all_started(?MODULE) of {ok, _} -> ok; StartError -> StartError end. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jose_xchacha20_poly1305_unsupported.erl0000644000232200023220000000217213605433351024453 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_xchacha20_poly1305_unsupported). -behaviour(jose_xchacha20_poly1305). %% jose_xchacha20_poly1305 callbacks -export([decrypt/5]). -export([encrypt/4]). -export([authenticate/3]). -export([verify/4]). %% Macros -define(unsupported, erlang:error(xchacha20_poly1305_unsupported)). %%==================================================================== %% jose_xchacha20_poly1305 callbacks %%==================================================================== decrypt(_CipherText, _CipherTag, _AAD, _IV, _Key) -> ?unsupported. encrypt(_PlainText, _AAD, _IV, _Key) -> ?unsupported. authenticate(_Message, _Key, _Nonce) -> ?unsupported. verify(_MAC, _Message, _Key, _Nonce) -> ?unsupported. erlang-jose-1.10.1/src/jwa/0000755000232200023220000000000013605433351015721 5ustar debalancedebalanceerlang-jose-1.10.1/src/jwa/jose_jwa_pkcs5.erl0000644000232200023220000001177713605433351021350 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc PKCS #5: Password-Based Cryptography Specification Version 2.0 %%% See RFC 2898: https://tools.ietf.org/html/rfc2898 %%% @end %%% Created : 27 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_pkcs5). %% API -export([pbkdf1/3]). -export([pbkdf1/4]). -export([pbkdf1/5]). -export([pbkdf2/3]). -export([pbkdf2/4]). -export([pbkdf2/5]). %%==================================================================== %% API functions %%==================================================================== pbkdf1(Hash, Password, Salt) -> pbkdf1(Hash, Password, Salt, 1). pbkdf1(Hash, Password, Salt, Iterations) -> HashFun = resolve_hash(Hash), DerivedKeyLen = byte_size(HashFun(<<>>)), pbkdf1(HashFun, Password, Salt, Iterations, DerivedKeyLen). pbkdf1(Hash, Password, Salt, Iterations, DerivedKeyLen) when is_function(Hash, 1) andalso is_binary(Password) andalso is_binary(Salt) andalso Iterations >= 1 andalso is_integer(DerivedKeyLen) andalso DerivedKeyLen >= 0 -> HashLen = byte_size(Hash(<<>>)), case DerivedKeyLen > HashLen of false -> {ok, derive_pbkdf1(Hash, 1, Iterations, DerivedKeyLen, << Password/binary, Salt/binary >>)}; true -> {error, derived_key_too_long} end; pbkdf1(Hash, Password, Salt, Iterations, DerivedKeyLen) when is_tuple(Hash) orelse is_atom(Hash) -> pbkdf1(resolve_hash(Hash), Password, Salt, Iterations, DerivedKeyLen). pbkdf2(Mac, Password, Salt) -> pbkdf2(Mac, Password, Salt, 1). pbkdf2(Mac, Password, Salt, Iterations) -> MacFun = resolve_mac(Mac), DerivedKeyLen = byte_size(MacFun(<<>>, <<>>)), pbkdf2(MacFun, Password, Salt, Iterations, DerivedKeyLen). pbkdf2(Mac, Password, Salt, Iterations, DerivedKeyLen) when is_function(Mac, 2) andalso is_binary(Password) andalso is_binary(Salt) andalso is_integer(Iterations) andalso Iterations >= 1 andalso is_integer(DerivedKeyLen) andalso DerivedKeyLen >= 0 -> MacLen = byte_size(Mac(<<>>, <<>>)), case DerivedKeyLen > (16#FFFFFFFF * MacLen) of false -> Reps = ceiling(DerivedKeyLen / MacLen), {ok, derive_pbkdf2(Mac, 1, Reps, Iterations, DerivedKeyLen, Password, Salt, <<>>)}; true -> {error, derived_key_too_long} end; pbkdf2(Mac, Password, Salt, Iterations, DerivedKeyLen) when is_tuple(Mac) orelse is_atom(Mac) -> pbkdf2(resolve_mac(Mac), Password, Salt, Iterations, DerivedKeyLen). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private ceiling(X) when X < 0 -> trunc(X); ceiling(X) -> T = trunc(X), case X - T == 0 of false -> T + 1; true -> T end. %% @private derive_pbkdf1(Hash, Reps, Reps, DerivedKeyLen, DerivedKeyingMaterial) -> << DerivedKey:DerivedKeyLen/binary, _/binary >> = Hash(DerivedKeyingMaterial), DerivedKey; derive_pbkdf1(Hash, Counter, Reps, DerivedKeyLen, DerivedKeyingMaterial) -> derive_pbkdf1(Hash, Counter + 1, Reps, DerivedKeyLen, Hash(DerivedKeyingMaterial)). %% @private derive_pbkdf2(Mac, Reps, Reps, Iterations, DerivedKeyLen, Password, Salt, DerivedKeyingMaterial) -> << DerivedKey:DerivedKeyLen/binary, _/binary >> = << DerivedKeyingMaterial/binary, (derive_pbkdf2_exor(Mac, Password, Salt, 1, Iterations, Reps, <<>>, <<>>))/binary >>, DerivedKey; derive_pbkdf2(Mac, Counter, Reps, Iterations, DerivedKeyLen, Password, Salt, DerivedKeyingMaterial) -> derive_pbkdf2(Mac, Counter + 1, Reps, Iterations, DerivedKeyLen, Password, Salt, << DerivedKeyingMaterial/binary, (derive_pbkdf2_exor(Mac, Password, Salt, 1, Iterations, Counter, <<>>, <<>>))/binary >>). %% @private derive_pbkdf2_exor(_Mac, _Password, _Salt, I, Iterations, _Counter, _Prev, Acc) when I > Iterations -> Acc; derive_pbkdf2_exor(Mac, Password, Salt, I = 1, Iterations, Counter, <<>>, <<>>) -> Next = Mac(Password, << Salt/binary, Counter:1/unsigned-big-integer-unit:32 >>), derive_pbkdf2_exor(Mac, Password, Salt, I + 1, Iterations, Counter, Next, Next); derive_pbkdf2_exor(Mac, Password, Salt, I, Iterations, Counter, Prev, Acc) -> Next = Mac(Password, Prev), derive_pbkdf2_exor(Mac, Password, Salt, I + 1, Iterations, Counter, Next, crypto:exor(Next, Acc)). %% @private resolve_hash(HashFun) when is_function(HashFun, 1) -> HashFun; resolve_hash(DigestType) when is_atom(DigestType) -> fun(Data) -> crypto:hash(DigestType, Data) end; resolve_hash({hmac, DigestType, Key}) when is_atom(DigestType) -> fun(Data) -> crypto:hmac(DigestType, Key, Data) end. %% @private resolve_mac(MacFun) when is_function(MacFun, 2) -> MacFun; resolve_mac(DigestType) when is_atom(DigestType) -> resolve_mac({hmac, DigestType}); resolve_mac({hmac, DigestType}) when is_atom(DigestType) -> fun(Key, Data) -> crypto:hmac(DigestType, Key, Data) end. erlang-jose-1.10.1/src/jwa/jose_jwa_pkcs1.erl0000644000232200023220000007437413605433351021346 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc PKCS #1: RSA Cryptography Specifications Version 2.1 %%% See RFC 3447: [https://tools.ietf.org/html/rfc3447] %%% @end %%% Created : 28 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_pkcs1). -include_lib("public_key/include/public_key.hrl"). %% Public Key API -export([decrypt_private/3]). -export([encrypt_public/3]). -export([sign/4]). -export([verify/5]). %% API -export([eme_oaep_decode/4]). -export([eme_oaep_encode/5]). -export([eme_pkcs1_decode/2]). -export([eme_pkcs1_encode/2]). -export([emsa_pkcs1_encode/4]). -export([emsa_pss_encode/3]). -export([emsa_pss_encode/4]). -export([emsa_pss_verify/4]). -export([emsa_pss_verify/5]). -export([mgf1/3]). -export([rsaes_oaep_decrypt/3]). -export([rsaes_oaep_decrypt/4]). -export([rsaes_oaep_encrypt/3]). -export([rsaes_oaep_encrypt/4]). -export([rsaes_oaep_encrypt/5]). -export([rsaes_pkcs1_decrypt/2]). -export([rsaes_pkcs1_encrypt/2]). -export([rsassa_pkcs1_sign/3]). -export([rsassa_pkcs1_sign/4]). -export([rsassa_pkcs1_verify/4]). -export([rsassa_pkcs1_verify/5]). -export([rsassa_pss_sign/3]). -export([rsassa_pss_sign/4]). -export([rsassa_pss_verify/4]). -export([rsassa_pss_verify/5]). %% Types -type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. -type rsa_hash_fun() :: rsa_digest_type() | {hmac, rsa_digest_type(), iodata()} | fun((iodata()) -> binary()). -type rsa_public_key() :: #'RSAPublicKey'{}. -type rsa_private_key() :: #'RSAPrivateKey'{}. -define(PSS_TRAILER_FIELD, 16#BC). %%==================================================================== %% Public Key API functions %%==================================================================== decrypt_private(CipherText, RSAPrivateKey=#'RSAPrivateKey'{}, Options) when is_list(Options) -> case proplists:get_value(rsa_padding, Options) of rsa_pkcs1_oaep_padding -> Hash = proplists:get_value(rsa_oaep_md, Options, sha), Label = proplists:get_value(rsa_oaep_label, Options, <<>>), rsaes_oaep_decrypt(Hash, CipherText, Label, RSAPrivateKey); rsa_pkcs1_padding -> rsaes_pkcs1_decrypt(CipherText, RSAPrivateKey); _ -> erlang:error(notsup) end; decrypt_private(CipherText, PrivateKey, Options) -> erlang:error(badarg, [CipherText, PrivateKey, Options]). encrypt_public(PlainText, RSAPublicKey=#'RSAPublicKey'{}, Options) when is_list(Options) -> Res = case proplists:get_value(rsa_padding, Options) of rsa_pkcs1_oaep_padding -> Hash = proplists:get_value(rsa_oaep_md, Options, sha), Label = proplists:get_value(rsa_oaep_label, Options, <<>>), rsaes_oaep_encrypt(Hash, PlainText, Label, RSAPublicKey); rsa_pkcs1_padding -> rsaes_pkcs1_encrypt(PlainText, RSAPublicKey); _ -> erlang:error(notsup) end, case Res of {ok, Signature} -> Signature; {error, Reason} -> erlang:error(Reason) end; encrypt_public(PlainText, PublicKey, Options) -> erlang:error(badarg, [PlainText, PublicKey, Options]). sign(Message, DigestType, RSAPrivateKey=#'RSAPrivateKey'{}, Options) when is_list(Options) -> Res = case proplists:get_value(rsa_padding, Options) of rsa_pkcs1_pss_padding -> SaltLen = proplists:get_value(rsa_pss_saltlen, Options, -1), rsassa_pss_sign(DigestType, Message, SaltLen, RSAPrivateKey); rsa_pkcs1_padding -> rsassa_pkcs1_sign(DigestType, Message, RSAPrivateKey); _ -> erlang:error(notsup) end, case Res of {ok, Signature} -> Signature; {error, Reason} -> erlang:error(Reason) end; sign(Message, DigestType, PrivateKey, Options) -> erlang:error(badarg, [Message, DigestType, PrivateKey, Options]). verify(Message, DigestType, Signature, RSAPublicKey=#'RSAPublicKey'{}, Options) when is_list(Options) -> case proplists:get_value(rsa_padding, Options) of rsa_pkcs1_pss_padding -> SaltLen = proplists:get_value(rsa_pss_saltlen, Options, -1), rsassa_pss_verify(DigestType, Message, Signature, SaltLen, RSAPublicKey); rsa_pkcs1_padding -> rsassa_pkcs1_verify(DigestType, Message, Signature, RSAPublicKey); _ -> erlang:error(notsup) end; verify(Message, DigestType, Signature, PublicKey, Options) -> erlang:error(badarg, [Message, DigestType, Signature, PublicKey, Options]). %%==================================================================== %% API functions %%==================================================================== %% See [https://tools.ietf.org/html/rfc3447#section-7.1.2] -spec eme_oaep_decode(Hash, EM, Label, K) -> M | error when Hash :: rsa_hash_fun(), EM :: binary(), Label :: binary(), K :: integer(), M :: binary(). eme_oaep_decode(Hash, EM, Label, K) when is_function(Hash, 1) andalso is_binary(EM) andalso is_binary(Label) andalso is_integer(K) -> HLen = byte_size(Hash(<<>>)), LHash = Hash(Label), MaskedDBLen = K - HLen - 1, case EM of << Y, MaskedSeed:HLen/binary, MaskedDB:MaskedDBLen/binary >> -> case mgf1(Hash, MaskedDB, HLen) of {ok, SeedMask} -> Seed = crypto:exor(MaskedSeed, SeedMask), case mgf1(Hash, Seed, K - HLen - 1) of {ok, DBMask} -> DB = crypto:exor(MaskedDB, DBMask), case DB of << LHashPrime:HLen/binary, DBRight/binary >> -> case {Y, unpad_zero(DBRight), LHashPrime} of {16#00, << 16#01, M/binary >>, LHash} -> M; _BadPS -> error end; _BadDB -> error end; _DBMaskMGF1Error -> error end; _SeedMGF1Error -> error end; _BadEM -> error end; eme_oaep_decode(Hash, EM, Label, K) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), eme_oaep_decode(HashFun, EM, Label, K). %% See [https://tools.ietf.org/html/rfc3447#section-7.1.1] -spec eme_oaep_encode(Hash, DM, Label, Seed, K) -> {ok, EM} | {error, Reason} when Hash :: rsa_hash_fun(), DM :: binary(), Label :: binary(), Seed :: binary(), K :: integer(), EM :: binary(), Reason :: term(). eme_oaep_encode(Hash, DM, Label, Seed, K) when is_function(Hash, 1) andalso is_binary(DM) andalso is_binary(Label) andalso is_binary(Seed) andalso is_integer(K) -> HLen = byte_size(Hash(<<>>)), MLen = byte_size(DM), LHash = Hash(Label), PSLen = ((K - MLen - (2 * HLen) - 2) * 8), PS = case PSLen > 0 of true -> << 0:PSLen >>; false -> <<>> end, DB = << LHash/binary, PS/binary, 16#01, DM/binary >>, case mgf1(Hash, Seed, K - HLen - 1) of {ok, DBMask} -> MaskedDB = crypto:exor(DB, DBMask), case mgf1(Hash, MaskedDB, HLen) of {ok, SeedMask} -> MaskedSeed = crypto:exor(Seed, SeedMask), EM = << 16#00, MaskedSeed/binary, MaskedDB/binary >>, {ok, EM}; MGF1SeedError -> MGF1SeedError end; MGF1Error -> MGF1Error end; eme_oaep_encode(Hash, DM, Label, Seed, K) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), eme_oaep_encode(HashFun, DM, Label, Seed, K). %% See [https://tools.ietf.org/html/rfc3447#section-7.2.2] -spec eme_pkcs1_decode(EM, K) -> M | error when EM :: binary(), K :: integer(), M :: binary(). eme_pkcs1_decode(<< 16#00, 16#02, Rest/binary >>, K) when is_integer(K) -> case binary:split(Rest, << 16#00 >>) of [PS, M] when byte_size(PS) >= 8 -> M; _ -> error end; eme_pkcs1_decode(EM, K) when is_binary(EM) andalso is_integer(K) -> error. %% See [https://tools.ietf.org/html/rfc3447#section-7.2.1] -spec eme_pkcs1_encode(DM, K) -> {ok, EM} | {error, Reason} when DM :: binary(), K :: integer(), EM :: binary(), Reason :: term(). eme_pkcs1_encode(DM, K) when is_binary(DM) andalso is_integer(K) -> MLen = byte_size(DM), PSLen = K - MLen - 3, PS = non_zero_strong_random_bytes(PSLen), EM = << 16#00, 16#02, PS/binary, 16#00, DM/binary >>, {ok, EM}. %% See [https://tools.ietf.org/html/rfc3447#section-9.2] -spec emsa_pkcs1_encode(Hash, Algorithm, Message, EMBits) -> {ok, EM} | {error, Reason} when Hash :: rsa_hash_fun(), Algorithm :: md5 | sha | sha1 | sha256 | sha384 | sha512 | binary(), Message :: binary(), EMBits :: integer(), EM :: binary(), Reason :: term(). emsa_pkcs1_encode(Hash, Algorithm, Message, EMBits) when is_function(Hash, 1) andalso is_binary(Algorithm) andalso is_binary(Message) andalso is_integer(EMBits) -> H = Hash(Message), T = << Algorithm/binary, H/binary >>, TLen = byte_size(T), EMLen = ceiling(EMBits / 8), case EMLen < (TLen + 11) of false -> PSLen = EMLen - TLen - 3, PS = binary:copy(<< 16#FF >>, PSLen), EM = << 16#00, 16#01, PS/binary, 16#00, T/binary >>, {ok, EM}; true -> {error, modulus_too_short} end; emsa_pkcs1_encode(Hash, md5, Message, EMBits) -> Algorithm = << 16#30, 16#20, 16#30, 16#0c, 16#06, 16#08, 16#2a, 16#86, 16#48, 16#86, 16#f7, 16#0d, 16#02, 16#05, 16#05, 16#00, 16#04 >>, emsa_pkcs1_encode(Hash, Algorithm, Message, EMBits); emsa_pkcs1_encode(Hash, sha, Message, EMBits) -> emsa_pkcs1_encode(Hash, sha1, Message, EMBits); emsa_pkcs1_encode(Hash, sha1, Message, EMBits) -> Algorithm = << 16#30, 16#21, 16#30, 16#09, 16#06, 16#05, 16#2b, 16#0e, 16#03, 16#02, 16#1a, 16#05, 16#00, 16#04, 16#14 >>, emsa_pkcs1_encode(Hash, Algorithm, Message, EMBits); emsa_pkcs1_encode(Hash, sha256, Message, EMBits) -> Algorithm = << 16#30, 16#31, 16#30, 16#0d, 16#06, 16#09, 16#60, 16#86, 16#48, 16#01, 16#65, 16#03, 16#04, 16#02, 16#01, 16#05, 16#00, 16#04, 16#20 >>, emsa_pkcs1_encode(Hash, Algorithm, Message, EMBits); emsa_pkcs1_encode(Hash, sha384, Message, EMBits) -> Algorithm = << 16#30, 16#41, 16#30, 16#0d, 16#06, 16#09, 16#60, 16#86, 16#48, 16#01, 16#65, 16#03, 16#04, 16#02, 16#02, 16#05, 16#00, 16#04, 16#30 >>, emsa_pkcs1_encode(Hash, Algorithm, Message, EMBits); emsa_pkcs1_encode(Hash, sha512, Message, EMBits) -> Algorithm = << 16#30, 16#51, 16#30, 16#0d, 16#06, 16#09, 16#60, 16#86, 16#48, 16#01, 16#65, 16#03, 16#04, 16#02, 16#03, 16#05, 16#00, 16#04, 16#40 >>, emsa_pkcs1_encode(Hash, Algorithm, Message, EMBits); emsa_pkcs1_encode(Hash, Algorithm, Message, EMBits) when is_atom(Hash) -> HashFun = resolve_hash(Hash), emsa_pkcs1_encode(HashFun, Algorithm, Message, EMBits). %% See [https://tools.ietf.org/html/rfc3447#section-9.1.1] -spec emsa_pss_encode(Hash, Message, EMBits) -> {ok, EM} | {error, Reason} when Hash :: rsa_hash_fun(), Message :: binary(), EMBits :: integer(), EM :: binary(), Reason :: term(). emsa_pss_encode(Hash, Message, EMBits) when is_function(Hash, 1) andalso is_binary(Message) andalso is_integer(EMBits) -> emsa_pss_encode(Hash, Message, -2, EMBits); emsa_pss_encode(Hash, Message, EMBits) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), emsa_pss_encode(HashFun, Message, EMBits). %% See [https://tools.ietf.org/html/rfc3447#section-9.1.1] -spec emsa_pss_encode(Hash, Message, Salt, EMBits) -> {ok, EM} | {error, Reason} when Hash :: rsa_hash_fun(), Message :: binary(), Salt :: binary() | integer(), EMBits :: integer(), EM :: binary(), Reason :: term(). emsa_pss_encode(Hash, Message, Salt, EMBits) when is_function(Hash, 1) andalso is_binary(Message) andalso is_binary(Salt) andalso is_integer(EMBits) -> MHash = Hash(Message), HashLen = byte_size(MHash), SaltLen = byte_size(Salt), EMLen = ceiling(EMBits / 8), case EMLen < (HashLen + SaltLen + 2) of false -> MPrime = << 0:64, MHash/binary, Salt/binary >>, H = Hash(MPrime), PS = << 0:((EMLen - SaltLen - HashLen - 2) * 8) >>, DB = << PS/binary, 16#01, Salt/binary >>, case mgf1(Hash, H, EMLen - HashLen - 1) of {ok, DBMask} -> LeftBits = (EMLen * 8) - EMBits, << _:LeftBits/bitstring, MaskedDBRight/bitstring >> = crypto:exor(DB, DBMask), MaskedDB = << 0:LeftBits, MaskedDBRight/bitstring >>, EM = << MaskedDB/binary, H/binary, ?PSS_TRAILER_FIELD >>, {ok, EM}; MGF1Error -> MGF1Error end; true -> {error, encoding_error} end; emsa_pss_encode(Hash, Message, -2, EMBits) when is_function(Hash, 1) andalso is_integer(EMBits) -> HashLen = byte_size(Hash(<<>>)), EMLen = ceiling(EMBits / 8), SaltLen = EMLen - HashLen - 2, case SaltLen < 0 of false -> emsa_pss_encode(Hash, Message, SaltLen, EMBits); true -> {error, encoding_error} end; emsa_pss_encode(Hash, Message, -1, EMBits) when is_function(Hash, 1) -> HashLen = byte_size(Hash(<<>>)), SaltLen = HashLen, emsa_pss_encode(Hash, Message, SaltLen, EMBits); emsa_pss_encode(Hash, Message, SaltLen, EMBits) when is_integer(SaltLen) andalso SaltLen >= 0 -> Salt = crypto:strong_rand_bytes(SaltLen), emsa_pss_encode(Hash, Message, Salt, EMBits); emsa_pss_encode(Hash, Message, Salt, EMBits) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), emsa_pss_encode(HashFun, Message, Salt, EMBits). %% See [https://tools.ietf.org/html/rfc3447#section-9.1.2] -spec emsa_pss_verify(Hash, Message, EM, EMBits) -> boolean() when Hash :: rsa_hash_fun(), Message :: binary(), EM :: binary(), EMBits :: integer(). emsa_pss_verify(Hash, Message, EM, EMBits) when is_function(Hash, 1) andalso is_binary(Message) andalso is_binary(EM) andalso is_integer(EMBits) -> emsa_pss_verify(Hash, Message, EM, -2, EMBits); emsa_pss_verify(Hash, Message, EM, EMBits) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), emsa_pss_verify(HashFun, Message, EM, EMBits). %% See [https://tools.ietf.org/html/rfc3447#section-9.1.2] -spec emsa_pss_verify(Hash, Message, EM, SaltLen, EMBits) -> boolean() when Hash :: rsa_hash_fun(), Message :: binary(), EM :: binary(), SaltLen :: integer(), EMBits :: integer(). emsa_pss_verify(Hash, Message, EM, SaltLen, EMBits) when is_function(Hash, 1) andalso is_binary(Message) andalso is_integer(SaltLen) andalso SaltLen >= 0 andalso is_integer(EMBits) -> MHash = Hash(Message), HashLen = byte_size(MHash), EMLen = ceiling(EMBits / 8), MaskedDBLen = (EMLen - HashLen - 1), case {EMLen < (HashLen + SaltLen + 2), byte_size(EM), EM} of {false, EMLen, << MaskedDB:MaskedDBLen/binary, H:HashLen/binary, ?PSS_TRAILER_FIELD >>} -> LeftBits = ((EMLen * 8) - EMBits), case MaskedDB of << 0:LeftBits, _/bitstring >> -> case mgf1(Hash, H, EMLen - HashLen - 1) of {ok, DBMask} -> << _:LeftBits/bitstring, DBRight/bitstring >> = crypto:exor(MaskedDB, DBMask), DB = << 0:LeftBits, DBRight/bitstring >>, PSLen = ((EMLen - HashLen - SaltLen - 2) * 8), case DB of << 0:PSLen, 16#01, Salt:SaltLen/binary >> -> MPrime = << 0:64, MHash/binary, Salt/binary >>, HPrime = Hash(MPrime), H =:= HPrime; _BadDB -> false end; _MGF1Error -> false end; _BadMaskedDB -> false end; _BadEMLen -> false end; emsa_pss_verify(Hash, Message, EM, -2, EMBits) when is_function(Hash, 1) andalso is_integer(EMBits) -> HashLen = byte_size(Hash(<<>>)), EMLen = ceiling(EMBits / 8), SaltLen = EMLen - HashLen - 2, case SaltLen < 0 of false -> emsa_pss_verify(Hash, Message, EM, SaltLen, EMBits); true -> false end; emsa_pss_verify(Hash, Message, EM, -1, EMBits) when is_function(Hash, 1) -> HashLen = byte_size(Hash(<<>>)), SaltLen = HashLen, emsa_pss_verify(Hash, Message, EM, SaltLen, EMBits). %% See [https://tools.ietf.org/html/rfc3447#appendix-B.2] -spec mgf1(Hash, Seed, MaskLen) -> {ok, binary()} | {error, mask_too_long} when Hash :: rsa_hash_fun(), Seed :: binary(), MaskLen :: pos_integer(). mgf1(Hash, Seed, MaskLen) when is_function(Hash, 1) andalso is_binary(Seed) andalso is_integer(MaskLen) andalso MaskLen >= 0 -> HashLen = byte_size(Hash(<<>>)), case MaskLen > (16#FFFFFFFF * HashLen) of false -> Reps = ceiling(MaskLen / HashLen), {ok, derive_mgf1(Hash, 0, Reps, Seed, MaskLen, <<>>)}; true -> {error, mask_too_long} end; mgf1(Hash, Seed, MaskLen) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), mgf1(HashFun, Seed, MaskLen). %% See [https://tools.ietf.org/html/rfc3447#section-7.1.2] -spec rsaes_oaep_decrypt(Hash, CipherText, RSAPrivateKey) -> PlainText when Hash :: rsa_hash_fun(), CipherText :: binary(), RSAPrivateKey :: rsa_private_key(), PlainText :: binary(). rsaes_oaep_decrypt(Hash, CipherText, RSAPrivateKey=#'RSAPrivateKey'{}) when is_function(Hash, 1) andalso is_binary(CipherText) -> rsaes_oaep_decrypt(Hash, CipherText, <<>>, RSAPrivateKey); rsaes_oaep_decrypt(Hash, CipherText, RSAPrivateKey) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsaes_oaep_decrypt(HashFun, CipherText, RSAPrivateKey). %% See [https://tools.ietf.org/html/rfc3447#section-7.1.2] -spec rsaes_oaep_decrypt(Hash, CipherText, Label, RSAPrivateKey) -> PlainText when Hash :: rsa_hash_fun(), CipherText :: binary(), Label :: binary(), RSAPrivateKey :: rsa_private_key(), PlainText :: binary(). rsaes_oaep_decrypt(Hash, CipherText, Label, RSAPrivateKey=#'RSAPrivateKey'{modulus=N}) when is_function(Hash, 1) andalso is_binary(CipherText) andalso is_binary(Label) -> HLen = byte_size(Hash(<<>>)), K = int_to_byte_size(N), case {byte_size(CipherText), K < ((2 * HLen) + 2)} of {K, false} -> EM = pad_to_key_size(K, dp(CipherText, RSAPrivateKey)), eme_oaep_decode(Hash, EM, Label, K); _BadSize -> {error, {badsize, _BadSize}} end; rsaes_oaep_decrypt(Hash, CipherText, Label, RSAPrivateKey) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsaes_oaep_decrypt(HashFun, CipherText, Label, RSAPrivateKey). %% See [https://tools.ietf.org/html/rfc3447#section-7.1.1] -spec rsaes_oaep_encrypt(Hash, PlainText, RSAPublicKey) -> CipherText when Hash :: rsa_hash_fun(), PlainText :: binary(), RSAPublicKey :: rsa_public_key(), CipherText :: binary(). rsaes_oaep_encrypt(Hash, PlainText, RSAPublicKey=#'RSAPublicKey'{}) when is_function(Hash, 1) andalso is_binary(PlainText) -> rsaes_oaep_encrypt(Hash, PlainText, <<>>, RSAPublicKey); rsaes_oaep_encrypt(Hash, PlainText, RSAPublicKey) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsaes_oaep_encrypt(HashFun, PlainText, RSAPublicKey). %% See [https://tools.ietf.org/html/rfc3447#section-7.1.1] -spec rsaes_oaep_encrypt(Hash, PlainText, Label, RSAPublicKey) -> CipherText when Hash :: rsa_hash_fun(), PlainText :: binary(), Label :: binary(), RSAPublicKey :: rsa_public_key(), CipherText :: binary(). rsaes_oaep_encrypt(Hash, PlainText, Label, RSAPublicKey=#'RSAPublicKey'{}) when is_function(Hash, 1) andalso is_binary(PlainText) andalso is_binary(Label) -> HLen = byte_size(Hash(<<>>)), Seed = crypto:strong_rand_bytes(HLen), rsaes_oaep_encrypt(Hash, PlainText, Label, Seed, RSAPublicKey); rsaes_oaep_encrypt(Hash, PlainText, Label, RSAPublicKey) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsaes_oaep_encrypt(HashFun, PlainText, Label, RSAPublicKey). %% See [https://tools.ietf.org/html/rfc3447#section-7.1.1] -spec rsaes_oaep_encrypt(Hash, PlainText, Label, Seed, RSAPublicKey) -> CipherText when Hash :: rsa_hash_fun(), PlainText :: binary(), Label :: binary(), Seed :: binary(), RSAPublicKey :: rsa_public_key(), CipherText :: binary(). rsaes_oaep_encrypt(Hash, PlainText, Label, Seed, RSAPublicKey=#'RSAPublicKey'{modulus=N}) when is_function(Hash, 1) andalso is_binary(PlainText) andalso is_binary(Label) andalso is_binary(Seed) -> HLen = byte_size(Hash(<<>>)), MLen = byte_size(PlainText), K = int_to_byte_size(N), case MLen > (K - (2 * HLen) - 2) of false -> case eme_oaep_encode(Hash, PlainText, Label, Seed, K) of {ok, EM} -> C = pad_to_key_size(K, ep(EM, RSAPublicKey)), {ok, C}; EncodingError -> EncodingError end; true -> {error, message_too_long} end; rsaes_oaep_encrypt(Hash, PlainText, Label, Seed, RSAPublicKey) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsaes_oaep_encrypt(HashFun, PlainText, Label, Seed, RSAPublicKey). %% See [https://tools.ietf.org/html/rfc3447#section-7.2.2] -spec rsaes_pkcs1_decrypt(CipherText, RSAPrivateKey) -> PlainText when CipherText :: binary(), RSAPrivateKey :: rsa_private_key(), PlainText :: binary(). rsaes_pkcs1_decrypt(CipherText, RSAPrivateKey=#'RSAPrivateKey'{modulus=N}) when is_binary(CipherText) -> K = int_to_byte_size(N), case {byte_size(CipherText), K < 11} of {K, false} -> EM = pad_to_key_size(K, dp(CipherText, RSAPrivateKey)), eme_pkcs1_decode(EM, K); _BadSize -> {error, {badsize, _BadSize}} end. %% See [https://tools.ietf.org/html/rfc3447#section-7.2.1] -spec rsaes_pkcs1_encrypt(PlainText, RSAPublicKey) -> CipherText when PlainText :: binary(), RSAPublicKey :: rsa_public_key(), CipherText :: binary(). rsaes_pkcs1_encrypt(PlainText, RSAPublicKey=#'RSAPublicKey'{modulus=N}) when is_binary(PlainText) -> MLen = byte_size(PlainText), K = int_to_byte_size(N), case MLen > (K - 11) of false -> case eme_pkcs1_encode(PlainText, K) of {ok, EM} -> C = pad_to_key_size(K, ep(EM, RSAPublicKey)), {ok, C}; EncodingError -> EncodingError end; true -> {error, message_too_long} end. %% See [https://tools.ietf.org/html/rfc3447#section-8.1.1] -spec rsassa_pkcs1_sign(Hash, Message, RSAPrivateKey) -> {ok, Signature} | {error, Reason} when Hash :: rsa_hash_fun(), Message :: binary(), RSAPrivateKey :: rsa_private_key(), Signature :: binary(), Reason :: term(). rsassa_pkcs1_sign(Hash, Message, RSAPrivateKey) when is_atom(Hash) -> rsassa_pkcs1_sign(Hash, Hash, Message, RSAPrivateKey). %% See [https://tools.ietf.org/html/rfc3447#section-8.1.1] -spec rsassa_pkcs1_sign(Hash, Algorithm, Message, RSAPrivateKey) -> {ok, Signature} | {error, Reason} when Hash :: rsa_hash_fun(), Algorithm :: md5 | sha | sha1 | sha256 | sha384 | sha512 | binary(), Message :: binary(), RSAPrivateKey :: rsa_private_key(), Signature :: binary(), Reason :: term(). rsassa_pkcs1_sign(Hash, Algorithm, Message, RSAPrivateKey=#'RSAPrivateKey'{modulus=Modulus}) when is_function(Hash, 1) andalso (is_atom(Algorithm) orelse is_binary(Algorithm)) andalso is_binary(Message) -> ModBits = int_to_bit_size(Modulus), case emsa_pkcs1_encode(Hash, Algorithm, Message, ModBits - 1) of {ok, EM} -> ModBytes = int_to_byte_size(Modulus), S = pad_to_key_size(ModBytes, dp(EM, RSAPrivateKey)), {ok, S}; EncodingError -> EncodingError end; rsassa_pkcs1_sign(Hash, Algorithm, Message, RSAPrivateKey=#'RSAPrivateKey'{}) when is_atom(Hash) -> HashFun = resolve_hash(Hash), rsassa_pkcs1_sign(HashFun, Algorithm, Message, RSAPrivateKey). %% See [https://tools.ietf.org/html/rfc3447#section-8.2.2] -spec rsassa_pkcs1_verify(Hash, Message, Signature, RSAPublicKey) -> boolean() when Hash :: rsa_hash_fun(), Message :: binary(), Signature :: binary(), RSAPublicKey :: rsa_public_key(). rsassa_pkcs1_verify(Hash, Message, Signature, RSAPublicKey) when is_atom(Hash) -> rsassa_pkcs1_verify(Hash, Hash, Message, Signature, RSAPublicKey). %% See [https://tools.ietf.org/html/rfc3447#section-8.2.2] -spec rsassa_pkcs1_verify(Hash, Algorithm, Message, Signature, RSAPublicKey) -> boolean() when Hash :: rsa_hash_fun(), Algorithm :: md5 | sha | sha1 | sha256 | sha384 | sha512 | binary(), Message :: binary(), Signature :: binary(), RSAPublicKey :: rsa_public_key(). rsassa_pkcs1_verify(Hash, Algorithm, Message, Signature, RSAPublicKey=#'RSAPublicKey'{modulus=Modulus}) when is_function(Hash, 1) andalso is_binary(Message) andalso is_binary(Signature) -> ModBytes = int_to_byte_size(Modulus), case byte_size(Signature) =:= ModBytes of true -> ModBits = int_to_bit_size(Modulus), EM = pad_to_key_size(ceiling((ModBits - 1) / 8), ep(Signature, RSAPublicKey)), case emsa_pkcs1_encode(Hash, Algorithm, Message, ModBits - 1) of {ok, EMPrime} -> jose_jwa:constant_time_compare(EM, EMPrime); _ -> false end; false -> false end; rsassa_pkcs1_verify(Hash, Algorithm, Message, Signature, RSAPublicKey=#'RSAPublicKey'{}) when is_atom(Hash) -> HashFun = resolve_hash(Hash), rsassa_pkcs1_verify(HashFun, Algorithm, Message, Signature, RSAPublicKey). %% See [https://tools.ietf.org/html/rfc3447#section-8.1.1] -spec rsassa_pss_sign(Hash, Message, RSAPrivateKey) -> {ok, Signature} | {error, Reason} when Hash :: rsa_hash_fun(), Message :: binary(), RSAPrivateKey :: rsa_private_key(), Signature :: binary(), Reason :: term(). rsassa_pss_sign(Hash, Message, RSAPrivateKey=#'RSAPrivateKey'{modulus=Modulus}) when is_function(Hash, 1) andalso is_binary(Message) -> ModBits = int_to_bit_size(Modulus), case emsa_pss_encode(Hash, Message, ModBits - 1) of {ok, EM} -> ModBytes = int_to_byte_size(Modulus), S = pad_to_key_size(ModBytes, dp(EM, RSAPrivateKey)), {ok, S}; EncodingError -> EncodingError end; rsassa_pss_sign(Hash, Message, RSAPrivateKey=#'RSAPrivateKey'{}) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsassa_pss_sign(HashFun, Message, RSAPrivateKey). %% See [https://tools.ietf.org/html/rfc3447#section-8.1.1] -spec rsassa_pss_sign(Hash, Message, Salt, RSAPrivateKey) -> {ok, Signature} | {error, Reason} when Hash :: rsa_hash_fun(), Message :: binary(), Salt :: binary() | integer(), RSAPrivateKey :: rsa_private_key(), Signature :: binary(), Reason :: term(). rsassa_pss_sign(Hash, Message, Salt, RSAPrivateKey=#'RSAPrivateKey'{modulus=Modulus}) when is_function(Hash, 1) andalso is_binary(Message) andalso (is_binary(Salt) orelse is_integer(Salt)) -> ModBits = int_to_bit_size(Modulus), case emsa_pss_encode(Hash, Message, Salt, ModBits - 1) of {ok, EM} -> ModBytes = int_to_byte_size(Modulus), S = pad_to_key_size(ModBytes, dp(EM, RSAPrivateKey)), {ok, S}; EncodingError -> EncodingError end; rsassa_pss_sign(Hash, Message, Salt, RSAPrivateKey=#'RSAPrivateKey'{}) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsassa_pss_sign(HashFun, Message, Salt, RSAPrivateKey). %% See [https://tools.ietf.org/html/rfc3447#section-8.1.2] -spec rsassa_pss_verify(Hash, Message, Signature, RSAPublicKey) -> boolean() when Hash :: rsa_hash_fun(), Message :: binary(), Signature :: binary(), RSAPublicKey :: rsa_public_key(). rsassa_pss_verify(Hash, Message, Signature, RSAPublicKey=#'RSAPublicKey'{modulus=Modulus}) when is_function(Hash, 1) andalso is_binary(Message) andalso is_binary(Signature) -> ModBytes = int_to_byte_size(Modulus), case byte_size(Signature) =:= ModBytes of true -> ModBits = int_to_bit_size(Modulus), EM = pad_to_key_size(ceiling((ModBits - 1) / 8), ep(Signature, RSAPublicKey)), emsa_pss_verify(Hash, Message, EM, ModBits - 1); false -> false end; rsassa_pss_verify(Hash, Message, Signature, RSAPublicKey=#'RSAPublicKey'{}) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsassa_pss_verify(HashFun, Message, Signature, RSAPublicKey). %% See [https://tools.ietf.org/html/rfc3447#section-8.1.2] -spec rsassa_pss_verify(Hash, Message, Signature, SaltLen, RSAPublicKey) -> boolean() when Hash :: rsa_hash_fun(), Message :: binary(), Signature :: binary(), SaltLen :: integer(), RSAPublicKey :: rsa_public_key(). rsassa_pss_verify(Hash, Message, Signature, SaltLen, RSAPublicKey=#'RSAPublicKey'{modulus=Modulus}) when is_function(Hash, 1) andalso is_binary(Message) andalso is_binary(Signature) andalso is_integer(SaltLen) -> ModBytes = int_to_byte_size(Modulus), case byte_size(Signature) =:= ModBytes of true -> ModBits = int_to_bit_size(Modulus), EM = pad_to_key_size(ceiling((ModBits - 1) / 8), ep(Signature, RSAPublicKey)), emsa_pss_verify(Hash, Message, EM, SaltLen, ModBits - 1); false -> false end; rsassa_pss_verify(Hash, Message, Signature, SaltLen, RSAPublicKey=#'RSAPublicKey'{}) when is_tuple(Hash) orelse is_atom(Hash) -> HashFun = resolve_hash(Hash), rsassa_pss_verify(HashFun, Message, Signature, SaltLen, RSAPublicKey). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private ceiling(X) when X < 0 -> trunc(X); ceiling(X) -> T = trunc(X), case X - T == 0 of false -> T + 1; true -> T end. %% @private derive_mgf1(_Hash, Reps, Reps, _Seed, MaskLen, T) -> binary:part(T, 0, MaskLen); derive_mgf1(Hash, Counter, Reps, Seed, MaskLen, T) -> CounterBin = << Counter:8/unsigned-big-integer-unit:4 >>, NewT = << T/binary, (Hash(<< Seed/binary, CounterBin/binary >>))/binary >>, derive_mgf1(Hash, Counter + 1, Reps, Seed, MaskLen, NewT). %% @private dp(B, #'RSAPrivateKey'{modulus=N, privateExponent=E}) -> crypto:mod_pow(B, E, N). %% @private ep(B, #'RSAPublicKey'{modulus=N, publicExponent=E}) -> crypto:mod_pow(B, E, N). %% @private int_to_bit_size(I) -> int_to_bit_size(I, 0). %% @private int_to_bit_size(0, B) -> B; int_to_bit_size(I, B) -> int_to_bit_size(I bsr 1, B + 1). %% @private int_to_byte_size(I) -> int_to_byte_size(I, 0). %% @private int_to_byte_size(0, B) -> B; int_to_byte_size(I, B) -> int_to_byte_size(I bsr 8, B + 1). %% @private non_zero_strong_random_byte() -> case crypto:strong_rand_bytes(1) of << 0 >> -> non_zero_strong_random_byte(); Byte -> Byte end. %% @private non_zero_strong_random_bytes(N) -> << << (case C of 0 -> << (non_zero_strong_random_byte())/binary >>; _ -> << C >> end)/binary >> || << C >> <= crypto:strong_rand_bytes(N) >>. %% @private pad_to_key_size(Bytes, Data) when byte_size(Data) < Bytes -> pad_to_key_size(Bytes, << 0, Data/binary >>); pad_to_key_size(_Bytes, Data) -> Data. %% @private resolve_hash(HashFun) when is_function(HashFun, 1) -> HashFun; resolve_hash(DigestType) when is_atom(DigestType) -> fun(Data) -> crypto:hash(DigestType, Data) end; resolve_hash({hmac, DigestType, Key}) when is_atom(DigestType) -> fun(Data) -> crypto:hmac(DigestType, Key, Data) end. %% @private unpad_zero(<< 0, Rest/binary >>) -> unpad_zero(Rest); unpad_zero(Rest) -> Rest. erlang-jose-1.10.1/src/jwa/jose_jwa_xchacha20_poly1305.erl0000644000232200023220000000351013605433351023422 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc XChaCha: eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 %%% See https://tools.ietf.org/html/draft-irtf-cfrg-xchacha %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_xchacha20_poly1305). -behaviour(jose_xchacha20_poly1305). %% jose_xchacha20_poly1305 callbacks -export([decrypt/5]). -export([encrypt/4]). -export([authenticate/3]). -export([verify/4]). %%==================================================================== %% jose_chacha20_poly1305 callbacks %%==================================================================== decrypt(CipherText, CipherTag, AAD, IV, CEK) -> {Subkey, Nonce} = jose_jwa_xchacha20:subkey_and_nonce(CEK, IV), jose_chacha20_poly1305:block_decrypt({chacha20_poly1305, 256}, Subkey, Nonce, {AAD, CipherText, CipherTag}). encrypt(PlainText, AAD, IV, CEK) -> {Subkey, Nonce} = jose_jwa_xchacha20:subkey_and_nonce(CEK, IV), jose_chacha20_poly1305:block_encrypt({chacha20_poly1305, 256}, Subkey, Nonce, {AAD, PlainText}). authenticate(Message, Key, Nonce0) -> {Subkey, Nonce} = jose_jwa_xchacha20:subkey_and_nonce(Key, Nonce0), jose_chacha20_poly1305:authenticate(Message, Nonce, Subkey). verify(MAC, Message, Key, Nonce0) -> {Subkey, Nonce} = jose_jwa_xchacha20:subkey_and_nonce(Key, Nonce0), jose_chacha20_poly1305:verify(MAC, Message, Nonce, Subkey). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwa/jose_jwa_ed448.erl0000644000232200023220000003325313605433351021144 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc Edwards-curve Digital Signature Algorithm (EdDSA) - Ed448 %%% See https://tools.ietf.org/html/draft-irtf-cfrg-eddsa %%% @end %%% Created : 20 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_ed448). %% API -export([xrecover/2]). -export([encode_point/1]). -export([decode_point/1]). -export([edwards_add/2]). -export([edwards_double/1]). -export([edwards_equal/2]). -export([scalarmult/2]). -export([scalarmult_base/1]). -export([normalize_point/1]). -export([secret/0]). -export([secret_to_curve448/1]). -export([secret_to_pk/1]). -export([keypair/0]). -export([keypair/1]). -export([sk_to_secret/1]). -export([sk_to_pk/1]). -export([sk_to_curve448/1]). -export([pk_to_curve448/1]). -export([sign/2]). -export([sign/3]). -export([sign_with_prehash/2]). -export([sign_with_prehash/3]). -export([verify/3]). -export([verify/4]). -export([verify_with_prehash/3]). -export([verify_with_prehash/4]). %% Macros -define(math, jose_jwa_math). -define(inv(Z), ?math:expmod(Z, ?p - 2, ?p)). % $= z^{-1} \mod p$, for z != 0 % 3. EdDSA Algorithm - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-3 % 5.2. Ed448ph and Ed448 - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2 -define(d, -39081). % -39081 % -define(d, 611975850744529176160423220965553317543219696871016626328968936415087860042636474891785599283666020414768678979989378147065462815545017). %% 1. An odd prime power p. EdDSA uses an elliptic curve over the %% finite field GF(p). -define(p, 726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018365439). % ?math:intpow(2, 448) - ?math:intpow(2, 224) - 1 %% 2. An integer b with 2^(b-1) > p. EdDSA public keys have exactly b %% bits, and EdDSA signatures have exactly 2*b bits. b is %% recommended to be multiple of 8, so public key and signature %% lengths are integral number of octets. -define(b, 456). % ?math:intpow(2, ?b - 1) > ?p -define(b_curve448, 448). %% 3. A (b-1)-bit encoding of elements of the finite field GF(p). -define(GFp, << 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FE,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#00 >>). % << ?p:(?b - 1)/unsigned-little-integer-unit:1, 0:1 >> %% 4. A cryptographic hash function H producing 2*b-bit output. %% Conservative hash functions are recommended and do not have much %% impact on the total cost of EdDSA. -define(HBits, 912). % ?b * 2 -define(HBytes, 114). % (?Hbits + 7) div 8 % -define(H(M), jose_sha3:shake256(<< "SigEd448", 16#00, 16#00, M/binary >>, ?HBytes)). -define(H(M), jose_sha3:shake256(M, ?HBytes)). -define(HdomHash(C, M), << "SigEd448", 16#01, (byte_size(C)):8/integer, C/binary, M/binary >>). -define(HdomPure(C, M), << "SigEd448", 16#00, (byte_size(C)):8/integer, C/binary, M/binary >>). %% 5. An integer c that is 2 or 3. Secret EdDSA scalars are multiples %% of 2^c. The integer c is the base-2 logarithm of the so called %% cofactor. -define(c, 2). %% 6. An integer n with c <= n < b. Secret EdDSA scalars have exactly %% n + 1 bits, with the top bit (the 2^n position) always set and %% the bottom c bits always cleared. -define(n, 448). % ?c =< ?n andalso ?n < ?b %% 7. A nonzero square element a of GF(p). The usual recommendation %% for best performance is a = -1 if p mod 4 = 1, and a = 1 if p %% mod 4 = 3. -define(a, 1). %% 8. An element B != (0,1) of the set E = { (x,y) is a member of %% GF(p) x GF(p) such that a * x^2 + y^2 = 1 + d * x^2 * y^2 }. -define(By, 298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660). -define(Bx, 224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710). % xrecover(?By) -define(B, {?Bx, ?By, 1}). % {?Bx, ?By, 1} % (?a * ?math:intpow(?Bx, 2) + ?math:intpow(?By, 2)) rem ?p == (1 + ?d * ?math:intpow(?Bx, 2) * ?math:intpow(?By, 2)) rem ?p %% 9. An odd prime l such that [l]B = 0 and 2^c * l = #E. The number %% #E (the number of points on the curve) is part of the standard %% data provided for an elliptic curve E. -define(l, 181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779). % ?math:intpow(2, 446) + 13818066809895115352007386748515426880336692474882178609894547503885 -define(E, ?math:intpow(2, ?c) * ?l). %% 10. A "prehash" function PH. PureEdDSA means EdDSA where PH is the %% identity function, i.e., PH(M) = M. HashEdDSA means EdDSA where %% PH generates a short output, no matter how long the message is; %% for example, PH(M) = SHA-512(M). -define(PHBits, 512). -define(PHBytes, 64). % (?PHBits + 7) div 8 -define(PH(C, M), jose_sha3:shake256(<< "SigEd448", 16#02, (byte_size(C)):8/integer, C/binary, M/binary >>, ?PHBytes)). -define(secretbytes, 57). % (?b + 7) div 8 -define(publickeybytes, 57). % (?b + 7) div 8 -define(secretkeybytes, 114). % ?secretbytes + ?publickeybytes %%==================================================================== %% API %%==================================================================== % 5.2.1. Modular arithmetic - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2.1 xrecover(Y, Xb) -> YY = Y * Y, U = (YY - 1), V = (?d * YY - 1), A = U * ?inv(V), X = ?math:expmod(A, (?p + 1) div 4, ?p), case ?math:mod((V * X * X), ?p) =:= ?math:mod(U, ?p) of true -> case X =:= 0 andalso Xb =:= 1 of true -> erlang:error(badarg); false -> case X rem 2 of Xb -> X; _ -> ?p - X end end; false -> erlang:error(badarg) end. % 5.2.2. Encoding - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2.2 encode_point({X, Y, Z}) -> Zi = ?inv(Z), Xp = ?math:mod((X * Zi), ?p), Yp = ?math:mod((Y * Zi), ?p), << YpHead:(?b - 8)/bitstring, _:1/bitstring, YpTail:7/bitstring >> = << Yp:?b/unsigned-little-integer-unit:1 >>, << YpHead/bitstring, (Xp band 1):1/integer, YpTail:7/bitstring >>. % 5.2.3. Decoding - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2.3 decode_point(<< YpHead:(?b - 8)/bitstring, Xb:1, YpTail:7/bitstring >>) -> << Y:?b/unsigned-little-integer-unit:1 >> = << YpHead/bitstring, 0:1, YpTail/bitstring >>, case Y >= ?p of true -> erlang:error(badarg); false -> X = xrecover(Y, Xb), {X, Y, 1} end. % 5.2.4. Point addition - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2.4 edwards_add({X1, Y1, Z1}, {X2, Y2, Z2}) -> Xcp = (X1 * X2) rem ?p, Ycp = (Y1 * Y2) rem ?p, Zcp = (Z1 * Z2) rem ?p, B = (Zcp * Zcp) rem ?p, E = (?d * Xcp * Ycp) rem ?p, F = (B - E) rem ?p, G = (B + E) rem ?p, ZcpF = (Zcp * F) rem ?p, ZcpG = (Zcp * G) rem ?p, X3r = ((X1 + Y1) * (X2 + Y2) - Xcp - Ycp) rem ?p, Y3r = (Ycp - Xcp) rem ?p, X3 = ?math:mod((ZcpF * X3r), ?p), Y3 = ?math:mod((ZcpG * Y3r), ?p), Z3 = ?math:mod((F * G), ?p), {X3, Y3, Z3}. edwards_double({X, Y, Z}) -> XX = (X * X) rem ?p, YY = (Y * Y) rem ?p, ZZ = (Z * Z) rem ?p, XY = (X + Y) rem ?p, F = (XX + YY) rem ?p, J = (F - (ZZ + ZZ)) rem ?p, XYXY = (XY * XY) rem ?p, X3 = ?math:mod(((XYXY - XX - YY) * J), ?p), Y3 = ?math:mod((F * (XX - YY)), ?p), Z3 = ?math:mod((F * J), ?p), {X3, Y3, Z3}. edwards_equal({X1, Y1, Z1}, {X2, Y2, Z2}) -> Xn1 = ?math:mod((X1 * Z2), ?p), Xn2 = ?math:mod((X2 * Z1), ?p), Yn1 = ?math:mod((Y1 * Z2), ?p), Yn2 = ?math:mod((Y2 * Z1), ?p), Xn1 =:= Xn2 andalso Yn1 =:= Yn2. scalarmult(_P, 0) -> {0, 1, 1}; scalarmult(P, E) -> Q = scalarmult(P, E div 2), QQ = edwards_double(Q), case E band 1 of 0 -> QQ; 1 -> edwards_add(QQ, P) end. scalarmult_base(E) -> scalarmult(?B, E). normalize_point({X, Y, Z}) -> Zi = ?inv(Z), Xp = ?math:mod((X * Zi), ?p), Yp = ?math:mod((Y * Zi), ?p), Zp = ?math:mod((Z * Zi), ?p), {Xp, Yp, Zp}. % 5.2.5. Key Generation - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2.5 secret() -> crypto:strong_rand_bytes(?secretbytes). secret_to_curve448(Secret = << _:?secretbytes/binary >>) -> << HHead0:6/bitstring, _:2/bitstring, HBody:54/binary, _:1/bitstring, HKnee0:7/bitstring, _HFoot0:8/integer, _/binary >> = ?H(Secret), << HHead:8/integer >> = << HHead0:6/bitstring, 0:2/integer >>, << HKnee:8/integer >> = << 0:1/integer, HKnee0:7/bitstring >>, HFoot = 0, << Scalar:?b/unsigned-little-integer-unit:1 >> = << HHead:8/integer, HBody/binary, HKnee:8/integer, HFoot:8/integer >>, Clamped = jose_jwa_x448:clamp_scalar(Scalar), << Clamped:?b_curve448/unsigned-little-integer-unit:1 >>. secret_to_pk(Secret = << _:?secretbytes/binary >>) -> << As:?b_curve448/unsigned-little-integer-unit:1 >> = secret_to_curve448(Secret), A = scalarmult(?B, As), encode_point(A). keypair() -> Secret = secret(), keypair(Secret). keypair(Secret = << _:?secretbytes/binary >>) -> PK = secret_to_pk(Secret), SK = << Secret/binary, PK/binary >>, {PK, SK}. sk_to_secret(<< Secret:?secretbytes/binary, _:?publickeybytes/binary >>) -> Secret. sk_to_pk(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>) -> PK. sk_to_curve448(<< Secret:?secretbytes/binary, _:?publickeybytes/binary >>) -> secret_to_curve448(Secret). pk_to_curve448(<< PK:?publickeybytes/binary >>) -> % u = y^2/x^2 _A = {X, Y, _Z} = decode_point(PK), U = ?math:mod((Y * Y) * ?inv(X * X), ?p), % v = (2 - x^2 - y^2)*y/x^3 << U:?b_curve448/unsigned-little-integer-unit:1 >>. % 5.2.6. Sign - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2.6 sign(M, SK = << _:?secretkeybytes/binary >>) when is_binary(M) -> sign(M, SK, <<>>). sign(M, << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>, C) when is_binary(C) andalso byte_size(C) =< 255 andalso is_binary(M) -> << HHead0:6/bitstring, _:2/bitstring, HBody:54/binary, _:1/bitstring, HKnee0:7/bitstring, _HFoot0:8/integer, HTail:57/binary >> = ?H(Secret), << HHead:8/integer >> = << HHead0:6/bitstring, 0:2/integer >>, << HKnee:8/integer >> = << 0:1/integer, HKnee0:7/bitstring >>, HFoot = 0, << Scalar:?b/unsigned-little-integer-unit:1 >> = << HHead:8/integer, HBody/binary, HKnee:8/integer, HFoot:8/integer >>, As = jose_jwa_x448:clamp_scalar(Scalar), << Ri:?HBits/unsigned-little-integer-unit:1 >> = ?H(?HdomPure(C, (<< HTail/binary, M/binary >>))), Rs = ?math:mod(Ri, ?l), R = encode_point(scalarmult(?B, Rs)), << Ki:?HBits/unsigned-little-integer-unit:1 >> = ?H(?HdomPure(C, (<< R/binary, PK/binary, M/binary >>))), K = ?math:mod(Ki, ?l), S = ?math:mod(Rs + (K * As), ?l), << R/binary, S:?b/unsigned-little-integer-unit:1 >>. sign_with_prehash(M, SK = << _:?secretkeybytes/binary >>) when is_binary(M) -> sign_with_prehash(M, SK, <<>>). sign_with_prehash(M, << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>, C) when is_binary(C) andalso byte_size(C) =< 255 andalso is_binary(M) -> HM = ?PH(C, M), << HHead0:6/bitstring, _:2/bitstring, HBody:54/binary, _:1/bitstring, HKnee0:7/bitstring, _HFoot0:8/integer, HTail:57/binary >> = ?H(Secret), << HHead:8/integer >> = << HHead0:6/bitstring, 0:2/integer >>, << HKnee:8/integer >> = << 0:1/integer, HKnee0:7/bitstring >>, HFoot = 0, << Scalar:?b/unsigned-little-integer-unit:1 >> = << HHead:8/integer, HBody/binary, HKnee:8/integer, HFoot:8/integer >>, As = jose_jwa_x448:clamp_scalar(Scalar), << Ri:?HBits/unsigned-little-integer-unit:1 >> = ?H(?HdomHash(C, (<< HTail/binary, HM/binary >>))), Rs = ?math:mod(Ri, ?l), R = encode_point(scalarmult(?B, Rs)), << Ki:?HBits/unsigned-little-integer-unit:1 >> = ?H(?HdomHash(C, (<< R/binary, PK/binary, HM/binary >>))), K = ?math:mod(Ki, ?l), S = ?math:mod(Rs + (K * As), ?l), << R/binary, S:?b/unsigned-little-integer-unit:1 >>. % 5.2.7. Verify - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2.7 verify(Sig, M, PK = << _:?publickeybytes/binary >>) when is_binary(Sig) andalso is_binary(M) -> verify(Sig, M, PK, <<>>). verify(<< R:?b/bitstring, S:?b/unsigned-little-integer-unit:1 >>, M, PK = << _:?publickeybytes/binary >>, C) when is_binary(C) andalso byte_size(C) =< 255 andalso is_binary(M) andalso S >= 0 andalso S < ?l -> A = decode_point(PK), << Ki:?HBits/unsigned-little-integer-unit:1 >> = ?H(?HdomPure(C, (<< R/binary, PK/binary, M/binary >>))), K = ?math:mod(Ki, ?l), edwards_equal(scalarmult(?B, S), edwards_add(decode_point(R), scalarmult(A, K))); verify(Sig, M, << _:?publickeybytes/binary >>, C) when is_binary(Sig) andalso is_binary(C) andalso byte_size(C) =< 255 andalso is_binary(M) -> false. verify_with_prehash(Sig, M, PK = << _:?publickeybytes/binary >>) when is_binary(Sig) andalso is_binary(M) -> verify_with_prehash(Sig, M, PK, <<>>). verify_with_prehash(<< R:?b/bitstring, S:?b/unsigned-little-integer-unit:1 >>, M, PK = << _:?publickeybytes/binary >>, C) when is_binary(C) andalso byte_size(C) =< 255 andalso is_binary(M) andalso S >= 0 andalso S < ?l -> HM = ?PH(C, M), A = decode_point(PK), << Ki:?HBits/unsigned-little-integer-unit:1 >> = ?H(?HdomHash(C, (<< R/binary, PK/binary, HM/binary >>))), K = ?math:mod(Ki, ?l), edwards_equal(scalarmult(?B, S), edwards_add(decode_point(R), scalarmult(A, K))); verify_with_prehash(Sig, M, << _:?publickeybytes/binary >>, C) when is_binary(Sig) andalso is_binary(C) andalso byte_size(C) =< 255 andalso is_binary(M) -> false. erlang-jose-1.10.1/src/jwa/jose_jwa_x448.erl0000644000232200023220000001277713605433351021033 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc Elliptic Curves for Security - X448 %%% See https://tools.ietf.org/html/rfc7748 %%% @end %%% Created : 07 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_x448). %% API -export([coordinate_to_edwards448_4isogeny/1]). -export([vrecover/1]). -export([xrecover/1]). -export([curve448/2]). -export([clamp_scalar/1]). -export([decode_scalar/1]). -export([montgomery_add/3]). -export([montgomery_double/1]). -export([scalarmult/2]). -export([scalarmult_base/1]). -export([x448/2]). -export([x448_base/1]). -export([keypair/0]). -export([keypair/1]). -export([sk_to_pk/1]). %% Macros -define(math, jose_jwa_math). -define(inv(Z), ?math:expmod(Z, ?p - 2, ?p)). % $= z^{-1} \mod p$, for z != 0 -define(d, 611975850744529176160423220965553317543219696871016626328968936415087860042636474891785599283666020414768678979989378147065462815545017). % 4.2. Curve448 - https://tools.ietf.org/html/rfc7748#section-4.2 -define(p, 726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018365439). % ?math:intpow(2, 448) - ?math:intpow(2, 224) - 1 -define(A, 156326). -define(A2sqrt, 528950257000142451010969798134146496096806208096258258133290419984524923934728256972792120570883515182233459997657945594599653183173011). % ?math:expmod((?A - 2), (?p + 1) div 4, ?p) -define(order, 181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779). % ?math:intpow(2, 446) - 16#8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d -define(cofactor, 4). -define(u, 5). -define(v, 355293926785568175264127502063783334808976399387714271831880898435169088786967410002932673765864550910142774147268105838985595290606362). -define(b, 448). -define(a24, 39081). % (?A - 2) div 4 -define(scalarbytes, 56). % (?b + 7) div 8 -define(coordinatebytes, 56). % (?b + 7) div 8 -define(publickeybytes, 56). % ?coordinatebytes -define(secretkeybytes, 56). % ?scalarbytes %%==================================================================== %% API %%==================================================================== coordinate_to_edwards448_4isogeny(<< U:?b/unsigned-little-integer-unit:1 >>) -> V = vrecover(U), % -(u^5 - 2*u^3 - 4*u*v^2 + u)/(u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u) U2 = ?math:expmod(U, 2, ?p), U3 = ?math:expmod(U, 3, ?p), U5 = ?math:mod(U2*U3, ?p), V2 = ?math:expmod(V, 2, ?p), YN = ?math:mod(-(U5 - (2*U3) - (4*U*V2) + U), ?p), YD = ?inv((U5 - (2*U2*V2) - (2*U3) - (2*V2) + U)), Y = ?math:mod(YN*YD, ?p), % 4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1) U4 = ?math:mod(U2*U2, ?p), XN = ?math:mod((4*V*(U2 - 1)), ?p), XD = ?inv((U4 - (2*U2) + (4*V2) + 1)), X = ?math:mod(XN*XD, ?p), jose_jwa_ed448:encode_point({X, Y, 1}). vrecover(U) -> Y = ?math:mod(((1 + U) * ?inv(1 - U)), ?p), X = xrecover(Y), UX = (U * ?inv(X)) rem ?p, V = (?A2sqrt * UX) rem ?p, case V rem 2 of 0 -> V; _ -> ?p - V end. xrecover(Y) -> YY = Y * Y, U = (YY - 1) rem ?p, V = ((?d * YY) - 1) rem ?p, A = (U * ?inv(V)) rem ?p, X = ?math:expmod(A, (?p + 1) div 4, ?p), case ((X * X) - A) rem ?p =:= 0 of true -> % x^2 = a (mod p). Then x is a square root. case X rem 2 of 0 -> X; _ -> ?p - X end; false -> % a is not a square modulo p. erlang:error(badarg) end. curve448(N, Base) -> One = {Base, 1}, Two = montgomery_double(One), % f(m) evaluates to a tuple containing the mth multiple and the % (m+1)th multiple of base. F = fun F(1) -> {One, Two}; F(M) when (M band 1) =:= 1 -> {Pm, Pm1} = F(M div 2), {montgomery_add(Pm, Pm1, One), montgomery_double(Pm1)}; F(M) -> {Pm, Pm1} = F(M div 2), {montgomery_double(Pm), montgomery_add(Pm, Pm1, One)} end, {{X, Z}, _} = F(N), (X * ?inv(Z)) rem ?p. % 5. The X25519 and X448 functions - https://tools.ietf.org/html/rfc7748#section-5 clamp_scalar(K0) when is_integer(K0) -> K1 = K0 band (bnot 3), K2 = K1 bor (128 bsl (?b - 8)), K2. decode_scalar(<< K0:8/integer, KBody:(?b - 16)/bitstring, K55:8/integer >>) -> << K:?b/unsigned-little-integer-unit:1 >> = << (K0 band 252):8/integer, KBody/bitstring, (K55 bor 128):8/integer >>, K. montgomery_add({Xn, Zn}, {Xm, Zm}, {Xd, Zd}) -> Z0 = (Xm * Xn) - (Zm * Zn), Z1 = (Xm * Zn) - (Zm * Xn), X = 4 * Z0 * Z0 * Zd, Z = 4 * Z1 * Z1 * Xd, {X rem ?p, Z rem ?p}. montgomery_double({Xn, Zn}) -> Xn2 = Xn * Xn, Zn2 = Zn * Zn, X = (Xn2 - Zn2), X2 = X * X, Z = 4 * Xn * Zn * (Xn2 + (?A * Xn * Zn) + Zn2), {X2 rem ?p, Z rem ?p}. scalarmult(<< Kb:?b/unsigned-little-integer-unit:1 >>, << U:?b/unsigned-little-integer-unit:1 >>) -> K = clamp_scalar(Kb), R = curve448(K, U), << R:?b/unsigned-little-integer-unit:1 >>. scalarmult_base(<< Kb:?b/unsigned-little-integer-unit:1 >>) -> K = clamp_scalar(Kb), R = curve448(K, ?u), << R:?b/unsigned-little-integer-unit:1 >>. x448(SK = << _:?secretkeybytes/binary >>, PK = << _:?publickeybytes/binary >>) -> scalarmult(SK, PK). x448_base(SK = << _:?secretkeybytes/binary >>) -> scalarmult_base(SK). keypair() -> keypair(crypto:strong_rand_bytes(?secretkeybytes)). keypair(SK = << _:?secretkeybytes/binary >>) -> PK = sk_to_pk(SK), {PK, SK}. sk_to_pk(SK = << _:?secretkeybytes/binary >>) -> x448_base(SK). erlang-jose-1.10.1/src/jwa/jose_jwa.erl0000644000232200023220000003204413605433351020231 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 21 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa). -include_lib("public_key/include/public_key.hrl"). %% Crypto API -export([block_decrypt/3]). -export([block_encrypt/3]). -export([block_decrypt/4]). -export([block_encrypt/4]). %% Public Key API -export([decrypt_private/3]). -export([encrypt_public/3]). -export([sign/4]). -export([verify/5]). %% API -export([block_cipher/1]). -export([crypto_ciphers/0]). -export([crypto_fallback/0]). -export([crypto_fallback/1]). -export([crypto_supports/0]). -export([constant_time_compare/2]). -export([ec_key_mode/0]). -export([is_block_cipher_supported/1]). -export([is_chacha20_poly1305_supported/0]). -export([is_rsa_crypt_supported/1]). -export([is_rsa_sign_supported/1]). -export([is_xchacha20_poly1305_supported/0]). -export([supports/0]). -export([unsecured_signing/0]). -export([unsecured_signing/1]). -define(TAB, ?MODULE). -define(MAYBE_START_JOSE(F), try F catch _:_ -> _ = jose:start(), F end). %%==================================================================== %% Crypto API functions %%==================================================================== block_decrypt(Cipher, Key, CipherText) when is_binary(CipherText) -> case block_cipher(Cipher) of {crypto, aes_ecb} -> << << (crypto:block_decrypt(aes_ecb, Key, Block))/binary >> || << Block:128/bitstring >> <= CipherText >>; {Module, BlockCipher} -> Module:block_decrypt(BlockCipher, Key, CipherText) end. block_encrypt(Cipher, Key, PlainText) when is_binary(PlainText) -> case block_cipher(Cipher) of {crypto, aes_ecb} -> << << (crypto:block_encrypt(aes_ecb, Key, Block))/binary >> || << Block:128/bitstring >> <= PlainText >>; {Module, BlockCipher} -> Module:block_encrypt(BlockCipher, Key, PlainText) end. block_decrypt(Cipher, Key, IV, CipherText) when is_binary(CipherText) -> {Module, BlockCipher} = block_cipher(Cipher), Module:block_decrypt(BlockCipher, Key, IV, CipherText); block_decrypt(Cipher, Key, IV, {AAD, CipherText, CipherTag}) when is_binary(AAD) andalso is_binary(CipherText) andalso is_binary(CipherTag) -> {Module, BlockCipher} = block_cipher(Cipher), Module:block_decrypt(BlockCipher, Key, IV, {AAD, CipherText, CipherTag}). block_encrypt(Cipher, Key, IV, PlainText) when is_binary(PlainText) -> {Module, BlockCipher} = block_cipher(Cipher), Module:block_encrypt(BlockCipher, Key, IV, PlainText); block_encrypt(Cipher, Key, IV, {AAD, PlainText}) when is_binary(AAD) andalso is_binary(PlainText) -> {Module, BlockCipher} = block_cipher(Cipher), Module:block_encrypt(BlockCipher, Key, IV, {AAD, PlainText}). %%==================================================================== %% Public Key API functions %%==================================================================== decrypt_private(CipherText, RSAPrivateKey=#'RSAPrivateKey'{}, Algorithm) when is_atom(Algorithm) -> {Module, Options} = rsa_crypt(Algorithm), Module:decrypt_private(CipherText, RSAPrivateKey, Options); decrypt_private(CipherText, PrivateKey, Options) -> public_key:decrypt_private(CipherText, PrivateKey, Options). encrypt_public(PlainText, RSAPublicKey=#'RSAPublicKey'{}, Algorithm) when is_atom(Algorithm) -> {Module, Options} = rsa_crypt(Algorithm), Module:encrypt_public(PlainText, RSAPublicKey, Options); encrypt_public(PlainText, PublicKey, Options) -> public_key:encrypt_public(PlainText, PublicKey, Options). sign(Message, DigestType, RSAPrivateKey=#'RSAPrivateKey'{}, Padding) when is_atom(Padding) -> case rsa_sign(Padding) of {Module, undefined} -> Module:sign(Message, DigestType, RSAPrivateKey); {Module, Options} -> Module:sign(Message, DigestType, RSAPrivateKey, Options) end; sign(Message, DigestType, PrivateKey, _Options) -> public_key:sign(Message, DigestType, PrivateKey). verify(Message, DigestType, Signature, RSAPublicKey=#'RSAPublicKey'{}, Padding) when is_atom(Padding) -> case rsa_sign(Padding) of {Module, undefined} -> Module:verify(Message, DigestType, Signature, RSAPublicKey); {Module, Options} -> Module:verify(Message, DigestType, Signature, RSAPublicKey, Options) end; verify(Message, DigestType, Signature, PublicKey, _Options) -> public_key:verify(Message, DigestType, Signature, PublicKey). %%==================================================================== %% API functions %%==================================================================== block_cipher(Cipher) -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, {cipher, Cipher}, 2)). crypto_ciphers() -> ?MAYBE_START_JOSE(ets:select(?TAB, [{ {{cipher, '$1'}, {'$2', '_'}}, [{'=/=', '$2', 'jose_jwa_unsupported'}], [{{'$1', '$2'}}] }])). crypto_fallback() -> application:get_env(jose, crypto_fallback, false). crypto_fallback(Boolean) when is_boolean(Boolean) -> application:set_env(jose, crypto_fallback, Boolean), ?MAYBE_START_JOSE(jose_server:config_change()). crypto_supports() -> Ciphers = ?MAYBE_START_JOSE(ets:select(?TAB, [{ {{cipher, '$1'}, {'$2', '_'}}, [{'=/=', '$2', 'jose_jwa_unsupported'}], ['$1'] }])), RSACrypt = ?MAYBE_START_JOSE(ets:select(?TAB, [{ {{rsa_crypt, '$1'}, {'$2', '_'}}, [{'=/=', '$2', 'jose_jwa_unsupported'}], ['$1'] }])), RSASign = ?MAYBE_START_JOSE(ets:select(?TAB, [{ {{rsa_sign, '$1'}, {'$2', '_'}}, [{'=/=', '$2', 'jose_jwa_unsupported'}], ['$1'] }])), ExternalHashs = external_checks([ {poly1305, fun() -> jose_chacha20_poly1305:authenticate(<<>>, <<0:256>>, <<0:96>>) end}, {shake256, fun() -> jose_sha3:shake256(<<>>, 0) end} ]), ExternalPublicKeys = external_checks([ {ed25519, fun jose_curve25519:eddsa_keypair/0}, {ed25519ph, fun jose_curve25519:eddsa_keypair/0}, {ed448, fun jose_curve448:eddsa_keypair/0}, {ed448ph, fun jose_curve448:eddsa_keypair/0}, {x25519, fun jose_curve25519:x25519_keypair/0}, {x448, fun jose_curve448:x448_keypair/0} ]), Supports = crypto:supports(), RecommendedHashs = [md5, poly1305, sha, sha256, sha384, sha512, shake256], Hashs = RecommendedHashs -- ((RecommendedHashs -- proplists:get_value(hashs, Supports)) -- ExternalHashs), RecommendedPublicKeys = [ec_gf2m, ecdh, ecdsa, ed25519, ed25519ph, ed448, ed448ph, rsa, x25519, x448], PublicKeys = RecommendedPublicKeys -- ((RecommendedPublicKeys -- proplists:get_value(public_keys, Supports)) -- ExternalPublicKeys), [ {ciphers, Ciphers}, {hashs, Hashs}, {public_keys, PublicKeys}, {rsa_crypt, RSACrypt}, {rsa_sign, RSASign} ]. constant_time_compare(<<>>, _) -> false; constant_time_compare(_, <<>>) -> false; constant_time_compare(A, B) when is_binary(A) andalso is_binary(B) andalso (byte_size(A) =/= byte_size(B)) -> false; constant_time_compare(A, B) when is_binary(A) andalso is_binary(B) andalso (byte_size(A) =:= byte_size(B)) -> constant_time_compare(A, B, 0). ec_key_mode() -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, ec_key_mode, 2)). is_block_cipher_supported(Cipher) -> case catch block_cipher(Cipher) of {crypto, _} -> true; _ -> false end. is_chacha20_poly1305_supported() -> case catch ?MAYBE_START_JOSE(ets:lookup_element(?TAB, chacha20_poly1305_module, 2)) of jose_chacha20_poly1305_unsupported -> false; _ -> true end. is_rsa_crypt_supported(Padding) -> case catch rsa_crypt(Padding) of {public_key, _} -> true; _ -> false end. is_rsa_sign_supported(Padding) -> case catch rsa_sign(Padding) of {public_key, _} -> true; _ -> false end. is_xchacha20_poly1305_supported() -> case catch ?MAYBE_START_JOSE(ets:lookup_element(?TAB, xchacha20_poly1305_module, 2)) of jose_xchacha20_poly1305_unsupported -> false; _ -> true end. supports() -> Supports = crypto_supports(), JWEALG = support_check([ {<<"A128GCMKW">>, ciphers, {aes_gcm, 128}}, {<<"A192GCMKW">>, ciphers, {aes_gcm, 192}}, {<<"A256GCMKW">>, ciphers, {aes_gcm, 256}}, {<<"A128KW">>, ciphers, {aes_ecb, 128}}, {<<"A192KW">>, ciphers, {aes_ecb, 192}}, {<<"A256KW">>, ciphers, {aes_ecb, 256}}, {<<"C20PKW">>, ciphers, {chacha20_poly1305, 256}}, <<"ECDH-1PU">>, {<<"ECDH-1PU+A128GCMKW">>, ciphers, {aes_gcm, 128}}, {<<"ECDH-1PU+A192GCMKW">>, ciphers, {aes_gcm, 192}}, {<<"ECDH-1PU+A256GCMKW">>, ciphers, {aes_gcm, 256}}, <<"ECDH-1PU+A128KW">>, <<"ECDH-1PU+A192KW">>, <<"ECDH-1PU+A256KW">>, {<<"ECDH-1PU+C20PKW">>, ciphers, {chacha20_poly1305, 256}}, {<<"ECDH-1PU+XC20PKW">>, ciphers, {xchacha20_poly1305, 256}}, <<"ECDH-ES">>, {<<"ECDH-ES+A128GCMKW">>, ciphers, {aes_gcm, 128}}, {<<"ECDH-ES+A192GCMKW">>, ciphers, {aes_gcm, 192}}, {<<"ECDH-ES+A256GCMKW">>, ciphers, {aes_gcm, 256}}, <<"ECDH-ES+A128KW">>, <<"ECDH-ES+A192KW">>, <<"ECDH-ES+A256KW">>, {<<"ECDH-ES+C20PKW">>, ciphers, {chacha20_poly1305, 256}}, {<<"ECDH-ES+XC20PKW">>, ciphers, {xchacha20_poly1305, 256}}, {<<"PBES2-HS256+A128GCMKW">>, ciphers, {aes_gcm, 128}}, {<<"PBES2-HS384+A192GCMKW">>, ciphers, {aes_gcm, 192}}, {<<"PBES2-HS512+A256GCMKW">>, ciphers, {aes_gcm, 256}}, {<<"PBES2-HS256+A128KW">>, ciphers, {aes_ecb, 128}}, {<<"PBES2-HS384+A192KW">>, ciphers, {aes_ecb, 192}}, {<<"PBES2-HS512+A256KW">>, ciphers, {aes_ecb, 256}}, {<<"PBES2-HS512+C20PKW">>, ciphers, {chacha20_poly1305, 256}}, {<<"PBES2-HS512+XC20PKW">>, ciphers, {xchacha20_poly1305, 256}}, {<<"RSA1_5">>, rsa_crypt, rsa1_5}, {<<"RSA-OAEP">>, rsa_crypt, rsa_oaep}, {<<"RSA-OAEP-256">>, rsa_crypt, rsa_oaep_256}, {<<"XC20PKW">>, ciphers, {xchacha20_poly1305, 256}}, <<"dir">> ], Supports, []), JWEENC = support_check([ {<<"A128CBC-HS256">>, ciphers, {aes_cbc, 128}}, {<<"A192CBC-HS384">>, ciphers, {aes_cbc, 192}}, {<<"A256CBC-HS512">>, ciphers, {aes_cbc, 256}}, {<<"A128GCM">>, ciphers, {aes_gcm, 128}}, {<<"A192GCM">>, ciphers, {aes_gcm, 192}}, {<<"A256GCM">>, ciphers, {aes_gcm, 256}}, {<<"C20P">>, ciphers, {chacha20_poly1305, 256}}, {<<"XC20P">>, ciphers, {xchacha20_poly1305, 256}} ], Supports, []), JWEZIP = support_check([ <<"DEF">> ], Supports, []), JWKKTY = support_check([ <<"EC">>, <<"oct">>, <<"OKP">>, <<"RSA">> ], Supports, []), JWKKTYOKPcrv = support_check([ {<<"Ed25519">>, public_keys, ed25519}, {<<"Ed25519ph">>, public_keys, ed25519ph}, {<<"Ed448">>, public_keys, ed448}, {<<"Ed448ph">>, public_keys, ed448ph}, {<<"X25519">>, public_keys, x25519}, {<<"X448">>, public_keys, x448} ], Supports, []), JWSALG = support_check([ {<<"Ed25519">>, public_keys, ed25519}, {<<"Ed25519ph">>, public_keys, ed25519ph}, {<<"Ed448">>, public_keys, ed448}, {<<"Ed448ph">>, public_keys, ed448ph}, {<<"ES256">>, public_keys, ecdsa}, {<<"ES384">>, public_keys, ecdsa}, {<<"ES512">>, public_keys, ecdsa}, <<"HS256">>, <<"HS384">>, <<"HS512">>, {<<"PS256">>, rsa_sign, rsa_pkcs1_pss_padding}, {<<"PS384">>, rsa_sign, rsa_pkcs1_pss_padding}, {<<"PS512">>, rsa_sign, rsa_pkcs1_pss_padding}, {<<"Poly1305">>, hashs, poly1305}, {<<"RS256">>, rsa_sign, rsa_pkcs1_padding}, {<<"RS384">>, rsa_sign, rsa_pkcs1_padding}, {<<"RS512">>, rsa_sign, rsa_pkcs1_padding}, {<<"none">>, fun unsecured_signing/0} ], Supports, []), [ {jwe, {alg, JWEALG}, {enc, JWEENC}, {zip, JWEZIP}}, {jwk, {kty, JWKKTY}, {kty_OKP_crv, JWKKTYOKPcrv}}, {jws, {alg, JWSALG}} ]. unsecured_signing() -> application:get_env(jose, unsecured_signing, false). unsecured_signing(Boolean) when is_boolean(Boolean) -> application:set_env(jose, unsecured_signing, Boolean), ?MAYBE_START_JOSE(jose_server:config_change()). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private constant_time_compare(<< AH, AT/binary >>, << BH, BT/binary >>, R) -> constant_time_compare(AT, BT, R bor (BH bxor AH)); constant_time_compare(<<>>, <<>>, R) -> R =:= 0. %% @private external_checks(Checks) -> external_checks(Checks, []). %% @private external_checks([{Key, Check} | Checks], Acc) -> try Check(), external_checks(Checks, [Key | Acc]) catch _:_ -> external_checks(Checks, Acc) end; external_checks([], Acc) -> lists:reverse(Acc). %% @private rsa_crypt(Algorithm) -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, {rsa_crypt, Algorithm}, 2)). %% @private rsa_sign(Padding) -> ?MAYBE_START_JOSE(ets:lookup_element(?TAB, {rsa_sign, Padding}, 2)). %% @private support_check([], _Supports, Acc) -> lists:usort(Acc); support_check([{ALG, Key, Val} | Rest], Supports, Acc) -> case lists:member(Val, proplists:get_value(Key, Supports)) of false -> support_check(Rest, Supports, Acc); true -> support_check(Rest, Supports, [ALG | Acc]) end; support_check([{ALG, Check} | Rest], Supports, Acc) when is_function(Check, 0) -> case Check() of false -> support_check(Rest, Supports, Acc); true -> support_check(Rest, Supports, [ALG | Acc]) end; support_check([ALG | Rest], Supports, Acc) when is_binary(ALG) -> support_check(Rest, Supports, [ALG | Acc]). erlang-jose-1.10.1/src/jwa/jose_jwa_pkcs7.erl0000644000232200023220000000577413605433351021352 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc PKCS-7 %%% See RFC 2315: https://tools.ietf.org/html/rfc2315 %%% @end %%% Created : 22 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_pkcs7). %% API -export([pad/1]). -export([unpad/1]). %%==================================================================== %% API functions %%==================================================================== -spec pad(binary()) -> binary(). pad(Bin) -> Size = 16 - (byte_size(Bin) rem 16), pad(Size, Bin). -spec unpad(binary()) -> binary(). unpad(Data) -> P = binary:last(Data), Size = byte_size(Data) - P, case Data of << Bin:Size/binary, P >> -> Bin; << Bin:Size/binary, P, P >> -> Bin; << Bin:Size/binary, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P >> -> Bin; << Bin:Size/binary, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P >> -> Bin; _ -> erlang:error({badarg, Data}) end. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private pad(P= 1, Bin) -> << Bin/binary, P >>; pad(P= 2, Bin) -> << Bin/binary, P, P >>; pad(P= 3, Bin) -> << Bin/binary, P, P, P >>; pad(P= 4, Bin) -> << Bin/binary, P, P, P, P >>; pad(P= 5, Bin) -> << Bin/binary, P, P, P, P, P >>; pad(P= 6, Bin) -> << Bin/binary, P, P, P, P, P, P >>; pad(P= 7, Bin) -> << Bin/binary, P, P, P, P, P, P, P >>; pad(P= 8, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P >>; pad(P= 9, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P, P >>; pad(P=10, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P, P, P >>; pad(P=11, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P, P, P, P >>; pad(P=12, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P, P, P, P, P >>; pad(P=13, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P, P, P, P, P, P >>; pad(P=14, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P, P, P, P, P, P, P >>; pad(P=15, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P >>; pad(P=16, Bin) -> << Bin/binary, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P >>. erlang-jose-1.10.1/src/jwa/jose_jwa_math.erl0000644000232200023220000000451013605433351021237 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 06 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_math). %% Public API -export([expmod/3]). -export([exprem/3]). -export([intpow/2]). -export([mod/2]). -export([mod_pow/3]). %% Private API -export([expmod_fast/3]). -export([expmod_slow/3]). -export([exprem_fast/3]). -export([exprem_slow/3]). %%==================================================================== %% Public API %%==================================================================== expmod(B, E, M) -> expmod_fast(B, E, M). exprem(B, E, M) -> exprem_fast(B, E, M). intpow(B, E) when is_integer(B) andalso is_integer(E) andalso E >= 0 -> case B of 0 -> 0; 1 -> 1; 2 -> 1 bsl E; _ -> intpow(B, E, 1) end. mod(B, M) -> (B rem M + M) rem M. mod_pow(B, E, M) -> Bytes = crypto:mod_pow(B, E, M), Size = byte_size(Bytes), << ((crypto:bytes_to_integer(Bytes) + M) rem M):Size/signed-big-integer-unit:8 >>. %%==================================================================== %% Private API %%==================================================================== % @private expmod_fast(B, E, M) -> (exprem_fast(B, E, M) + M) rem M. % @private expmod_slow(B, E, M) -> (exprem_slow(B, E, M) + M) rem M. % @private exprem_fast(B, E, M) when B < 0 andalso E rem 2 =/= 0 -> -exprem_fast(abs(B), E, M); exprem_fast(B, E, M) when B < 0 -> exprem_fast(abs(B), E, M); exprem_fast(B, E, M) -> crypto:bytes_to_integer(crypto:mod_pow(B, E, M)). %% @private exprem_slow(_B, 0, _M) -> 1; exprem_slow(B, E, M) -> T0 = exprem_slow(B, E div 2, M), T = (T0 * T0) rem M, case E rem 2 of 0 -> T band M; _ -> (T * B) rem M end. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private intpow(B, E, R) when (E rem 2) =:= 0 -> intpow(B * B, E div 2, R); intpow(B, E, R) when (E div 2) =:= 0 -> B * R; intpow(B, E, R) -> intpow(B * B, E div 2, B * R). erlang-jose-1.10.1/src/jwa/jose_jwa_concat_kdf.erl0000644000232200023220000001101313605433351022375 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc Concat KDF, as defined in Section 5.8.1 of NIST.800-56A %%% See NIST.800-56A: https://dx.doi.org/10.6028/NIST.SP.800-56Ar2 %%% @end %%% Created : 24 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_concat_kdf). %% API -export([kdf/3]). -export([kdf/4]). %%==================================================================== %% API functions %%==================================================================== kdf(Hash, Z, OtherInfo) -> HashFun = resolve_hash(Hash), KeyDataLen = bit_size(HashFun(<<>>)), kdf(HashFun, Z, OtherInfo, KeyDataLen). kdf(Hash, Z, OtherInfo, KeyDataLen) when is_function(Hash) andalso is_binary(Z) andalso is_binary(OtherInfo) andalso is_integer(KeyDataLen) -> HashLen = bit_size(Hash(<<>>)), Reps = ceiling(KeyDataLen / HashLen), case Reps of 1 -> Concatenation = << 0, 0, 0, 1, Z/binary, OtherInfo/binary >>, << DerivedKey:KeyDataLen/bitstring, _/bitstring >> = Hash(Concatenation), DerivedKey; _ when Reps > 16#FFFFFFFF -> erlang:error({badarg, [Hash, Z, OtherInfo, KeyDataLen]}); _ -> derive_key(Hash, 1, Reps, KeyDataLen, << Z/binary, OtherInfo/binary >>, <<>>) end; kdf(Hash, Z, OtherInfo, KeyDataLen) when is_tuple(Hash) orelse is_atom(Hash) -> kdf(resolve_hash(Hash), Z, OtherInfo, KeyDataLen); kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo}, KeyDataLen) -> kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo, <<>>}, KeyDataLen); kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo, SuppPubInfo}, KeyDataLen) -> kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo, SuppPubInfo, <<>>}, KeyDataLen); kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo, SuppPubInfo, SuppPrivInfo}, KeyDataLen) when is_binary(AlgorithmID) andalso is_binary(PartyUInfo) andalso is_binary(PartyVInfo) andalso is_binary(SuppPubInfo) andalso is_binary(SuppPrivInfo) -> kdf(Hash, Z, << (byte_size(AlgorithmID)):1/unsigned-big-integer-unit:32, AlgorithmID/binary, (byte_size(PartyUInfo)):1/unsigned-big-integer-unit:32, PartyUInfo/binary, (byte_size(PartyVInfo)):1/unsigned-big-integer-unit:32, PartyVInfo/binary, SuppPubInfo/binary, SuppPrivInfo/binary >>, KeyDataLen); kdf(Hash, Z, {undefined, PartyUInfo, PartyVInfo, SuppPubInfo, SuppPrivInfo}, KeyDataLen) -> kdf(Hash, Z, {<<>>, PartyUInfo, PartyVInfo, SuppPubInfo, SuppPrivInfo}, KeyDataLen); kdf(Hash, Z, {AlgorithmID, undefined, PartyVInfo, SuppPubInfo, SuppPrivInfo}, KeyDataLen) -> kdf(Hash, Z, {AlgorithmID, <<>>, PartyVInfo, SuppPubInfo, SuppPrivInfo}, KeyDataLen); kdf(Hash, Z, {AlgorithmID, PartyUInfo, undefined, SuppPubInfo, SuppPrivInfo}, KeyDataLen) -> kdf(Hash, Z, {AlgorithmID, PartyUInfo, <<>>, SuppPubInfo, SuppPrivInfo}, KeyDataLen); kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo, undefined, SuppPrivInfo}, KeyDataLen) -> kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo, <<>>, SuppPrivInfo}, KeyDataLen); kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo, SuppPubInfo, undefined}, KeyDataLen) -> kdf(Hash, Z, {AlgorithmID, PartyUInfo, PartyVInfo, SuppPubInfo, <<>>}, KeyDataLen). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private ceiling(X) when X < 0 -> trunc(X); ceiling(X) -> T = trunc(X), case X - T == 0 of false -> T + 1; true -> T end. %% @private derive_key(Hash, Reps, Reps, KeyDataLen, ZOtherInfo, DerivedKeyingMaterial) -> Concatenation = << Reps:1/unsigned-big-integer-unit:32, ZOtherInfo/binary >>, << DerivedKey:KeyDataLen/bitstring, _/bitstring >> = << DerivedKeyingMaterial/binary, (Hash(Concatenation))/binary >>, DerivedKey; derive_key(Hash, Counter, Reps, KeyDataLen, ZOtherInfo, DerivedKeyingMaterial) -> Concatenation = << Counter:1/unsigned-big-integer-unit:32, ZOtherInfo/binary >>, derive_key(Hash, Counter + 1, Reps, KeyDataLen, ZOtherInfo, << DerivedKeyingMaterial/binary, (Hash(Concatenation))/binary >>). %% @private resolve_hash(HashFun) when is_function(HashFun) -> HashFun; resolve_hash(DigestType) when is_atom(DigestType) -> fun(Data) -> crypto:hash(DigestType, Data) end; resolve_hash({hmac, DigestType, Key}) when is_atom(DigestType) -> fun(Data) -> crypto:hmac(DigestType, Key, Data) end. erlang-jose-1.10.1/src/jwa/jose_jwa_chacha20.erl0000644000232200023220000001135113605433351021660 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc ChaCha20 and Poly1305 for IETF Protocols %%% See https://tools.ietf.org/html/rfc7539 %%% @end %%% Created : 31 May 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_chacha20). %% API -export([quarter_round/1]). -export([column_round/1]). -export([diagonal_round/1]). -export([block/3]). -export([encrypt/4]). %% Macros -define(math, jose_jwa_math). -define(p, 16#100000000). -define(rotl(X, R), ?math:mod((X bsl R) bor (X bsr (32 - R)), ?p)). %%==================================================================== %% API functions %%==================================================================== quarter_round({A0, B0, C0, D0}) -> A1 = ?math:mod(A0 + B0, ?p), D1 = ?rotl(D0 bxor A1, 16), C1 = ?math:mod(C0 + D1, ?p), B1 = ?rotl(B0 bxor C1, 12), A = ?math:mod(A1 + B1, ?p), D = ?rotl(D1 bxor A, 8), C = ?math:mod(C1 + D, ?p), B = ?rotl(B1 bxor C, 7), {A, B, C, D}. column_round({X00, X01, X02, X03, X04, X05, X06, X07, X08, X09, X10, X11, X12, X13, X14, X15}) -> {Y00, Y04, Y08, Y12} = quarter_round({X00, X04, X08, X12}), {Y01, Y05, Y09, Y13} = quarter_round({X01, X05, X09, X13}), {Y02, Y06, Y10, Y14} = quarter_round({X02, X06, X10, X14}), {Y03, Y07, Y11, Y15} = quarter_round({X03, X07, X11, X15}), {Y00, Y01, Y02, Y03, Y04, Y05, Y06, Y07, Y08, Y09, Y10, Y11, Y12, Y13, Y14, Y15}. diagonal_round({Y00, Y01, Y02, Y03, Y04, Y05, Y06, Y07, Y08, Y09, Y10, Y11, Y12, Y13, Y14, Y15}) -> {Z00, Z05, Z10, Z15} = quarter_round({Y00, Y05, Y10, Y15}), {Z01, Z06, Z11, Z12} = quarter_round({Y01, Y06, Y11, Y12}), {Z02, Z07, Z08, Z13} = quarter_round({Y02, Y07, Y08, Y13}), {Z03, Z04, Z09, Z14} = quarter_round({Y03, Y04, Y09, Y14}), {Z00, Z01, Z02, Z03, Z04, Z05, Z06, Z07, Z08, Z09, Z10, Z11, Z12, Z13, Z14, Z15}. block(Key, Counter, Nonce) when is_binary(Key) andalso bit_size(Key) =:= 256 andalso is_integer(Counter) andalso Counter >= 0 andalso is_binary(Nonce) andalso bit_size(Nonce) =:= 96 -> State = << "expand 32-byte k", Key:256/bitstring, Counter:32/unsigned-little-integer-unit:1, Nonce:96/bitstring >>, WS0 = list_to_tuple([Word || << Word:32/unsigned-little-integer-unit:1 >> <= State]), WS1 = rounds(WS0, 10), WS2 = add(WS1, WS0), serialize(WS2). encrypt(Key, Counter, Nonce, Plaintext) -> encrypt(Key, Counter, Nonce, Plaintext, 0, <<>>). encrypt(_Key, _Counter, _Nonce, <<>>, _J, EncryptedMessage) -> EncryptedMessage; encrypt(Key, Counter, Nonce, << Block:64/binary, Rest/binary >>, J, EncryptedMessage) -> KeyStream = block(Key, Counter + J, Nonce), encrypt(Key, Counter, Nonce, Rest, J + 1, << EncryptedMessage/binary, (crypto:exor(Block, KeyStream))/binary >>); encrypt(Key, Counter, Nonce, Block, J, EncryptedMessage) -> BlockBytes = byte_size(Block), << KeyStream:BlockBytes/binary, _/binary >> = block(Key, Counter + J, Nonce), << EncryptedMessage/binary, (crypto:exor(Block, KeyStream))/binary >>. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private inner_block(State0) when is_tuple(State0) andalso tuple_size(State0) =:= 16 -> State1 = column_round(State0), State2 = diagonal_round(State1), State2. %% @private rounds(S, 0) -> S; rounds(S, N) when is_integer(N) andalso N > 0 -> rounds(inner_block(S), N - 1). %% @private add({X00, X01, X02, X03, X04, X05, X06, X07, X08, X09, X10, X11, X12, X13, X14, X15}, {Y00, Y01, Y02, Y03, Y04, Y05, Y06, Y07, Y08, Y09, Y10, Y11, Y12, Y13, Y14, Y15}) -> {X00 + Y00, X01 + Y01, X02 + Y02, X03 + Y03, X04 + Y04, X05 + Y05, X06 + Y06, X07 + Y07, X08 + Y08, X09 + Y09, X10 + Y10, X11 + Y11, X12 + Y12, X13 + Y13, X14 + Y14, X15 + Y15}. %% @private serialize({Z00, Z01, Z02, Z03, Z04, Z05, Z06, Z07, Z08, Z09, Z10, Z11, Z12, Z13, Z14, Z15}) -> << Z00:32/unsigned-little-integer-unit:1, Z01:32/unsigned-little-integer-unit:1, Z02:32/unsigned-little-integer-unit:1, Z03:32/unsigned-little-integer-unit:1, Z04:32/unsigned-little-integer-unit:1, Z05:32/unsigned-little-integer-unit:1, Z06:32/unsigned-little-integer-unit:1, Z07:32/unsigned-little-integer-unit:1, Z08:32/unsigned-little-integer-unit:1, Z09:32/unsigned-little-integer-unit:1, Z10:32/unsigned-little-integer-unit:1, Z11:32/unsigned-little-integer-unit:1, Z12:32/unsigned-little-integer-unit:1, Z13:32/unsigned-little-integer-unit:1, Z14:32/unsigned-little-integer-unit:1, Z15:32/unsigned-little-integer-unit:1 >>. erlang-jose-1.10.1/src/jwa/jose_jwa_poly1305.erl0000644000232200023220000000513513605433351021606 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc ChaCha20 and Poly1305 for IETF Protocols %%% See https://tools.ietf.org/html/rfc7539 %%% @end %%% Created : 31 May 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_poly1305). %% API -export([mac/2]). -export([mac_init/1]). -export([mac_update/2]). -export([mac_final/1]). %% Macros -define(math, jose_jwa_math). -define(clamp(R), R band 16#0ffffffc0ffffffc0ffffffc0fffffff). -define(p, 16#3fffffffffffffffffffffffffffffffb). %%==================================================================== %% API functions %%==================================================================== mac(M, K) when is_binary(M) andalso is_binary(K) andalso bit_size(K) =:= 256 -> mac_final(mac_update(mac_init(K), M)). mac_init(<< R:128/unsigned-little-integer-unit:1, S:128/unsigned-little-integer-unit:1 >>) -> A = 0, << (?clamp(R)):128/unsigned-little-integer-unit:1, A:136/unsigned-little-integer-unit:1, S:128/unsigned-little-integer-unit:1, 0:1656 >>. mac_update(C = << _:392, 0:1656 >>, <<>>) -> C; mac_update(<< R:128/unsigned-little-integer-unit:1, A:136/unsigned-little-integer-unit:1, S:128/unsigned-little-integer-unit:1, 0:1656 >>, << Block:128/bitstring, Rest/binary >>) -> << B:136/unsigned-little-integer-unit:1 >> = << Block:128/bitstring, 1:8/unsigned-little-integer-unit:1 >>, mac_update(<< R:128/unsigned-little-integer-unit:1, (?math:mod((A + B) * R, ?p)):136/unsigned-little-integer-unit:1, S:128/unsigned-little-integer-unit:1, 0:1656 >>, Rest); mac_update(<< R:128/unsigned-little-integer-unit:1, A:136/unsigned-little-integer-unit:1, S:128/unsigned-little-integer-unit:1, 0:1656 >>, << Block/binary >>) -> BlockBits = bit_size(Block), PadBits = 136 - BlockBits - 8, << B:136/unsigned-little-integer-unit:1 >> = << Block/binary, 1:8/unsigned-little-integer-unit:1, 0:PadBits/unsigned-little-integer-unit:1 >>, << R:128/unsigned-little-integer-unit:1, (?math:mod((A + B) * R, ?p)):136/unsigned-little-integer-unit:1, S:128/unsigned-little-integer-unit:1, 0:1656 >>. mac_final(<< _R:128/unsigned-little-integer-unit:1, A:136/unsigned-little-integer-unit:1, S:128/unsigned-little-integer-unit:1, 0:1656 >>) -> << (A + S):128/unsigned-little-integer-unit:1 >>. erlang-jose-1.10.1/src/jwa/jose_jwa_curve448.erl0000644000232200023220000000661213605433351021677 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 07 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_curve448). -behaviour(jose_curve448). %% jose_curve448 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed448_sign/2]). -export([ed448_sign/3]). -export([ed448_verify/3]). -export([ed448_verify/4]). -export([ed448ph_sign/2]). -export([ed448ph_sign/3]). -export([ed448ph_verify/3]). -export([ed448ph_verify/4]). -export([x448_keypair/0]). -export([x448_keypair/1]). -export([x448_secret_to_public/1]). -export([x448_shared_secret/2]). %%==================================================================== %% jose_curve448 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> jose_jwa_ed448:keypair(). eddsa_keypair(Seed) when is_binary(Seed) -> jose_jwa_ed448:keypair(Seed). eddsa_secret_to_public(SecretKey) when is_binary(SecretKey) -> jose_jwa_ed448:secret_to_pk(SecretKey). % Ed448 ed448_sign(Message, SecretKey) when is_binary(Message) andalso is_binary(SecretKey) -> jose_jwa_ed448:sign(Message, SecretKey). ed448_sign(Message, SecretKey, Context) when is_binary(Message) andalso is_binary(SecretKey) andalso is_binary(Context) -> jose_jwa_ed448:sign(Message, SecretKey, Context). ed448_verify(Signature, Message, PublicKey) when is_binary(Signature) andalso is_binary(Message) andalso is_binary(PublicKey) -> try jose_jwa_ed448:verify(Signature, Message, PublicKey) catch _:_ -> false end. ed448_verify(Signature, Message, PublicKey, Context) when is_binary(Signature) andalso is_binary(Message) andalso is_binary(PublicKey) andalso is_binary(Context) -> try jose_jwa_ed448:verify(Signature, Message, PublicKey, Context) catch _:_ -> false end. % Ed448ph ed448ph_sign(Message, SecretKey) when is_binary(Message) andalso is_binary(SecretKey) -> jose_jwa_ed448:sign_with_prehash(Message, SecretKey). ed448ph_sign(Message, SecretKey, Context) when is_binary(Message) andalso is_binary(SecretKey) andalso is_binary(Context) -> jose_jwa_ed448:sign_with_prehash(Message, SecretKey, Context). ed448ph_verify(Signature, Message, PublicKey) when is_binary(Signature) andalso is_binary(Message) andalso is_binary(PublicKey) -> try jose_jwa_ed448:verify_with_prehash(Signature, Message, PublicKey) catch _:_ -> false end. ed448ph_verify(Signature, Message, PublicKey, Context) when is_binary(Signature) andalso is_binary(Message) andalso is_binary(PublicKey) andalso is_binary(Context) -> try jose_jwa_ed448:verify_with_prehash(Signature, Message, PublicKey, Context) catch _:_ -> false end. % X448 x448_keypair() -> jose_jwa_x448:keypair(). x448_keypair(Seed) when is_binary(Seed) -> jose_jwa_x448:keypair(Seed). x448_secret_to_public(SecretKey) when is_binary(SecretKey) -> jose_jwa_x448:sk_to_pk(SecretKey). x448_shared_secret(MySecretKey, YourPublicKey) when is_binary(MySecretKey) andalso is_binary(YourPublicKey) -> jose_jwa_x448:x448(MySecretKey, YourPublicKey). erlang-jose-1.10.1/src/jwa/jose_jwa_base64url.erl0000644000232200023220000000154313605433351022120 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2017-2019, Andrew Bennett %%% @doc RFC 4648, Section 5: https://tools.ietf.org/html/rfc4648#section-5 %%% %%% @end %%% Created : 29 Jul 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_base64url). %% API -export([decode/1]). -export([encode/1]). %%%=================================================================== %%% API functions %%%=================================================================== decode(Input) -> jose_base64url:'decode!'(Input). encode(Input) -> jose_base64url:encode(Input, #{ padding => false }). erlang-jose-1.10.1/src/jwa/jose_jwa_sha3.erl0000644000232200023220000001752013605433351021151 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 08 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_sha3). %% API -export([rol64/2]). -export([load64/1]). -export([store64/1]). -export([keccak_f_1600/1]). -export([load_lanes/1]). -export([store_lanes/1]). -export([keccak/5]). -export([keccak_absorb/4]). -export([keccak_pad/4]). -export([shake128/2]). -export([shake256/2]). -export([sha3_224/1]). -export([sha3_256/1]). -export([sha3_384/1]). -export([sha3_512/1]). %%==================================================================== %% API functions %%==================================================================== rol64(A, N) -> ((A bsr (64 - (N rem 64))) + (A bsl (N rem 64))) rem (1 bsl 64). keccak_f_1600_on_lanes(Lanes) -> keccak_f_1600_on_lanes(Lanes, 1, 0). keccak_f_1600_on_lanes(Lanes, _R, 24) -> Lanes; keccak_f_1600_on_lanes(Lanes, R, Round) -> % θ Lanes0 = theta(Lanes), % ρ and π Lanes1 = rho_and_pi(mget(Lanes0, 1, 0), Lanes0, 1, 0, 0), % χ Lanes2 = chi(Lanes1, 0), % ι {Lanes3, Rn} = iota(Lanes2, R, 0), keccak_f_1600_on_lanes(Lanes3, Rn, Round + 1). %% @private theta(Lanes) -> C = list_to_tuple([begin E = mget(Lanes, X), mget(E, 0) bxor mget(E, 1) bxor mget(E, 2) bxor mget(E, 3) bxor mget(E, 4) end || X <- lists:seq(0, 4)]), D = list_to_tuple([begin mget(C, (X + 4) rem 5) bxor rol64(mget(C, (X + 1) rem 5), 1) end || X <- lists:seq(0, 4)]), list_to_tuple([begin list_to_tuple([begin mget(Lanes, X, Y) bxor mget(D, X) end || Y <- lists:seq(0, 4)]) end || X <- lists:seq(0, 4)]). %% @private rho_and_pi(_Current, Lanes, _X, _Y, 24) -> Lanes; rho_and_pi(Current, Lanes, X, Y, T) -> Xn = Y, Yn = ((2 * X) + (3 * Y)) rem 5, Zn = rol64(Current, ((T + 1) * (T + 2)) div 2), rho_and_pi(mget(Lanes, Xn, Yn), mput(Lanes, Xn, Yn, Zn), Xn, Yn, T + 1). %% @private chi(Lanes, 5) -> Lanes; chi(Lanes, Y) -> T = list_to_tuple([mget(Lanes, X, Y) || X <- lists:seq(0, 4)]), chi(Lanes, T, Y, 0). chi(Lanes, _T, Y, 5) -> chi(Lanes, Y + 1); chi(Lanes, T, Y, X) -> V = mget(T, X) bxor ((bnot mget(T, (X + 1) rem 5)) band mget(T, (X + 2) rem 5)), chi(mput(Lanes, X, Y, V), T, Y, X + 1). %% @private iota(Lanes, R, 7) -> {Lanes, R}; iota(Lanes, R, J) -> Rn = ((R bsl 1) bxor ((R bsr 7) * 16#71)) rem 256, case Rn band 2 of 0 -> iota(Lanes, Rn, J + 1); _ -> Right = (1 bsl ((1 bsl J) - 1)), Left = mget(Lanes, 0, 0), Down = Left bxor Right, V = Down, iota(mput(Lanes, 0, 0, V), Rn, J + 1) end. load64(<< B:64/unsigned-little-integer-unit:1 >>) -> B. store64(B) when is_integer(B) -> << B:64/unsigned-little-integer-unit:1 >>. keccak_f_1600(State) -> Lanes0 = load_lanes(State), Lanes1 = keccak_f_1600_on_lanes(Lanes0), store_lanes(Lanes1). load_lanes(State) -> load_lanes(State, 0, 0, [], []). %% @private load_lanes(_State, 5, _Y, [], Lanes) -> list_to_tuple(lists:reverse(Lanes)); load_lanes(State, X, 5, Lane, Lanes) -> load_lanes(State, X + 1, 0, [], [list_to_tuple(lists:reverse(Lane)) | Lanes]); load_lanes(State, X, Y, Lane, Lanes) -> Pos = 8 * (X + 5 * Y), Len = 8, load_lanes(State, X, Y + 1, [load64(binary:part(State, Pos, Len)) | Lane], Lanes). store_lanes(Lanes) -> store_lanes(Lanes, 0, 0, << 0:1600 >>). store_lanes(_Lanes, 5, _Y, StateBytes) -> StateBytes; store_lanes(Lanes, X, 5, StateBytes) -> store_lanes(Lanes, X + 1, 0, StateBytes); store_lanes(Lanes, X, Y, StateBytes) -> V = mget(Lanes, X, Y), Pos = 8 * (X + 5 * Y), Len = 8, << StateHead:Pos/binary, _:Len/binary, StateTail/binary >> = StateBytes, store_lanes(Lanes, X, Y + 1, << StateHead/binary, (store64(V))/binary, StateTail/binary >>). keccak(Rate, Capacity, InputBytes, DelimitedSuffix, OutputByteLen) -> case (Rate + Capacity) =/= 1600 orelse (Rate rem 8) =/= 0 of true -> erlang:error(badarg); false -> {RateInBytes, StateBytes} = keccak_absorb(Rate div 8, InputBytes, << 0:1600 >>, DelimitedSuffix), keccak_squeeze(RateInBytes, OutputByteLen, StateBytes, <<>>) end. % Absorb all the input blocks keccak_absorb(RateInBytes, InputBytes, StateBytes, DelimitedSuffix) when is_integer(RateInBytes) andalso byte_size(InputBytes) >= RateInBytes -> << InputHead:RateInBytes/binary, InputTail/binary >> = InputBytes, << StateHead:RateInBytes/binary, StateTail/binary >> = StateBytes, State = << (crypto:exor(StateHead, InputHead))/binary, StateTail/binary >>, keccak_absorb(RateInBytes, InputTail, keccak_f_1600(State), DelimitedSuffix); keccak_absorb(RateInBytes, InputBytes, StateBytes, DelimitedSuffix) -> BlockSize = byte_size(InputBytes), << StateHead:BlockSize/binary, StateTail/binary >> = StateBytes, State = << (crypto:exor(StateHead, InputBytes))/binary, StateTail/binary >>, keccak_pad(RateInBytes, BlockSize, State, DelimitedSuffix). % Do the padding and switch to the squeezing phase keccak_pad(RateInBytes, BlockSize, StateBytes, DelimitedSuffix) -> << StateHead:BlockSize/binary, S:8/integer, StateTail/binary >> = StateBytes, State0 = << StateHead/binary, (S bxor DelimitedSuffix):8/integer, StateTail/binary >>, State1 = case (DelimitedSuffix band 16#80) =/= 0 andalso BlockSize =:= (RateInBytes - 1) of false -> State0; true -> keccak_f_1600(State0) end, RateInBytesSubOne = RateInBytes - 1, << XHead:RateInBytesSubOne/binary, X:8/integer, XTail/binary >> = State1, State2 = << XHead/binary, (X bxor 16#80):8/integer, XTail/binary >>, State3 = keccak_f_1600(State2), {RateInBytes, State3}. % Squeeze out all the output blocks keccak_squeeze(RateInBytes, OutputByteLen, StateBytes, OutputBytes) when OutputByteLen > 0 -> BlockSize = min(OutputByteLen, RateInBytes), << StateBlock:BlockSize/binary, _/binary >> = StateBytes, NewOutputByteLen = OutputByteLen - BlockSize, State = case NewOutputByteLen > 0 of true -> keccak_f_1600(StateBytes); false -> StateBytes end, keccak_squeeze(RateInBytes, NewOutputByteLen, State, << OutputBytes/binary, StateBlock/binary >>); keccak_squeeze(_RateInBytes, _OutputByteLen, _StateBytes, OutputBytes) -> OutputBytes. shake128(InputBytes, OutputByteLen) when is_binary(InputBytes) andalso is_integer(OutputByteLen) andalso OutputByteLen >= 0 -> keccak(1344, 256, InputBytes, 16#1F, OutputByteLen). shake256(InputBytes, OutputByteLen) when is_binary(InputBytes) andalso is_integer(OutputByteLen) andalso OutputByteLen >= 0 -> keccak(1088, 512, InputBytes, 16#1F, OutputByteLen). sha3_224(InputBytes) -> keccak(1152, 448, InputBytes, 16#06, 224 div 8). sha3_256(InputBytes) -> keccak(1088, 512, InputBytes, 16#06, 256 div 8). sha3_384(InputBytes) -> keccak(832, 768, InputBytes, 16#06, 384 div 8). sha3_512(InputBytes) -> keccak(576, 1024, InputBytes, 16#06, 512 div 8). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private mget(M, X) -> element(X + 1, M). %% @private mget(M, X, Y) -> mget(mget(M, X), Y). %% @private mput({E0, E1, E2, E3, E4}, 0, Y, V) -> {mput(E0, Y, V), E1, E2, E3, E4}; mput({E0, E1, E2, E3, E4}, 1, Y, V) -> {E0, mput(E1, Y, V), E2, E3, E4}; mput({E0, E1, E2, E3, E4}, 2, Y, V) -> {E0, E1, mput(E2, Y, V), E3, E4}; mput({E0, E1, E2, E3, E4}, 3, Y, V) -> {E0, E1, E2, mput(E3, Y, V), E4}; mput({E0, E1, E2, E3, E4}, 4, Y, V) -> {E0, E1, E2, E3, mput(E4, Y, V)}. %% @private mput({_, V1, V2, V3, V4}, 0, V0) -> {V0, V1, V2, V3, V4}; mput({V0, _, V2, V3, V4}, 1, V1) -> {V0, V1, V2, V3, V4}; mput({V0, V1, _, V3, V4}, 2, V2) -> {V0, V1, V2, V3, V4}; mput({V0, V1, V2, _, V4}, 3, V3) -> {V0, V1, V2, V3, V4}; mput({V0, V1, V2, V3, _}, 4, V4) -> {V0, V1, V2, V3, V4}. erlang-jose-1.10.1/src/jwa/jose_jwa_unsupported.erl0000644000232200023220000000402513605433351022677 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 10 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_unsupported). -behaviour(jose_block_encryptor). %% jose_block_encryptor callbacks -export([block_decrypt/3]). -export([block_decrypt/4]). -export([block_encrypt/3]). -export([block_encrypt/4]). %% Public Key API -export([decrypt_private/3]). -export([encrypt_public/3]). -export([sign/4]). -export([verify/5]). %%==================================================================== %% jose_block_encryptor callbacks %%==================================================================== block_decrypt(Cipher, _Key, _CipherText) -> erlang:error({cipher_unsupported, [Cipher]}). block_decrypt(Cipher, _Key, _IV, _CipherText) -> erlang:error({cipher_unsupported, [Cipher]}). block_encrypt(Cipher, _Key, _PlainText) -> erlang:error({cipher_unsupported, [Cipher]}). block_encrypt(Cipher, _Key, _IV, _PlainText) -> erlang:error({cipher_unsupported, [Cipher]}). %%==================================================================== %% Public Key API functions %%==================================================================== decrypt_private(_CipherText, _PrivateKey, Options) -> erlang:error({crypt_unsupported, [Options]}). encrypt_public(_PlainText, _PublicKey, Options) -> erlang:error({crypt_unsupported, [Options]}). sign(_Message, _DigestType, _PrivateKey, Options) -> erlang:error({sign_unsupported, [Options]}). verify(_Message, _DigestType, _Signature, _PublicKey, Options) -> erlang:error({sign_unsupported, [Options]}). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwa/jose_jwa_curve25519.erl0000644000232200023220000000467013605433351022047 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 07 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_curve25519). -behaviour(jose_curve25519). %% jose_curve25519 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed25519_sign/2]). -export([ed25519_verify/3]). -export([ed25519ph_sign/2]). -export([ed25519ph_verify/3]). -export([x25519_keypair/0]). -export([x25519_keypair/1]). -export([x25519_secret_to_public/1]). -export([x25519_shared_secret/2]). %%==================================================================== %% jose_curve25519 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> jose_jwa_ed25519:keypair(). eddsa_keypair(Seed) when is_binary(Seed) -> jose_jwa_ed25519:keypair(Seed). eddsa_secret_to_public(SecretKey) when is_binary(SecretKey) -> jose_jwa_ed25519:secret_to_pk(SecretKey). % Ed25519 ed25519_sign(Message, SecretKey) when is_binary(Message) andalso is_binary(SecretKey) -> jose_jwa_ed25519:sign(Message, SecretKey). ed25519_verify(Signature, Message, PublicKey) when is_binary(Signature) andalso is_binary(Message) andalso is_binary(PublicKey) -> try jose_jwa_ed25519:verify(Signature, Message, PublicKey) catch _:_ -> false end. % Ed25519ph ed25519ph_sign(Message, SecretKey) when is_binary(Message) andalso is_binary(SecretKey) -> jose_jwa_ed25519:sign_with_prehash(Message, SecretKey). ed25519ph_verify(Signature, Message, PublicKey) when is_binary(Signature) andalso is_binary(Message) andalso is_binary(PublicKey) -> try jose_jwa_ed25519:verify_with_prehash(Signature, Message, PublicKey) catch _:_ -> false end. % X25519 x25519_keypair() -> jose_jwa_x25519:keypair(). x25519_keypair(Seed) when is_binary(Seed) -> jose_jwa_x25519:keypair(Seed). x25519_secret_to_public(SecretKey) when is_binary(SecretKey) -> jose_jwa_x25519:sk_to_pk(SecretKey). x25519_shared_secret(MySecretKey, YourPublicKey) when is_binary(MySecretKey) andalso is_binary(YourPublicKey) -> jose_jwa_x25519:x25519(MySecretKey, YourPublicKey). erlang-jose-1.10.1/src/jwa/jose_jwa_bench.erl0000644000232200023220000000462613605433351021375 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 06 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_bench). %% API -export([bench/2]). -export([bench/3]). -export([compare/3]). %%==================================================================== %% API %%==================================================================== bench(Function, Arguments) -> bench(Function, Arguments, 1). bench(Function, Arguments, N) when is_function(Function) andalso (is_list(Arguments) orelse is_function(Arguments, 0)) andalso (is_integer(N) andalso N > 0) -> {AccUSec, MinUSec, MaxUSec} = bench_loop(N, 0, 0, 0, Function, Arguments), {AccUSec, MinUSec, MaxUSec, AccUSec / N}. compare(Groups, Arguments, N) when is_list(Groups) andalso (is_list(Arguments) orelse is_function(Arguments, 0)) andalso (is_integer(N) andalso N > 0) -> ResolvedArguments = resolve(Arguments), [begin {Label, bench(Function, ResolvedArguments, N)} end || {Label, Function} <- Groups, is_atom(Label) andalso is_function(Function)]. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private bench_loop(0, MinUSec, MaxUSec, AccUSec, _Function, _Arguments) -> {AccUSec, MinUSec, MaxUSec}; bench_loop(I, 0, MaxUSec, AccUSec, Function, Arguments) -> {USec, _} = timer:tc(Function, resolve(Arguments)), MinUSec = USec, NewMaxUSec = case USec > MaxUSec of true -> USec; false -> MaxUSec end, bench_loop(I - 1, MinUSec, NewMaxUSec, AccUSec + USec, Function, Arguments); bench_loop(I, MinUSec, MaxUSec, AccUSec, Function, Arguments) -> {USec, _} = timer:tc(Function, resolve(Arguments)), NewMinUSec = case USec < MinUSec of true -> USec; false -> MinUSec end, NewMaxUSec = case USec > MaxUSec of true -> USec; false -> MaxUSec end, bench_loop(I - 1, NewMinUSec, NewMaxUSec, AccUSec + USec, Function, Arguments). %% @private resolve(Arguments) when is_function(Arguments, 0) -> resolve(Arguments()); resolve(Arguments) when is_list(Arguments) -> Arguments. erlang-jose-1.10.1/src/jwa/jose_jwa_ed25519.erl0000644000232200023220000002402113605433351021303 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc Edwards-curve Digital Signature Algorithm (EdDSA) - Ed25519 %%% See https://tools.ietf.org/html/draft-irtf-cfrg-eddsa %%% @end %%% Created : 06 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_ed25519). %% API -export([xrecover/1]). -export([encode_point/1]). -export([decode_point/1]). -export([edwards_add/2]). -export([edwards_double/1]). -export([edwards_equal/2]). -export([scalarmult/2]). -export([scalarmult_base/1]). -export([normalize_point/1]). -export([secret/0]). -export([secret_to_curve25519/1]). -export([secret_to_pk/1]). -export([keypair/0]). -export([keypair/1]). -export([sk_to_secret/1]). -export([sk_to_pk/1]). -export([sk_to_curve25519/1]). -export([pk_to_curve25519/1]). -export([sign/2]). -export([sign_with_prehash/2]). -export([verify/3]). -export([verify_with_prehash/3]). %% Macros -define(math, jose_jwa_math). -define(inv(Z), ?math:expmod(Z, ?p - 2, ?p)). % $= z^{-1} \mod p$, for z != 0 % 3. EdDSA Algorithm - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-3 % 5.1. Ed25519ph and Ed25519 - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-01#section-5.1 -define(d, -4513249062541557337682894930092624173785641285191125241628941591882900924598840740). % (-121665) * ?inv(121666) -define(I, 19681161376707505956807079304988542015446066515923890162744021073123829784752). % ?math:expmod(2, (?p - 1) div 4, ?p) %% 1. An odd prime power p. EdDSA uses an elliptic curve over the %% finite field GF(p). -define(p, 57896044618658097711785492504343953926634992332820282019728792003956564819949). % ?math:intpow(2, 255) - 19 %% 2. An integer b with 2^(b-1) > p. EdDSA public keys have exactly b %% bits, and EdDSA signatures have exactly 2*b bits. b is %% recommended to be multiple of 8, so public key and signature %% lengths are integral number of octets. -define(b, 256). % ?math:intpow(2, ?b - 1) > ?p %% 3. A (b-1)-bit encoding of elements of the finite field GF(p). -define(GFp, << 16#ED,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF, 16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FF,16#FE >>). % << ?p:(?b - 1)/unsigned-little-integer-unit:1, 0:1 >> %% 4. A cryptographic hash function H producing 2*b-bit output. %% Conservative hash functions are recommended and do not have much %% impact on the total cost of EdDSA. -define(H(M), crypto:hash(sha512, M)). -define(HBits, 512). % ?b * 2 %% 5. An integer c that is 2 or 3. Secret EdDSA scalars are multiples %% of 2^c. The integer c is the base-2 logarithm of the so called %% cofactor. -define(c, 3). %% 6. An integer n with c <= n < b. Secret EdDSA scalars have exactly %% n + 1 bits, with the top bit (the 2^n position) always set and %% the bottom c bits always cleared. -define(n, 254). % ?c =< ?n andalso ?n < ?b %% 7. A nonzero square element a of GF(p). The usual recommendation %% for best performance is a = -1 if p mod 4 = 1, and a = 1 if p %% mod 4 = 3. -define(a, -1). %% 8. An element B != (0,1) of the set E = { (x,y) is a member of %% GF(p) x GF(p) such that a * x^2 + y^2 = 1 + d * x^2 * y^2 }. -define(By, 46316835694926478169428394003475163141307993866256225615783033603165251855960). % 4 * ?inv(5) -define(Bx, 15112221349535400772501151409588531511454012693041857206046113283949847762202). % xrecover(?By) -define(B, {?Bx, ?By, 1, 46827403850823179245072216630277197565144205554125654976674165829533817101731}). % {?Bx, ?By, 1, (?Bx * ?Bx) rem ?p} % (?a * ?math:intpow(?Bx, 2) + ?math:intpow(?By, 2)) rem ?p == (1 + ?d * ?math:intpow(?Bx, 2) * ?math:intpow(?By, 2)) rem ?p %% 9. An odd prime l such that [l]B = 0 and 2^c * l = #E. The number %% #E (the number of points on the curve) is part of the standard %% data provided for an elliptic curve E. -define(l, 7237005577332262213973186563042994240857116359379907606001950938285454250989). % ?math:intpow(2, 252) + 27742317777372353535851937790883648493 -define(E, ?math:intpow(2, ?c) * ?l). %% 10. A "prehash" function PH. PureEdDSA means EdDSA where PH is the %% identity function, i.e., PH(M) = M. HashEdDSA means EdDSA where %% PH generates a short output, no matter how long the message is; %% for example, PH(M) = SHA-512(M). -define(PH(M), crypto:hash(sha512, M)). -define(secretbytes, 32). % (?b + 7) div 8 -define(publickeybytes, 32). % (?b + 7) div 8 -define(secretkeybytes, 64). % ?secretbytes + ?publickeybytes %%==================================================================== %% API %%==================================================================== % 5.1.1. Modular arithmetic - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1.1 xrecover(Y) -> YY = Y * Y, A = (YY - 1) * ?inv((?d * YY) + 1), X = ?math:expmod(A, (?p + 3) div 8, ?p), case ((X * X) - A) rem ?p =:= 0 of true -> % x^2 = a (mod p). Then x is a square root. case X rem 2 of 0 -> X; _ -> ?p - X end; false -> case ((X * X) + A) rem ?p =:= 0 of true -> % x^2 = -a (mod p). Then 2^((p-1)/4) x is a square root. Xi = (X * ?I) rem ?p, case Xi rem 2 of 0 -> Xi; _ -> ?p - Xi end; false -> % a is not a square modulo p. erlang:error(badarg) end end. % 5.1.2. Encoding - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1.2 encode_point({X, Y, Z, _T}) -> Zi = ?inv(Z), Xp = ?math:mod((X * Zi), ?p), Yp = ?math:mod((Y * Zi), ?p), << YpHead:(?b - 8)/bitstring, YpTail:8/integer >> = << Yp:?b/unsigned-little-integer-unit:1 >>, << YpHead/bitstring, (YpTail bxor (16#80 * (Xp band 1))):8/integer >>. % 5.1.3. Decoding - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1.3 decode_point(<< YpHead:(?b - 8)/bitstring, Xb:1, YpTail:7/bitstring >>) -> << Yp:?b/unsigned-little-integer-unit:1 >> = << YpHead/bitstring, 0:1, YpTail/bitstring >>, case Yp >= ?p of true -> erlang:error(badarg); false -> Xp = xrecover(Yp), X = case Xp band 1 of Xb -> Xp; _ -> ?p - Xp end, {X, Yp, 1, (X * Yp) rem ?p} end. % 5.1.4. Point addition - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1.4 edwards_add({X1, Y1, Z1, T1}, {X2, Y2, Z2, T2}) -> A = ((Y1 - X1) * (Y2 - X2)) rem ?p, B = ((Y1 + X1) * (Y2 + X2)) rem ?p, C = (T1 * 2 * ?d * T2) rem ?p, D = (Z1 * 2 * Z2) rem ?p, E = B - A, F = D - C, G = D + C, H = B + A, X3 = E * F, Y3 = G * H, T3 = E * H, Z3 = F * G, {X3 rem ?p, Y3 rem ?p, Z3 rem ?p, T3 rem ?p}. edwards_double(P) -> edwards_add(P, P). edwards_equal({X1, Y1, Z1, _T1}, {X2, Y2, Z2, _T2}) -> Z1i = ?inv(Z1), X1p = ?math:mod((X1 * Z1i), ?p), Y1p = ?math:mod((Y1 * Z1i), ?p), Z2i = ?inv(Z2), X2p = ?math:mod((X2 * Z2i), ?p), Y2p = ?math:mod((Y2 * Z2i), ?p), {X1p, Y1p} =:= {X2p, Y2p}. scalarmult(_P, 0) -> {0, 1, 1, 0}; scalarmult(P, E) -> Q = scalarmult(P, E div 2), QQ = edwards_double(Q), case E band 1 of 0 -> QQ; 1 -> edwards_add(QQ, P) end. scalarmult_base(E) -> scalarmult(?B, E). normalize_point({X, Y, Z, _T}) -> Zi = ?inv(Z), Xp = ?math:mod((X * Zi), ?p), Yp = ?math:mod((Y * Zi), ?p), Zp = ?math:mod((Z * Zi), ?p), {Xp, Yp, Zp, ?math:mod((Xp * Yp), ?p)}. % 5.1.5. Key Generation - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1.5 secret() -> crypto:strong_rand_bytes(?secretbytes). secret_to_curve25519(Secret = << _:?secretbytes/binary >>) -> << HHead0:8/integer, HBody:30/binary, HFoot0:8/integer, _/binary >> = ?H(Secret), HHead = HHead0 band 248, HFoot = (HFoot0 band 63) bor 64, << HHead:8/integer, HBody/binary, HFoot:8/integer >>. secret_to_pk(Secret = << _:?secretbytes/binary >>) -> << As:?b/unsigned-little-integer-unit:1 >> = secret_to_curve25519(Secret), A = scalarmult(?B, As), encode_point(A). keypair() -> Secret = secret(), keypair(Secret). keypair(Secret = << _:?secretbytes/binary >>) -> PK = secret_to_pk(Secret), SK = << Secret/binary, PK/binary >>, {PK, SK}. sk_to_secret(<< Secret:?secretbytes/binary, _:?publickeybytes/binary >>) -> Secret. sk_to_pk(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>) -> PK. sk_to_curve25519(<< Secret:?secretbytes/binary, _:?publickeybytes/binary >>) -> secret_to_curve25519(Secret). pk_to_curve25519(<< PK:?publickeybytes/binary >>) -> _A = {_X, Y, _Z, _T} = decode_point(PK), U = ?math:mod((1 + Y) * ?inv(1 - Y), ?p), << U:?b/unsigned-little-integer-unit:1 >>. % 5.1.6. Sign - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1.6 sign(M, << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>) when is_binary(M) -> << HHead0:8/integer, HBody:30/binary, HFoot0:8/integer, HTail:32/binary >> = ?H(Secret), HHead = HHead0 band 248, HFoot = (HFoot0 band 63) bor 64, << As:?b/unsigned-little-integer-unit:1 >> = << HHead:8/integer, HBody/binary, HFoot:8/integer >>, << Rs:?HBits/unsigned-little-integer-unit:1 >> = ?H(<< HTail/binary, M/binary >>), R = encode_point(scalarmult(?B, Rs)), << K:?HBits/unsigned-little-integer-unit:1 >> = ?H(<< R/binary, PK/binary, M/binary >>), S = ?math:mod(Rs + (K * As), ?l), << R/binary, S:?b/unsigned-little-integer-unit:1 >>. sign_with_prehash(M, SK = << _:?secretkeybytes/binary >>) when is_binary(M) -> sign(?PH(M), SK). % 5.1.7. Verify - https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1.7 verify(<< R:?b/bitstring, S:?b/unsigned-little-integer-unit:1 >>, M, PK = << _:?publickeybytes/binary >>) when is_binary(M) -> A = decode_point(PK), << K:?HBits/unsigned-little-integer-unit:1 >> = ?H(<< R/binary, PK/binary, M/binary >>), edwards_equal(scalarmult(?B, S), edwards_add(decode_point(R), scalarmult(A, K))); verify(Sig, M, << _:?publickeybytes/binary >>) when is_binary(Sig) andalso is_binary(M) -> false. verify_with_prehash(Sig, M, PK = << _:?publickeybytes/binary >>) when is_binary(Sig) andalso is_binary(M) -> verify(Sig, ?PH(M), PK). erlang-jose-1.10.1/src/jwa/jose_jwa_x25519.erl0000644000232200023220000001004213605433351021160 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc Elliptic Curves for Security - X25519 %%% See https://tools.ietf.org/html/rfc7748 %%% @end %%% Created : 06 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_x25519). %% API -export([coordinate_to_edwards25519/1]). -export([curve25519/2]). -export([clamp_scalar/1]). -export([decode_scalar/1]). -export([montgomery_add/3]). -export([montgomery_double/1]). -export([scalarmult/2]). -export([scalarmult_base/1]). -export([x25519/2]). -export([x25519_base/1]). -export([keypair/0]). -export([keypair/1]). -export([sk_to_pk/1]). %% Macros -define(math, jose_jwa_math). -define(inv(Z), ?math:expmod(Z, ?p - 2, ?p)). % $= z^{-1} \mod p$, for z != 0 % 4.1. Curve25519 - https://tools.ietf.org/html/rfc7748#section-4.1 -define(p, 57896044618658097711785492504343953926634992332820282019728792003956564819949). % ?math:intpow(2, 255) - 19 -define(A, 486662). -define(order, 7237005577332262213973186563042994240857116359379907606001950938285454250989). % ?math:intpow(2, 252) + 16#14def9dea2f79cd65812631a5cf5d3ed -define(cofactor, 8). -define(u, 9). -define(v, 14781619447589544791020593568409986887264606134616475288964881837755586237401). -define(b, 256). -define(a24, 121665). % (?A - 2) div 4 -define(scalarbytes, 32). % (?b + 7) div 8 -define(coordinatebytes, 32). % (?b + 7) div 8 -define(publickeybytes, 32). % ?coordinatebytes -define(secretkeybytes, 32). % ?scalarbytes %%==================================================================== %% API %%==================================================================== coordinate_to_edwards25519(<< U:?b/unsigned-little-integer-unit:1 >>) -> Y = ?math:mod((U - 1) * ?inv(U + 1), ?p), Xp = jose_jwa_ed25519:xrecover(Y), X = case Xp band 1 of 0 -> Xp; _ -> ?p - Xp end, jose_jwa_ed25519:encode_point({X, Y, 1, X * Y}). curve25519(N, Base) -> One = {Base, 1}, Two = montgomery_double(One), % f(m) evaluates to a tuple containing the mth multiple and the % (m+1)th multiple of base. F = fun F(1) -> {One, Two}; F(M) when (M band 1) =:= 1 -> {Pm, Pm1} = F(M div 2), {montgomery_add(Pm, Pm1, One), montgomery_double(Pm1)}; F(M) -> {Pm, Pm1} = F(M div 2), {montgomery_double(Pm), montgomery_add(Pm, Pm1, One)} end, {{X, Z}, _} = F(N), (X * ?inv(Z)) rem ?p. % 5. The X25519 and X448 functions - https://tools.ietf.org/html/rfc7748#section-5 clamp_scalar(K0) -> K1 = K0 band (bnot 7), K2 = K1 band (bnot (128 bsl (?b - 8))), K3 = K2 bor (64 bsl (?b - 8)), K3. decode_scalar(<< K0:8/integer, KBody:(?b - 16)/bitstring, K31:8/integer >>) -> << K:?b/unsigned-little-integer-unit:1 >> = << (K0 band 248):8/integer, KBody/bitstring, ((K31 band 127) bor 64):8/integer >>, K. montgomery_add({Xn, Zn}, {Xm, Zm}, {Xd, Zd}) -> Z0 = (Xm * Xn) - (Zm * Zn), Z1 = (Xm * Zn) - (Zm * Xn), X = 4 * Z0 * Z0 * Zd, Z = 4 * Z1 * Z1 * Xd, {X rem ?p, Z rem ?p}. montgomery_double({Xn, Zn}) -> Xn2 = Xn * Xn, Zn2 = Zn * Zn, X = (Xn2 - Zn2), X2 = X * X, Z = 4 * Xn * Zn * (Xn2 + (?A * Xn * Zn) + Zn2), {X2 rem ?p, Z rem ?p}. scalarmult(<< Kb:?b/unsigned-little-integer-unit:1 >>, << U:?b/unsigned-little-integer-unit:1 >>) -> K = clamp_scalar(Kb), R = curve25519(K, U), << R:?b/unsigned-little-integer-unit:1 >>. scalarmult_base(<< Kb:?b/unsigned-little-integer-unit:1 >>) -> K = clamp_scalar(Kb), R = curve25519(K, ?u), << R:?b/unsigned-little-integer-unit:1 >>. x25519(SK = << _:?secretkeybytes/binary >>, PK = << _:?publickeybytes/binary >>) -> scalarmult(SK, PK). x25519_base(SK = << _:?secretkeybytes/binary >>) -> scalarmult_base(SK). keypair() -> keypair(crypto:strong_rand_bytes(?secretkeybytes)). keypair(SK = << _:?secretkeybytes/binary >>) -> PK = sk_to_pk(SK), {PK, SK}. sk_to_pk(SK = << _:?secretkeybytes/binary >>) -> x25519_base(SK). erlang-jose-1.10.1/src/jwa/jose_jwa_chacha20_poly1305.erl0000644000232200023220000000507313605433351023240 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc ChaCha20 and Poly1305 for IETF Protocols %%% See https://tools.ietf.org/html/rfc7539 %%% @end %%% Created : 08 Aug 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_chacha20_poly1305). -behaviour(jose_chacha20_poly1305). %% jose_chacha20_poly1305 callbacks -export([decrypt/5]). -export([encrypt/4]). -export([authenticate/3]). -export([verify/4]). %% Internal API -export([pad16/1]). -export([poly1305_key_gen/2]). %%==================================================================== %% jose_chacha20_poly1305 callbacks %%==================================================================== decrypt(CipherText, CipherTag, AAD, IV, CEK) -> OTK = poly1305_key_gen(CEK, IV), MacData = << AAD/binary, (pad16(AAD))/binary, CipherText/binary, (pad16(CipherText))/binary, (byte_size(AAD)):64/unsigned-little-integer-unit:1, (byte_size(CipherText)):64/unsigned-little-integer-unit:1 >>, Challenge = jose_jwa_poly1305:mac(MacData, OTK), case jose_jwa:constant_time_compare(CipherTag, Challenge) of true -> PlainText = jose_jwa_chacha20:encrypt(CEK, 1, IV, CipherText), PlainText; false -> error end. encrypt(PlainText, AAD, IV, CEK) -> OTK = poly1305_key_gen(CEK, IV), CipherText = jose_jwa_chacha20:encrypt(CEK, 1, IV, PlainText), MacData = << AAD/binary, (pad16(AAD))/binary, CipherText/binary, (pad16(CipherText))/binary, (byte_size(AAD)):64/unsigned-little-integer-unit:1, (byte_size(CipherText)):64/unsigned-little-integer-unit:1 >>, CipherTag = jose_jwa_poly1305:mac(MacData, OTK), {CipherText, CipherTag}. authenticate(Message, Key, Nonce) -> OTK = poly1305_key_gen(Key, Nonce), jose_jwa_poly1305:mac(Message, OTK). verify(MAC, Message, Key, Nonce) -> Challenge = authenticate(Message, Key, Nonce), jose_jwa:constant_time_compare(MAC, Challenge). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private pad16(X) when (byte_size(X) rem 16) == 0 -> <<>>; pad16(X) -> binary:copy(<< 0 >>, 16 - (byte_size(X) rem 16)). %% @private poly1305_key_gen(Key, Nonce) -> Counter = 0, << Block:32/binary, _/binary >> = jose_jwa_chacha20:block(Key, Counter, Nonce), Block. erlang-jose-1.10.1/src/jwa/jose_jwa_aes_kw.erl0000644000232200023220000000640313605433351021562 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc Advanced Encryption Standard (AES) Key Wrap Algorithm %%% See RFC 3394 [https://tools.ietf.org/html/rfc3394] %%% @end %%% Created : 22 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_aes_kw). %% API -export([wrap/2]). -export([wrap/3]). -export([unwrap/2]). -export([unwrap/3]). -define(MSB64, 1/unsigned-big-integer-unit:64). -define(DEFAULT_IV, << 16#A6A6A6A6A6A6A6A6:?MSB64 >>). %%==================================================================== %% API functions %%==================================================================== wrap(PlainText, KEK) -> wrap(PlainText, KEK, ?DEFAULT_IV). wrap(PlainText, KEK, IV) when (byte_size(PlainText) rem 8) =:= 0 andalso (bit_size(KEK) =:= 128 orelse bit_size(KEK) =:= 192 orelse bit_size(KEK) =:= 256) -> Buffer = << IV/binary, PlainText/binary >>, BlockCount = (byte_size(Buffer) div 8) - 1, do_wrap(Buffer, 0, BlockCount, KEK). unwrap(CipherText, KEK) -> unwrap(CipherText, KEK, ?DEFAULT_IV). unwrap(CipherText, KEK, IV) when (byte_size(CipherText) rem 8) =:= 0 andalso (bit_size(KEK) =:= 128 orelse bit_size(KEK) =:= 192 orelse bit_size(KEK) =:= 256) -> BlockCount = (byte_size(CipherText) div 8) - 1, IVSize = byte_size(IV), case do_unwrap(CipherText, 5, BlockCount, KEK) of << IV:IVSize/binary, PlainText/binary >> -> PlainText; _ -> erlang:error({badarg, [CipherText, KEK, IV]}) end. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private do_wrap(Buffer, 6, _BlockCount, _KEK) -> Buffer; do_wrap(Buffer, J, BlockCount, KEK) -> do_wrap(do_wrap(Buffer, J, 1, BlockCount, KEK), J + 1, BlockCount, KEK). %% @private do_wrap(Buffer, _J, I, BlockCount, _KEK) when I > BlockCount -> Buffer; do_wrap(<< A0:8/binary, Rest/binary >>, J, I, BlockCount, KEK) -> HeadSize = (I - 1) * 8, << Head:HeadSize/binary, B0:8/binary, Tail/binary >> = Rest, Round = (BlockCount * J) + I, Data = << A0/binary, B0/binary >>, << A1:?MSB64, B1/binary >> = jose_jwa:block_encrypt({aes_ecb, bit_size(KEK)}, KEK, Data), A2 = A1 bxor Round, do_wrap(<< A2:?MSB64, Head/binary, B1/binary, Tail/binary >>, J, I + 1, BlockCount, KEK). %% @private do_unwrap(Buffer, J, _BlockCount, _KEK) when J < 0 -> Buffer; do_unwrap(Buffer, J, BlockCount, KEK) -> do_unwrap(do_unwrap(Buffer, J, BlockCount, BlockCount, KEK), J - 1, BlockCount, KEK). %% @private do_unwrap(Buffer, _J, I, _BlockCount, _KEK) when I < 1 -> Buffer; do_unwrap(<< A0:?MSB64, Rest/binary >>, J, I, BlockCount, KEK) -> HeadSize = (I - 1) * 8, << Head:HeadSize/binary, B0:8/binary, Tail/binary >> = Rest, Round = (BlockCount * J) + I, A1 = A0 bxor Round, Data = << A1:?MSB64, B0/binary >>, << A2:8/binary, B1/binary >> = jose_jwa:block_decrypt({aes_ecb, bit_size(KEK)}, KEK, Data), do_unwrap(<< A2/binary, Head/binary, B1/binary, Tail/binary >>, J, I - 1, BlockCount, KEK). erlang-jose-1.10.1/src/jwa/jose_jwa_xchacha20.erl0000644000232200023220000000243413605433351022052 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc XChaCha: eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 %%% See https://tools.ietf.org/html/draft-irtf-cfrg-xchacha %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_xchacha20). %% API -export([encrypt/4]). -export([subkey_and_nonce/2]). %%==================================================================== %% API functions %%==================================================================== encrypt(Key, Counter, Nonce0, Plaintext) -> {Subkey, Nonce} = subkey_and_nonce(Key, Nonce0), jose_jwa_chacha20:encrypt(Subkey, Counter, Nonce, Plaintext). subkey_and_nonce(Key, << Nonce0:128/bitstring, Nonce1:64/bitstring >>) -> Subkey = jose_jwa_hchacha20:hash(Key, Nonce0), Nonce = << 0:32, Nonce1:64/bitstring >>, {Subkey, Nonce}. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwa/jose_jwa_aes.erl0000644000232200023220000020127113605433351021061 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc Advanced Encryption Standard (AES) %%% Cipher Block Chaining (CBC), as defined in NIST.800-38A %%% Electronic Codebook (ECB), as defined in NIST.800-38A %%% Galois/Counter Mode (GCM) and GMAC, as defined in NIST.800-38D %%% See NIST.800-38A: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf %%% See NIST.800-38D: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf %%% @end %%% Created : 28 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_aes). -behaviour(jose_block_encryptor). %% jose_block_encryptor callbacks -export([block_decrypt/3]). -export([block_decrypt/4]). -export([block_encrypt/3]). -export([block_encrypt/4]). %%==================================================================== %% jose_block_encryptor callbacks %%==================================================================== block_decrypt({aes_ecb, Bits}, Key, CipherText) when (Bits =:= 128 orelse Bits =:= 192 orelse Bits =:= 256) andalso bit_size(Key) =:= Bits andalso is_binary(CipherText) -> {St, RoundKey} = aes_key_expansion(Bits, Key), ecb_block_decrypt(St, RoundKey, CipherText, <<>>). block_decrypt({aes_cbc, Bits}, Key, IV, CipherText) when (Bits =:= 128 orelse Bits =:= 192 orelse Bits =:= 256) andalso bit_size(Key) =:= Bits andalso bit_size(IV) =:= 128 andalso is_binary(CipherText) -> {St, RoundKey} = aes_key_expansion(Bits, Key), cbc_block_decrypt(St, RoundKey, IV, CipherText, <<>>); block_decrypt({aes_gcm, Bits}, Key, IV, {AAD, CipherText, CipherTag}) when (Bits =:= 128 orelse Bits =:= 192 orelse Bits =:= 256) andalso bit_size(Key) =:= Bits andalso bit_size(IV) > 0 andalso is_binary(AAD) andalso is_binary(CipherText) andalso is_binary(CipherTag) -> MasterKey = block_encrypt({aes_ecb, Bits}, Key, << 0:128 >>), gcm_block_decrypt(MasterKey, Key, IV, AAD, CipherText, CipherTag). block_encrypt({aes_ecb, Bits}, Key, PlainText) when (Bits =:= 128 orelse Bits =:= 192 orelse Bits =:= 256) andalso bit_size(Key) =:= Bits andalso is_binary(PlainText) -> {St, RoundKey} = aes_key_expansion(Bits, Key), ecb_block_encrypt(St, RoundKey, PlainText, <<>>). block_encrypt({aes_cbc, Bits}, Key, IV, PlainText) when (Bits =:= 128 orelse Bits =:= 192 orelse Bits =:= 256) andalso bit_size(Key) =:= Bits andalso bit_size(IV) =:= 128 andalso is_binary(PlainText) -> {St, RoundKey} = aes_key_expansion(Bits, Key), cbc_block_encrypt(St, RoundKey, IV, PlainText, <<>>); block_encrypt({aes_gcm, Bits}, Key, IV, {AAD, PlainText}) when (Bits =:= 128 orelse Bits =:= 192 orelse Bits =:= 256) andalso bit_size(Key) =:= Bits andalso bit_size(IV) > 0 andalso is_binary(AAD) andalso is_binary(PlainText) -> MasterKey = block_encrypt({aes_ecb, Bits}, Key, << 0:128 >>), gcm_block_encrypt(MasterKey, Key, IV, AAD, PlainText). %%%------------------------------------------------------------------- %%% Internal AES functions %%%------------------------------------------------------------------- %% @private aes_add_round_key(B0, RoundKey, {Nb, _, _}, Round) -> B1 = aes_add_round_key(0, 0, B0, RoundKey, Nb, Round), B2 = aes_add_round_key(1, 0, B1, RoundKey, Nb, Round), B3 = aes_add_round_key(2, 0, B2, RoundKey, Nb, Round), B4 = aes_add_round_key(3, 0, B3, RoundKey, Nb, Round), B4. %% @private aes_add_round_key(_I, 4, Block, _RoundKey, _Nb, _Round) -> Block; aes_add_round_key(I, J, B0, RoundKey, Nb, Round) -> RK = bget(RoundKey, Round * Nb * 4 + I * Nb + J), BK = bget(B0, I * 4 + J), B1 = bset(B0, I * 4 + J, BK bxor RK), aes_add_round_key(I, J + 1, B1, RoundKey, Nb, Round). %% @private aes_key_expansion(Bits, Key) -> % The number of columns comprising a state in AES. Nb = 4, % The number of 32 bit words in a key. Nk = Bits div 32, % The number of rounds in AES Cipher. Nr = case Bits of 128 -> 10; 192 -> 12; 256 -> 14 end, KeyLen = bit_size(Key), KeysLen = Nb * (Nr + 1) * Nk * 8, Keys = << Key/binary, 0:(KeysLen - KeyLen) >>, St = {Nb, Nk, Nr}, {St, aes_key_expansion((KeyLen div 32), (Nb * (Nr + 1)), St, Keys)}. aes_key_expansion(Rs, Rs, _, RoundKey) -> RoundKey; aes_key_expansion(I, Rs, St={Nb, Nk, _}, RoundKey) -> T0 = bget(RoundKey, (I - 1) * Nb + 0), T1 = bget(RoundKey, (I - 1) * Nb + 1), T2 = bget(RoundKey, (I - 1) * Nb + 2), T3 = bget(RoundKey, (I - 1) * Nb + 3), {V0, V1, V2, V3} = case I rem Nk of 0 -> % RotWord RW0 = T1, RW1 = T2, RW2 = T3, RW3 = T0, % SubWord SW0 = sBox(RW0) bxor rcon(I div Nk), SW1 = sBox(RW1), SW2 = sBox(RW2), SW3 = sBox(RW3), { SW0, SW1, SW2, SW3 }; 4 when Nk > 6 -> % SubWord SW0 = sBox(T0), SW1 = sBox(T1), SW2 = sBox(T2), SW3 = sBox(T3), { SW0, SW1, SW2, SW3 }; _ -> { T0, T1, T2, T3 } end, A0 = bget(RoundKey, (I - Nk) * Nb + 0) bxor V0, A1 = bget(RoundKey, (I - Nk) * Nb + 1) bxor V1, A2 = bget(RoundKey, (I - Nk) * Nb + 2) bxor V2, A3 = bget(RoundKey, (I - Nk) * Nb + 3) bxor V3, RK0 = bset(RoundKey, I * Nb + 0, A0), RK1 = bset(RK0, I * Nb + 1, A1), RK2 = bset(RK1, I * Nb + 2, A2), RK3 = bset(RK2, I * Nb + 3, A3), aes_key_expansion(I + 1, Rs, St, RK3). %%%------------------------------------------------------------------- %%% Internal AES decrypt functions %%%------------------------------------------------------------------- %% @private aes_inverse_cipher(St={_, _, Nr}, RoundKey, B0) -> B1 = aes_add_round_key(B0, RoundKey, St, Nr), B2 = aes_inverse_cipher_rounds(Nr - 1, St, RoundKey, B1), B3 = aes_inverse_shift_rows(B2), B4 = aes_inverse_sub_bytes(B3), B5 = aes_add_round_key(B4, RoundKey, St, 0), B5. %% @private aes_inverse_cipher_rounds(0, _St, _RoundKey, B) -> B; aes_inverse_cipher_rounds(Round, St, RoundKey, B0) -> B1 = aes_inverse_shift_rows(B0), B2 = aes_inverse_sub_bytes(B1), B3 = aes_add_round_key(B2, RoundKey, St, Round), B4 = aes_inverse_mix_columns(B3), aes_inverse_cipher_rounds(Round - 1, St, RoundKey, B4). %% @private aes_inverse_mix_columns(B) -> aes_inverse_mix_columns(0, B). %% @private aes_inverse_mix_columns(4, B) -> B; aes_inverse_mix_columns(I, B0) -> A = bget(B0, I * 4 + 0), B = bget(B0, I * 4 + 1), C = bget(B0, I * 4 + 2), D = bget(B0, I * 4 + 3), B1 = bset(B0, I * 4 + 0, gex(A) bxor gbx(B) bxor gdx(C) bxor g9x(D)), B2 = bset(B1, I * 4 + 1, g9x(A) bxor gex(B) bxor gbx(C) bxor gdx(D)), B3 = bset(B2, I * 4 + 2, gdx(A) bxor g9x(B) bxor gex(C) bxor gbx(D)), B4 = bset(B3, I * 4 + 3, gbx(A) bxor gdx(B) bxor g9x(C) bxor gex(D)), aes_inverse_mix_columns(I + 1, B4). %% @private aes_inverse_shift_rows(B0) -> % Rotate first row 1 columns to right T0 = bget(B0, 3 * 4 + 1), B1 = bset(B0, 3 * 4 + 1, bget(B0, 2 * 4 + 1)), B2 = bset(B1, 2 * 4 + 1, bget(B1, 1 * 4 + 1)), B3 = bset(B2, 1 * 4 + 1, bget(B2, 0 * 4 + 1)), B4 = bset(B3, 0 * 4 + 1, T0), % Rotate second row 2 columns to right T1 = bget(B4, 0 * 4 + 2), B5 = bset(B4, 0 * 4 + 2, bget(B4, 2 * 4 + 2)), B6 = bset(B5, 2 * 4 + 2, T1), T2 = bget(B6, 1 * 4 + 2), B7 = bset(B6, 1 * 4 + 2, bget(B6, 3 * 4 + 2)), B8 = bset(B7, 3 * 4 + 2, T2), % Rotate third row 3 columns to right T3 = bget(B8, 0 * 4 + 3), B9 = bset(B8, 0 * 4 + 3, bget(B8, 1 * 4 + 3)), BA = bset(B9, 1 * 4 + 3, bget(B9, 2 * 4 + 3)), BB = bset(BA, 2 * 4 + 3, bget(BA, 3 * 4 + 3)), BC = bset(BB, 3 * 4 + 3, T3), BC. %% @private aes_inverse_sub_bytes(B0) -> B1 = aes_inverse_sub_bytes(0, 0, B0), B2 = aes_inverse_sub_bytes(1, 0, B1), B3 = aes_inverse_sub_bytes(2, 0, B2), B4 = aes_inverse_sub_bytes(3, 0, B3), B4. %% @private aes_inverse_sub_bytes(_I, 4, B) -> B; aes_inverse_sub_bytes(I, J, B0) -> T0 = bget(B0, J * 4 + I), B1 = bset(B0, J * 4 + I, isBox(T0)), aes_inverse_sub_bytes(I, J + 1, B1). %%%------------------------------------------------------------------- %%% Internal AES encrypt functions %%%------------------------------------------------------------------- %% @private aes_cipher(St={_, _, Nr}, RoundKey, B0) -> B1 = aes_add_round_key(B0, RoundKey, St, 0), B2 = aes_cipher_rounds(1, St, RoundKey, B1), B3 = aes_sub_bytes(B2), B4 = aes_shift_rows(B3), B5 = aes_add_round_key(B4, RoundKey, St, Nr), B5. %% @private aes_cipher_rounds(Nr, _St={_, _, Nr}, _RoundKey, B) -> B; aes_cipher_rounds(Round, St, RoundKey, B0) -> B1 = aes_sub_bytes(B0), B2 = aes_shift_rows(B1), B3 = aes_mix_columns(B2), B4 = aes_add_round_key(B3, RoundKey, St, Round), aes_cipher_rounds(Round + 1, St, RoundKey, B4). %% @private aes_mix_columns(B) -> aes_mix_columns(0, B). %% @private aes_mix_columns(4, B) -> B; aes_mix_columns(I, B0) -> A = bget(B0, I * 4 + 0), B = bget(B0, I * 4 + 1), C = bget(B0, I * 4 + 2), D = bget(B0, I * 4 + 3), B1 = bset(B0, I * 4 + 0, g2x(A) bxor g3x(B) bxor C bxor D), B2 = bset(B1, I * 4 + 1, A bxor g2x(B) bxor g3x(C) bxor D), B3 = bset(B2, I * 4 + 2, A bxor B bxor g2x(C) bxor g3x(D)), B4 = bset(B3, I * 4 + 3, g3x(A) bxor B bxor C bxor g2x(D)), aes_mix_columns(I + 1, B4). %% @private aes_shift_rows(B0) -> % Rotate first row 1 columns to left T0 = bget(B0, 0 * 4 + 1), B1 = bset(B0, 0 * 4 + 1, bget(B0, 1 * 4 + 1)), B2 = bset(B1, 1 * 4 + 1, bget(B1, 2 * 4 + 1)), B3 = bset(B2, 2 * 4 + 1, bget(B2, 3 * 4 + 1)), B4 = bset(B3, 3 * 4 + 1, T0), % Rotate second row 2 columns to left T1 = bget(B4, 0 * 4 + 2), B5 = bset(B4, 0 * 4 + 2, bget(B4, 2 * 4 + 2)), B6 = bset(B5, 2 * 4 + 2, T1), T2 = bget(B6, 1 * 4 + 2), B7 = bset(B6, 1 * 4 + 2, bget(B6, 3 * 4 + 2)), B8 = bset(B7, 3 * 4 + 2, T2), % Rotate third row 3 columns to left T3 = bget(B8, 0 * 4 + 3), B9 = bset(B8, 0 * 4 + 3, bget(B8, 3 * 4 + 3)), BA = bset(B9, 3 * 4 + 3, bget(B9, 2 * 4 + 3)), BB = bset(BA, 2 * 4 + 3, bget(BA, 1 * 4 + 3)), BC = bset(BB, 1 * 4 + 3, T3), BC. %% @private aes_sub_bytes(B0) -> B1 = aes_sub_bytes(0, 0, B0), B2 = aes_sub_bytes(1, 0, B1), B3 = aes_sub_bytes(2, 0, B2), B4 = aes_sub_bytes(3, 0, B3), B4. %% @private aes_sub_bytes(_I, 4, B) -> B; aes_sub_bytes(I, J, B0) -> T0 = bget(B0, J * 4 + I), B1 = bset(B0, J * 4 + I, sBox(T0)), aes_sub_bytes(I, J + 1, B1). %%%------------------------------------------------------------------- %%% Internal CBC decrypt functions %%%------------------------------------------------------------------- %% @private cbc_block_decrypt(_St, _RoundKey, _IV, <<>>, PlainText) -> PlainText; cbc_block_decrypt(St, RoundKey, IV, << Block:128/bitstring, CipherText/bitstring >>, PlainText) -> Decrypted = crypto:exor(aes_inverse_cipher(St, RoundKey, Block), IV), cbc_block_decrypt(St, RoundKey, Block, CipherText, << PlainText/binary, Decrypted/binary >>). %%%------------------------------------------------------------------- %%% Internal CBC encrypt functions %%%------------------------------------------------------------------- %% @private cbc_block_encrypt(_St, _RoundKey, _IV, <<>>, CipherText) -> CipherText; cbc_block_encrypt(St, RoundKey, IV, << Block:128/bitstring, PlainText/bitstring >>, CipherText) -> Encrypted = aes_cipher(St, RoundKey, crypto:exor(Block, IV)), cbc_block_encrypt(St, RoundKey, Encrypted, PlainText, << CipherText/binary, Encrypted/binary >>). %%%------------------------------------------------------------------- %%% Internal GCM functions %%%------------------------------------------------------------------- %% @private gcm_block_decrypt(H, K, IV, A, C, T) -> Y0 = case bit_size(IV) of 96 -> << IV/binary, 1:32/unsigned-big-integer-unit:1 >>; _ -> gcm_ghash(H, <<>>, IV) end, S0 = crypto:stream_init(aes_ctr, K, Y0), {S1, EKY0xor} = crypto:stream_encrypt(S0, Y0), EKY0 = crypto:exor(EKY0xor, Y0), << Y0int:128/unsigned-big-integer-unit:1 >> = Y0, Y1 = << (Y0int + 1):128/unsigned-big-integer-unit:1 >>, GHASH = gcm_ghash(H, A, C), TBits = bit_size(T), << TPrime:TBits/bitstring, _/bitstring >> = crypto:exor(GHASH, EKY0), case jose_jwa:constant_time_compare(T, TPrime) of false -> error; true -> P = gcm_exor(S1, Y1, C, <<>>), P end. %% @private gcm_block_encrypt(H, K, IV, A, P) -> Y0 = case bit_size(IV) of 96 -> << IV/binary, 1:32/unsigned-big-integer-unit:1 >>; _ -> gcm_ghash(H, <<>>, IV) end, S0 = crypto:stream_init(aes_ctr, K, Y0), {S1, EKY0xor} = crypto:stream_encrypt(S0, Y0), EKY0 = crypto:exor(EKY0xor, Y0), << Y0int:128/unsigned-big-integer-unit:1 >> = Y0, Y1 = << (Y0int + 1):128/unsigned-big-integer-unit:1 >>, C = gcm_exor(S1, Y1, P, <<>>), GHASH = gcm_ghash(H, A, C), T = crypto:exor(GHASH, EKY0), {C, T}. %% @private gcm_exor(_S, _Y, <<>>, C) -> C; gcm_exor(S0, Y0, << B:128/bitstring, P/bitstring >>, C0) -> {S1, EKY0xor} = crypto:stream_encrypt(S0, Y0), EKY0 = crypto:exor(EKY0xor, Y0), << Y0int:128/unsigned-big-integer-unit:1 >> = Y0, Y1 = << (Y0int + 1):128/unsigned-big-integer-unit:1 >>, C1 = << C0/binary, (crypto:exor(B, EKY0))/binary >>, gcm_exor(S1, Y1, P, C1); gcm_exor(S0, Y0, P, C0) -> PBits = bit_size(P), {_S1, EKY0xor} = crypto:stream_encrypt(S0, Y0), << EKY0:PBits/bitstring, _/bitstring >> = crypto:exor(EKY0xor, Y0), C1 = << C0/binary, (crypto:exor(P, EKY0))/binary >>, C1. %% @private gcm_ghash(Key, AAD, CipherText) -> Data = << (gcm_pad(AAD))/binary, (gcm_pad(CipherText))/binary >>, K = crypto:bytes_to_integer(Key), gcm_ghash_block(K, AAD, CipherText, Data, << 0:128/unsigned-big-integer-unit:1 >>). %% @private gcm_ghash_block(K, AAD, CipherText, <<>>, GHash) -> AADBits = bit_size(AAD), CipherTextBits = bit_size(CipherText), GHashMask = << ((AADBits bsl 64) bor CipherTextBits):128/unsigned-big-integer-unit:1 >>, gcm_ghash_multiply(crypto:exor(GHash, GHashMask), K); gcm_ghash_block(K, AAD, CipherText, << Block:128/bitstring, Data/bitstring >>, GHash) -> gcm_ghash_block(K, AAD, CipherText, Data, gcm_ghash_multiply(crypto:exor(GHash, Block), K)). %% @private gcm_ghash_multiply(GHash, K) -> gcm_ghash_multiply(0, K, crypto:bytes_to_integer(GHash), 0). %% @private gcm_ghash_multiply(16, _K, _GHash, Result) -> << Result:128/unsigned-big-integer-unit:1 >>; gcm_ghash_multiply(I, K, GHash, Result) -> J = (GHash band 16#FF), Val = gf_2_128_mul(K, (J bsl (I * 8))), gcm_ghash_multiply(I + 1, K, GHash bsr 8, Result bxor Val). %% @private gcm_pad(Binary) when (byte_size(Binary) rem 16) =/= 0 -> PadBits = (16 - (byte_size(Binary) rem 16)) * 8, << Binary/binary, 0:PadBits >>; gcm_pad(Binary) -> Binary. %% @private gf_2_128_mul(X, Y) -> gf_2_128_mul(127, X, Y, 0). %% @private gf_2_128_mul(-1, _X, _Y, R) -> R; gf_2_128_mul(I, X0, Y, R0) -> R1 = (R0 bxor (X0 * ((Y bsr I) band 1))), X1 = (X0 bsr 1) bxor ((X0 band 1) * 16#E1000000000000000000000000000000), gf_2_128_mul(I - 1, X1, Y, R1). %%%------------------------------------------------------------------- %%% Internal ECB decrypt functions %%%------------------------------------------------------------------- %% @private ecb_block_decrypt(_St, _RoundKey, <<>>, PlainText) -> PlainText; ecb_block_decrypt(St, RoundKey, << Block:128/bitstring, CipherText/bitstring >>, PlainText) -> Decrypted = aes_inverse_cipher(St, RoundKey, Block), ecb_block_decrypt(St, RoundKey, CipherText, << PlainText/binary, Decrypted/binary >>). %%%------------------------------------------------------------------- %%% Internal ECB encrypt functions %%%------------------------------------------------------------------- %% @private ecb_block_encrypt(_St, _RoundKey, <<>>, CipherText) -> CipherText; ecb_block_encrypt(St, RoundKey, << Block:128/bitstring, PlainText/bitstring >>, CipherText) -> Encrypted = aes_cipher(St, RoundKey, Block), ecb_block_encrypt(St, RoundKey, PlainText, << CipherText/binary, Encrypted/binary >>). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private bget(B, Pos) when Pos >= 0 -> binary:at(B, Pos); bget(B, Pos) -> bget(B, byte_size(B) + Pos). %% @private bset(B, Pos, Val) when Pos =:= byte_size(B) -> << B/binary, Val >>; bset(<< _, B/binary >>, 0, Val) -> << Val, B/binary >>; bset(B, Pos, Val) when Pos >= 0 -> << Head:Pos/binary, _, Tail/binary >> = B, << Head/binary, Val, Tail/binary >>; bset(B, Pos, Val) -> bset(B, byte_size(B) + Pos, Val). %%%------------------------------------------------------------------- %%% AES constant functions %%%------------------------------------------------------------------- %% @private g2x(16#00) -> 16#00; g2x(16#01) -> 16#02; g2x(16#02) -> 16#04; g2x(16#03) -> 16#06; g2x(16#04) -> 16#08; g2x(16#05) -> 16#0A; g2x(16#06) -> 16#0C; g2x(16#07) -> 16#0E; g2x(16#08) -> 16#10; g2x(16#09) -> 16#12; g2x(16#0A) -> 16#14; g2x(16#0B) -> 16#16; g2x(16#0C) -> 16#18; g2x(16#0D) -> 16#1A; g2x(16#0E) -> 16#1C; g2x(16#0F) -> 16#1E; g2x(16#10) -> 16#20; g2x(16#11) -> 16#22; g2x(16#12) -> 16#24; g2x(16#13) -> 16#26; g2x(16#14) -> 16#28; g2x(16#15) -> 16#2A; g2x(16#16) -> 16#2C; g2x(16#17) -> 16#2E; g2x(16#18) -> 16#30; g2x(16#19) -> 16#32; g2x(16#1A) -> 16#34; g2x(16#1B) -> 16#36; g2x(16#1C) -> 16#38; g2x(16#1D) -> 16#3A; g2x(16#1E) -> 16#3C; g2x(16#1F) -> 16#3E; g2x(16#20) -> 16#40; g2x(16#21) -> 16#42; g2x(16#22) -> 16#44; g2x(16#23) -> 16#46; g2x(16#24) -> 16#48; g2x(16#25) -> 16#4A; g2x(16#26) -> 16#4C; g2x(16#27) -> 16#4E; g2x(16#28) -> 16#50; g2x(16#29) -> 16#52; g2x(16#2A) -> 16#54; g2x(16#2B) -> 16#56; g2x(16#2C) -> 16#58; g2x(16#2D) -> 16#5A; g2x(16#2E) -> 16#5C; g2x(16#2F) -> 16#5E; g2x(16#30) -> 16#60; g2x(16#31) -> 16#62; g2x(16#32) -> 16#64; g2x(16#33) -> 16#66; g2x(16#34) -> 16#68; g2x(16#35) -> 16#6A; g2x(16#36) -> 16#6C; g2x(16#37) -> 16#6E; g2x(16#38) -> 16#70; g2x(16#39) -> 16#72; g2x(16#3A) -> 16#74; g2x(16#3B) -> 16#76; g2x(16#3C) -> 16#78; g2x(16#3D) -> 16#7A; g2x(16#3E) -> 16#7C; g2x(16#3F) -> 16#7E; g2x(16#40) -> 16#80; g2x(16#41) -> 16#82; g2x(16#42) -> 16#84; g2x(16#43) -> 16#86; g2x(16#44) -> 16#88; g2x(16#45) -> 16#8A; g2x(16#46) -> 16#8C; g2x(16#47) -> 16#8E; g2x(16#48) -> 16#90; g2x(16#49) -> 16#92; g2x(16#4A) -> 16#94; g2x(16#4B) -> 16#96; g2x(16#4C) -> 16#98; g2x(16#4D) -> 16#9A; g2x(16#4E) -> 16#9C; g2x(16#4F) -> 16#9E; g2x(16#50) -> 16#A0; g2x(16#51) -> 16#A2; g2x(16#52) -> 16#A4; g2x(16#53) -> 16#A6; g2x(16#54) -> 16#A8; g2x(16#55) -> 16#AA; g2x(16#56) -> 16#AC; g2x(16#57) -> 16#AE; g2x(16#58) -> 16#B0; g2x(16#59) -> 16#B2; g2x(16#5A) -> 16#B4; g2x(16#5B) -> 16#B6; g2x(16#5C) -> 16#B8; g2x(16#5D) -> 16#BA; g2x(16#5E) -> 16#BC; g2x(16#5F) -> 16#BE; g2x(16#60) -> 16#C0; g2x(16#61) -> 16#C2; g2x(16#62) -> 16#C4; g2x(16#63) -> 16#C6; g2x(16#64) -> 16#C8; g2x(16#65) -> 16#CA; g2x(16#66) -> 16#CC; g2x(16#67) -> 16#CE; g2x(16#68) -> 16#D0; g2x(16#69) -> 16#D2; g2x(16#6A) -> 16#D4; g2x(16#6B) -> 16#D6; g2x(16#6C) -> 16#D8; g2x(16#6D) -> 16#DA; g2x(16#6E) -> 16#DC; g2x(16#6F) -> 16#DE; g2x(16#70) -> 16#E0; g2x(16#71) -> 16#E2; g2x(16#72) -> 16#E4; g2x(16#73) -> 16#E6; g2x(16#74) -> 16#E8; g2x(16#75) -> 16#EA; g2x(16#76) -> 16#EC; g2x(16#77) -> 16#EE; g2x(16#78) -> 16#F0; g2x(16#79) -> 16#F2; g2x(16#7A) -> 16#F4; g2x(16#7B) -> 16#F6; g2x(16#7C) -> 16#F8; g2x(16#7D) -> 16#FA; g2x(16#7E) -> 16#FC; g2x(16#7F) -> 16#FE; g2x(16#80) -> 16#1B; g2x(16#81) -> 16#19; g2x(16#82) -> 16#1F; g2x(16#83) -> 16#1D; g2x(16#84) -> 16#13; g2x(16#85) -> 16#11; g2x(16#86) -> 16#17; g2x(16#87) -> 16#15; g2x(16#88) -> 16#0B; g2x(16#89) -> 16#09; g2x(16#8A) -> 16#0F; g2x(16#8B) -> 16#0D; g2x(16#8C) -> 16#03; g2x(16#8D) -> 16#01; g2x(16#8E) -> 16#07; g2x(16#8F) -> 16#05; g2x(16#90) -> 16#3B; g2x(16#91) -> 16#39; g2x(16#92) -> 16#3F; g2x(16#93) -> 16#3D; g2x(16#94) -> 16#33; g2x(16#95) -> 16#31; g2x(16#96) -> 16#37; g2x(16#97) -> 16#35; g2x(16#98) -> 16#2B; g2x(16#99) -> 16#29; g2x(16#9A) -> 16#2F; g2x(16#9B) -> 16#2D; g2x(16#9C) -> 16#23; g2x(16#9D) -> 16#21; g2x(16#9E) -> 16#27; g2x(16#9F) -> 16#25; g2x(16#A0) -> 16#5B; g2x(16#A1) -> 16#59; g2x(16#A2) -> 16#5F; g2x(16#A3) -> 16#5D; g2x(16#A4) -> 16#53; g2x(16#A5) -> 16#51; g2x(16#A6) -> 16#57; g2x(16#A7) -> 16#55; g2x(16#A8) -> 16#4B; g2x(16#A9) -> 16#49; g2x(16#AA) -> 16#4F; g2x(16#AB) -> 16#4D; g2x(16#AC) -> 16#43; g2x(16#AD) -> 16#41; g2x(16#AE) -> 16#47; g2x(16#AF) -> 16#45; g2x(16#B0) -> 16#7B; g2x(16#B1) -> 16#79; g2x(16#B2) -> 16#7F; g2x(16#B3) -> 16#7D; g2x(16#B4) -> 16#73; g2x(16#B5) -> 16#71; g2x(16#B6) -> 16#77; g2x(16#B7) -> 16#75; g2x(16#B8) -> 16#6B; g2x(16#B9) -> 16#69; g2x(16#BA) -> 16#6F; g2x(16#BB) -> 16#6D; g2x(16#BC) -> 16#63; g2x(16#BD) -> 16#61; g2x(16#BE) -> 16#67; g2x(16#BF) -> 16#65; g2x(16#C0) -> 16#9B; g2x(16#C1) -> 16#99; g2x(16#C2) -> 16#9F; g2x(16#C3) -> 16#9D; g2x(16#C4) -> 16#93; g2x(16#C5) -> 16#91; g2x(16#C6) -> 16#97; g2x(16#C7) -> 16#95; g2x(16#C8) -> 16#8B; g2x(16#C9) -> 16#89; g2x(16#CA) -> 16#8F; g2x(16#CB) -> 16#8D; g2x(16#CC) -> 16#83; g2x(16#CD) -> 16#81; g2x(16#CE) -> 16#87; g2x(16#CF) -> 16#85; g2x(16#D0) -> 16#BB; g2x(16#D1) -> 16#B9; g2x(16#D2) -> 16#BF; g2x(16#D3) -> 16#BD; g2x(16#D4) -> 16#B3; g2x(16#D5) -> 16#B1; g2x(16#D6) -> 16#B7; g2x(16#D7) -> 16#B5; g2x(16#D8) -> 16#AB; g2x(16#D9) -> 16#A9; g2x(16#DA) -> 16#AF; g2x(16#DB) -> 16#AD; g2x(16#DC) -> 16#A3; g2x(16#DD) -> 16#A1; g2x(16#DE) -> 16#A7; g2x(16#DF) -> 16#A5; g2x(16#E0) -> 16#DB; g2x(16#E1) -> 16#D9; g2x(16#E2) -> 16#DF; g2x(16#E3) -> 16#DD; g2x(16#E4) -> 16#D3; g2x(16#E5) -> 16#D1; g2x(16#E6) -> 16#D7; g2x(16#E7) -> 16#D5; g2x(16#E8) -> 16#CB; g2x(16#E9) -> 16#C9; g2x(16#EA) -> 16#CF; g2x(16#EB) -> 16#CD; g2x(16#EC) -> 16#C3; g2x(16#ED) -> 16#C1; g2x(16#EE) -> 16#C7; g2x(16#EF) -> 16#C5; g2x(16#F0) -> 16#FB; g2x(16#F1) -> 16#F9; g2x(16#F2) -> 16#FF; g2x(16#F3) -> 16#FD; g2x(16#F4) -> 16#F3; g2x(16#F5) -> 16#F1; g2x(16#F6) -> 16#F7; g2x(16#F7) -> 16#F5; g2x(16#F8) -> 16#EB; g2x(16#F9) -> 16#E9; g2x(16#FA) -> 16#EF; g2x(16#FB) -> 16#ED; g2x(16#FC) -> 16#E3; g2x(16#FD) -> 16#E1; g2x(16#FE) -> 16#E7; g2x(16#FF) -> 16#E5. %% @private g3x(16#00) -> 16#00; g3x(16#01) -> 16#03; g3x(16#02) -> 16#06; g3x(16#03) -> 16#05; g3x(16#04) -> 16#0C; g3x(16#05) -> 16#0F; g3x(16#06) -> 16#0A; g3x(16#07) -> 16#09; g3x(16#08) -> 16#18; g3x(16#09) -> 16#1B; g3x(16#0A) -> 16#1E; g3x(16#0B) -> 16#1D; g3x(16#0C) -> 16#14; g3x(16#0D) -> 16#17; g3x(16#0E) -> 16#12; g3x(16#0F) -> 16#11; g3x(16#10) -> 16#30; g3x(16#11) -> 16#33; g3x(16#12) -> 16#36; g3x(16#13) -> 16#35; g3x(16#14) -> 16#3C; g3x(16#15) -> 16#3F; g3x(16#16) -> 16#3A; g3x(16#17) -> 16#39; g3x(16#18) -> 16#28; g3x(16#19) -> 16#2B; g3x(16#1A) -> 16#2E; g3x(16#1B) -> 16#2D; g3x(16#1C) -> 16#24; g3x(16#1D) -> 16#27; g3x(16#1E) -> 16#22; g3x(16#1F) -> 16#21; g3x(16#20) -> 16#60; g3x(16#21) -> 16#63; g3x(16#22) -> 16#66; g3x(16#23) -> 16#65; g3x(16#24) -> 16#6C; g3x(16#25) -> 16#6F; g3x(16#26) -> 16#6A; g3x(16#27) -> 16#69; g3x(16#28) -> 16#78; g3x(16#29) -> 16#7B; g3x(16#2A) -> 16#7E; g3x(16#2B) -> 16#7D; g3x(16#2C) -> 16#74; g3x(16#2D) -> 16#77; g3x(16#2E) -> 16#72; g3x(16#2F) -> 16#71; g3x(16#30) -> 16#50; g3x(16#31) -> 16#53; g3x(16#32) -> 16#56; g3x(16#33) -> 16#55; g3x(16#34) -> 16#5C; g3x(16#35) -> 16#5F; g3x(16#36) -> 16#5A; g3x(16#37) -> 16#59; g3x(16#38) -> 16#48; g3x(16#39) -> 16#4B; g3x(16#3A) -> 16#4E; g3x(16#3B) -> 16#4D; g3x(16#3C) -> 16#44; g3x(16#3D) -> 16#47; g3x(16#3E) -> 16#42; g3x(16#3F) -> 16#41; g3x(16#40) -> 16#C0; g3x(16#41) -> 16#C3; g3x(16#42) -> 16#C6; g3x(16#43) -> 16#C5; g3x(16#44) -> 16#CC; g3x(16#45) -> 16#CF; g3x(16#46) -> 16#CA; g3x(16#47) -> 16#C9; g3x(16#48) -> 16#D8; g3x(16#49) -> 16#DB; g3x(16#4A) -> 16#DE; g3x(16#4B) -> 16#DD; g3x(16#4C) -> 16#D4; g3x(16#4D) -> 16#D7; g3x(16#4E) -> 16#D2; g3x(16#4F) -> 16#D1; g3x(16#50) -> 16#F0; g3x(16#51) -> 16#F3; g3x(16#52) -> 16#F6; g3x(16#53) -> 16#F5; g3x(16#54) -> 16#FC; g3x(16#55) -> 16#FF; g3x(16#56) -> 16#FA; g3x(16#57) -> 16#F9; g3x(16#58) -> 16#E8; g3x(16#59) -> 16#EB; g3x(16#5A) -> 16#EE; g3x(16#5B) -> 16#ED; g3x(16#5C) -> 16#E4; g3x(16#5D) -> 16#E7; g3x(16#5E) -> 16#E2; g3x(16#5F) -> 16#E1; g3x(16#60) -> 16#A0; g3x(16#61) -> 16#A3; g3x(16#62) -> 16#A6; g3x(16#63) -> 16#A5; g3x(16#64) -> 16#AC; g3x(16#65) -> 16#AF; g3x(16#66) -> 16#AA; g3x(16#67) -> 16#A9; g3x(16#68) -> 16#B8; g3x(16#69) -> 16#BB; g3x(16#6A) -> 16#BE; g3x(16#6B) -> 16#BD; g3x(16#6C) -> 16#B4; g3x(16#6D) -> 16#B7; g3x(16#6E) -> 16#B2; g3x(16#6F) -> 16#B1; g3x(16#70) -> 16#90; g3x(16#71) -> 16#93; g3x(16#72) -> 16#96; g3x(16#73) -> 16#95; g3x(16#74) -> 16#9C; g3x(16#75) -> 16#9F; g3x(16#76) -> 16#9A; g3x(16#77) -> 16#99; g3x(16#78) -> 16#88; g3x(16#79) -> 16#8B; g3x(16#7A) -> 16#8E; g3x(16#7B) -> 16#8D; g3x(16#7C) -> 16#84; g3x(16#7D) -> 16#87; g3x(16#7E) -> 16#82; g3x(16#7F) -> 16#81; g3x(16#80) -> 16#9B; g3x(16#81) -> 16#98; g3x(16#82) -> 16#9D; g3x(16#83) -> 16#9E; g3x(16#84) -> 16#97; g3x(16#85) -> 16#94; g3x(16#86) -> 16#91; g3x(16#87) -> 16#92; g3x(16#88) -> 16#83; g3x(16#89) -> 16#80; g3x(16#8A) -> 16#85; g3x(16#8B) -> 16#86; g3x(16#8C) -> 16#8F; g3x(16#8D) -> 16#8C; g3x(16#8E) -> 16#89; g3x(16#8F) -> 16#8A; g3x(16#90) -> 16#AB; g3x(16#91) -> 16#A8; g3x(16#92) -> 16#AD; g3x(16#93) -> 16#AE; g3x(16#94) -> 16#A7; g3x(16#95) -> 16#A4; g3x(16#96) -> 16#A1; g3x(16#97) -> 16#A2; g3x(16#98) -> 16#B3; g3x(16#99) -> 16#B0; g3x(16#9A) -> 16#B5; g3x(16#9B) -> 16#B6; g3x(16#9C) -> 16#BF; g3x(16#9D) -> 16#BC; g3x(16#9E) -> 16#B9; g3x(16#9F) -> 16#BA; g3x(16#A0) -> 16#FB; g3x(16#A1) -> 16#F8; g3x(16#A2) -> 16#FD; g3x(16#A3) -> 16#FE; g3x(16#A4) -> 16#F7; g3x(16#A5) -> 16#F4; g3x(16#A6) -> 16#F1; g3x(16#A7) -> 16#F2; g3x(16#A8) -> 16#E3; g3x(16#A9) -> 16#E0; g3x(16#AA) -> 16#E5; g3x(16#AB) -> 16#E6; g3x(16#AC) -> 16#EF; g3x(16#AD) -> 16#EC; g3x(16#AE) -> 16#E9; g3x(16#AF) -> 16#EA; g3x(16#B0) -> 16#CB; g3x(16#B1) -> 16#C8; g3x(16#B2) -> 16#CD; g3x(16#B3) -> 16#CE; g3x(16#B4) -> 16#C7; g3x(16#B5) -> 16#C4; g3x(16#B6) -> 16#C1; g3x(16#B7) -> 16#C2; g3x(16#B8) -> 16#D3; g3x(16#B9) -> 16#D0; g3x(16#BA) -> 16#D5; g3x(16#BB) -> 16#D6; g3x(16#BC) -> 16#DF; g3x(16#BD) -> 16#DC; g3x(16#BE) -> 16#D9; g3x(16#BF) -> 16#DA; g3x(16#C0) -> 16#5B; g3x(16#C1) -> 16#58; g3x(16#C2) -> 16#5D; g3x(16#C3) -> 16#5E; g3x(16#C4) -> 16#57; g3x(16#C5) -> 16#54; g3x(16#C6) -> 16#51; g3x(16#C7) -> 16#52; g3x(16#C8) -> 16#43; g3x(16#C9) -> 16#40; g3x(16#CA) -> 16#45; g3x(16#CB) -> 16#46; g3x(16#CC) -> 16#4F; g3x(16#CD) -> 16#4C; g3x(16#CE) -> 16#49; g3x(16#CF) -> 16#4A; g3x(16#D0) -> 16#6B; g3x(16#D1) -> 16#68; g3x(16#D2) -> 16#6D; g3x(16#D3) -> 16#6E; g3x(16#D4) -> 16#67; g3x(16#D5) -> 16#64; g3x(16#D6) -> 16#61; g3x(16#D7) -> 16#62; g3x(16#D8) -> 16#73; g3x(16#D9) -> 16#70; g3x(16#DA) -> 16#75; g3x(16#DB) -> 16#76; g3x(16#DC) -> 16#7F; g3x(16#DD) -> 16#7C; g3x(16#DE) -> 16#79; g3x(16#DF) -> 16#7A; g3x(16#E0) -> 16#3B; g3x(16#E1) -> 16#38; g3x(16#E2) -> 16#3D; g3x(16#E3) -> 16#3E; g3x(16#E4) -> 16#37; g3x(16#E5) -> 16#34; g3x(16#E6) -> 16#31; g3x(16#E7) -> 16#32; g3x(16#E8) -> 16#23; g3x(16#E9) -> 16#20; g3x(16#EA) -> 16#25; g3x(16#EB) -> 16#26; g3x(16#EC) -> 16#2F; g3x(16#ED) -> 16#2C; g3x(16#EE) -> 16#29; g3x(16#EF) -> 16#2A; g3x(16#F0) -> 16#0B; g3x(16#F1) -> 16#08; g3x(16#F2) -> 16#0D; g3x(16#F3) -> 16#0E; g3x(16#F4) -> 16#07; g3x(16#F5) -> 16#04; g3x(16#F6) -> 16#01; g3x(16#F7) -> 16#02; g3x(16#F8) -> 16#13; g3x(16#F9) -> 16#10; g3x(16#FA) -> 16#15; g3x(16#FB) -> 16#16; g3x(16#FC) -> 16#1F; g3x(16#FD) -> 16#1C; g3x(16#FE) -> 16#19; g3x(16#FF) -> 16#1A. %% @private g9x(16#00) -> 16#00; g9x(16#01) -> 16#09; g9x(16#02) -> 16#12; g9x(16#03) -> 16#1B; g9x(16#04) -> 16#24; g9x(16#05) -> 16#2D; g9x(16#06) -> 16#36; g9x(16#07) -> 16#3F; g9x(16#08) -> 16#48; g9x(16#09) -> 16#41; g9x(16#0A) -> 16#5A; g9x(16#0B) -> 16#53; g9x(16#0C) -> 16#6C; g9x(16#0D) -> 16#65; g9x(16#0E) -> 16#7E; g9x(16#0F) -> 16#77; g9x(16#10) -> 16#90; g9x(16#11) -> 16#99; g9x(16#12) -> 16#82; g9x(16#13) -> 16#8B; g9x(16#14) -> 16#B4; g9x(16#15) -> 16#BD; g9x(16#16) -> 16#A6; g9x(16#17) -> 16#AF; g9x(16#18) -> 16#D8; g9x(16#19) -> 16#D1; g9x(16#1A) -> 16#CA; g9x(16#1B) -> 16#C3; g9x(16#1C) -> 16#FC; g9x(16#1D) -> 16#F5; g9x(16#1E) -> 16#EE; g9x(16#1F) -> 16#E7; g9x(16#20) -> 16#3B; g9x(16#21) -> 16#32; g9x(16#22) -> 16#29; g9x(16#23) -> 16#20; g9x(16#24) -> 16#1F; g9x(16#25) -> 16#16; g9x(16#26) -> 16#0D; g9x(16#27) -> 16#04; g9x(16#28) -> 16#73; g9x(16#29) -> 16#7A; g9x(16#2A) -> 16#61; g9x(16#2B) -> 16#68; g9x(16#2C) -> 16#57; g9x(16#2D) -> 16#5E; g9x(16#2E) -> 16#45; g9x(16#2F) -> 16#4C; g9x(16#30) -> 16#AB; g9x(16#31) -> 16#A2; g9x(16#32) -> 16#B9; g9x(16#33) -> 16#B0; g9x(16#34) -> 16#8F; g9x(16#35) -> 16#86; g9x(16#36) -> 16#9D; g9x(16#37) -> 16#94; g9x(16#38) -> 16#E3; g9x(16#39) -> 16#EA; g9x(16#3A) -> 16#F1; g9x(16#3B) -> 16#F8; g9x(16#3C) -> 16#C7; g9x(16#3D) -> 16#CE; g9x(16#3E) -> 16#D5; g9x(16#3F) -> 16#DC; g9x(16#40) -> 16#76; g9x(16#41) -> 16#7F; g9x(16#42) -> 16#64; g9x(16#43) -> 16#6D; g9x(16#44) -> 16#52; g9x(16#45) -> 16#5B; g9x(16#46) -> 16#40; g9x(16#47) -> 16#49; g9x(16#48) -> 16#3E; g9x(16#49) -> 16#37; g9x(16#4A) -> 16#2C; g9x(16#4B) -> 16#25; g9x(16#4C) -> 16#1A; g9x(16#4D) -> 16#13; g9x(16#4E) -> 16#08; g9x(16#4F) -> 16#01; g9x(16#50) -> 16#E6; g9x(16#51) -> 16#EF; g9x(16#52) -> 16#F4; g9x(16#53) -> 16#FD; g9x(16#54) -> 16#C2; g9x(16#55) -> 16#CB; g9x(16#56) -> 16#D0; g9x(16#57) -> 16#D9; g9x(16#58) -> 16#AE; g9x(16#59) -> 16#A7; g9x(16#5A) -> 16#BC; g9x(16#5B) -> 16#B5; g9x(16#5C) -> 16#8A; g9x(16#5D) -> 16#83; g9x(16#5E) -> 16#98; g9x(16#5F) -> 16#91; g9x(16#60) -> 16#4D; g9x(16#61) -> 16#44; g9x(16#62) -> 16#5F; g9x(16#63) -> 16#56; g9x(16#64) -> 16#69; g9x(16#65) -> 16#60; g9x(16#66) -> 16#7B; g9x(16#67) -> 16#72; g9x(16#68) -> 16#05; g9x(16#69) -> 16#0C; g9x(16#6A) -> 16#17; g9x(16#6B) -> 16#1E; g9x(16#6C) -> 16#21; g9x(16#6D) -> 16#28; g9x(16#6E) -> 16#33; g9x(16#6F) -> 16#3A; g9x(16#70) -> 16#DD; g9x(16#71) -> 16#D4; g9x(16#72) -> 16#CF; g9x(16#73) -> 16#C6; g9x(16#74) -> 16#F9; g9x(16#75) -> 16#F0; g9x(16#76) -> 16#EB; g9x(16#77) -> 16#E2; g9x(16#78) -> 16#95; g9x(16#79) -> 16#9C; g9x(16#7A) -> 16#87; g9x(16#7B) -> 16#8E; g9x(16#7C) -> 16#B1; g9x(16#7D) -> 16#B8; g9x(16#7E) -> 16#A3; g9x(16#7F) -> 16#AA; g9x(16#80) -> 16#EC; g9x(16#81) -> 16#E5; g9x(16#82) -> 16#FE; g9x(16#83) -> 16#F7; g9x(16#84) -> 16#C8; g9x(16#85) -> 16#C1; g9x(16#86) -> 16#DA; g9x(16#87) -> 16#D3; g9x(16#88) -> 16#A4; g9x(16#89) -> 16#AD; g9x(16#8A) -> 16#B6; g9x(16#8B) -> 16#BF; g9x(16#8C) -> 16#80; g9x(16#8D) -> 16#89; g9x(16#8E) -> 16#92; g9x(16#8F) -> 16#9B; g9x(16#90) -> 16#7C; g9x(16#91) -> 16#75; g9x(16#92) -> 16#6E; g9x(16#93) -> 16#67; g9x(16#94) -> 16#58; g9x(16#95) -> 16#51; g9x(16#96) -> 16#4A; g9x(16#97) -> 16#43; g9x(16#98) -> 16#34; g9x(16#99) -> 16#3D; g9x(16#9A) -> 16#26; g9x(16#9B) -> 16#2F; g9x(16#9C) -> 16#10; g9x(16#9D) -> 16#19; g9x(16#9E) -> 16#02; g9x(16#9F) -> 16#0B; g9x(16#A0) -> 16#D7; g9x(16#A1) -> 16#DE; g9x(16#A2) -> 16#C5; g9x(16#A3) -> 16#CC; g9x(16#A4) -> 16#F3; g9x(16#A5) -> 16#FA; g9x(16#A6) -> 16#E1; g9x(16#A7) -> 16#E8; g9x(16#A8) -> 16#9F; g9x(16#A9) -> 16#96; g9x(16#AA) -> 16#8D; g9x(16#AB) -> 16#84; g9x(16#AC) -> 16#BB; g9x(16#AD) -> 16#B2; g9x(16#AE) -> 16#A9; g9x(16#AF) -> 16#A0; g9x(16#B0) -> 16#47; g9x(16#B1) -> 16#4E; g9x(16#B2) -> 16#55; g9x(16#B3) -> 16#5C; g9x(16#B4) -> 16#63; g9x(16#B5) -> 16#6A; g9x(16#B6) -> 16#71; g9x(16#B7) -> 16#78; g9x(16#B8) -> 16#0F; g9x(16#B9) -> 16#06; g9x(16#BA) -> 16#1D; g9x(16#BB) -> 16#14; g9x(16#BC) -> 16#2B; g9x(16#BD) -> 16#22; g9x(16#BE) -> 16#39; g9x(16#BF) -> 16#30; g9x(16#C0) -> 16#9A; g9x(16#C1) -> 16#93; g9x(16#C2) -> 16#88; g9x(16#C3) -> 16#81; g9x(16#C4) -> 16#BE; g9x(16#C5) -> 16#B7; g9x(16#C6) -> 16#AC; g9x(16#C7) -> 16#A5; g9x(16#C8) -> 16#D2; g9x(16#C9) -> 16#DB; g9x(16#CA) -> 16#C0; g9x(16#CB) -> 16#C9; g9x(16#CC) -> 16#F6; g9x(16#CD) -> 16#FF; g9x(16#CE) -> 16#E4; g9x(16#CF) -> 16#ED; g9x(16#D0) -> 16#0A; g9x(16#D1) -> 16#03; g9x(16#D2) -> 16#18; g9x(16#D3) -> 16#11; g9x(16#D4) -> 16#2E; g9x(16#D5) -> 16#27; g9x(16#D6) -> 16#3C; g9x(16#D7) -> 16#35; g9x(16#D8) -> 16#42; g9x(16#D9) -> 16#4B; g9x(16#DA) -> 16#50; g9x(16#DB) -> 16#59; g9x(16#DC) -> 16#66; g9x(16#DD) -> 16#6F; g9x(16#DE) -> 16#74; g9x(16#DF) -> 16#7D; g9x(16#E0) -> 16#A1; g9x(16#E1) -> 16#A8; g9x(16#E2) -> 16#B3; g9x(16#E3) -> 16#BA; g9x(16#E4) -> 16#85; g9x(16#E5) -> 16#8C; g9x(16#E6) -> 16#97; g9x(16#E7) -> 16#9E; g9x(16#E8) -> 16#E9; g9x(16#E9) -> 16#E0; g9x(16#EA) -> 16#FB; g9x(16#EB) -> 16#F2; g9x(16#EC) -> 16#CD; g9x(16#ED) -> 16#C4; g9x(16#EE) -> 16#DF; g9x(16#EF) -> 16#D6; g9x(16#F0) -> 16#31; g9x(16#F1) -> 16#38; g9x(16#F2) -> 16#23; g9x(16#F3) -> 16#2A; g9x(16#F4) -> 16#15; g9x(16#F5) -> 16#1C; g9x(16#F6) -> 16#07; g9x(16#F7) -> 16#0E; g9x(16#F8) -> 16#79; g9x(16#F9) -> 16#70; g9x(16#FA) -> 16#6B; g9x(16#FB) -> 16#62; g9x(16#FC) -> 16#5D; g9x(16#FD) -> 16#54; g9x(16#FE) -> 16#4F; g9x(16#FF) -> 16#46. %% @private gbx(16#00) -> 16#00; gbx(16#01) -> 16#0B; gbx(16#02) -> 16#16; gbx(16#03) -> 16#1D; gbx(16#04) -> 16#2C; gbx(16#05) -> 16#27; gbx(16#06) -> 16#3A; gbx(16#07) -> 16#31; gbx(16#08) -> 16#58; gbx(16#09) -> 16#53; gbx(16#0A) -> 16#4E; gbx(16#0B) -> 16#45; gbx(16#0C) -> 16#74; gbx(16#0D) -> 16#7F; gbx(16#0E) -> 16#62; gbx(16#0F) -> 16#69; gbx(16#10) -> 16#B0; gbx(16#11) -> 16#BB; gbx(16#12) -> 16#A6; gbx(16#13) -> 16#AD; gbx(16#14) -> 16#9C; gbx(16#15) -> 16#97; gbx(16#16) -> 16#8A; gbx(16#17) -> 16#81; gbx(16#18) -> 16#E8; gbx(16#19) -> 16#E3; gbx(16#1A) -> 16#FE; gbx(16#1B) -> 16#F5; gbx(16#1C) -> 16#C4; gbx(16#1D) -> 16#CF; gbx(16#1E) -> 16#D2; gbx(16#1F) -> 16#D9; gbx(16#20) -> 16#7B; gbx(16#21) -> 16#70; gbx(16#22) -> 16#6D; gbx(16#23) -> 16#66; gbx(16#24) -> 16#57; gbx(16#25) -> 16#5C; gbx(16#26) -> 16#41; gbx(16#27) -> 16#4A; gbx(16#28) -> 16#23; gbx(16#29) -> 16#28; gbx(16#2A) -> 16#35; gbx(16#2B) -> 16#3E; gbx(16#2C) -> 16#0F; gbx(16#2D) -> 16#04; gbx(16#2E) -> 16#19; gbx(16#2F) -> 16#12; gbx(16#30) -> 16#CB; gbx(16#31) -> 16#C0; gbx(16#32) -> 16#DD; gbx(16#33) -> 16#D6; gbx(16#34) -> 16#E7; gbx(16#35) -> 16#EC; gbx(16#36) -> 16#F1; gbx(16#37) -> 16#FA; gbx(16#38) -> 16#93; gbx(16#39) -> 16#98; gbx(16#3A) -> 16#85; gbx(16#3B) -> 16#8E; gbx(16#3C) -> 16#BF; gbx(16#3D) -> 16#B4; gbx(16#3E) -> 16#A9; gbx(16#3F) -> 16#A2; gbx(16#40) -> 16#F6; gbx(16#41) -> 16#FD; gbx(16#42) -> 16#E0; gbx(16#43) -> 16#EB; gbx(16#44) -> 16#DA; gbx(16#45) -> 16#D1; gbx(16#46) -> 16#CC; gbx(16#47) -> 16#C7; gbx(16#48) -> 16#AE; gbx(16#49) -> 16#A5; gbx(16#4A) -> 16#B8; gbx(16#4B) -> 16#B3; gbx(16#4C) -> 16#82; gbx(16#4D) -> 16#89; gbx(16#4E) -> 16#94; gbx(16#4F) -> 16#9F; gbx(16#50) -> 16#46; gbx(16#51) -> 16#4D; gbx(16#52) -> 16#50; gbx(16#53) -> 16#5B; gbx(16#54) -> 16#6A; gbx(16#55) -> 16#61; gbx(16#56) -> 16#7C; gbx(16#57) -> 16#77; gbx(16#58) -> 16#1E; gbx(16#59) -> 16#15; gbx(16#5A) -> 16#08; gbx(16#5B) -> 16#03; gbx(16#5C) -> 16#32; gbx(16#5D) -> 16#39; gbx(16#5E) -> 16#24; gbx(16#5F) -> 16#2F; gbx(16#60) -> 16#8D; gbx(16#61) -> 16#86; gbx(16#62) -> 16#9B; gbx(16#63) -> 16#90; gbx(16#64) -> 16#A1; gbx(16#65) -> 16#AA; gbx(16#66) -> 16#B7; gbx(16#67) -> 16#BC; gbx(16#68) -> 16#D5; gbx(16#69) -> 16#DE; gbx(16#6A) -> 16#C3; gbx(16#6B) -> 16#C8; gbx(16#6C) -> 16#F9; gbx(16#6D) -> 16#F2; gbx(16#6E) -> 16#EF; gbx(16#6F) -> 16#E4; gbx(16#70) -> 16#3D; gbx(16#71) -> 16#36; gbx(16#72) -> 16#2B; gbx(16#73) -> 16#20; gbx(16#74) -> 16#11; gbx(16#75) -> 16#1A; gbx(16#76) -> 16#07; gbx(16#77) -> 16#0C; gbx(16#78) -> 16#65; gbx(16#79) -> 16#6E; gbx(16#7A) -> 16#73; gbx(16#7B) -> 16#78; gbx(16#7C) -> 16#49; gbx(16#7D) -> 16#42; gbx(16#7E) -> 16#5F; gbx(16#7F) -> 16#54; gbx(16#80) -> 16#F7; gbx(16#81) -> 16#FC; gbx(16#82) -> 16#E1; gbx(16#83) -> 16#EA; gbx(16#84) -> 16#DB; gbx(16#85) -> 16#D0; gbx(16#86) -> 16#CD; gbx(16#87) -> 16#C6; gbx(16#88) -> 16#AF; gbx(16#89) -> 16#A4; gbx(16#8A) -> 16#B9; gbx(16#8B) -> 16#B2; gbx(16#8C) -> 16#83; gbx(16#8D) -> 16#88; gbx(16#8E) -> 16#95; gbx(16#8F) -> 16#9E; gbx(16#90) -> 16#47; gbx(16#91) -> 16#4C; gbx(16#92) -> 16#51; gbx(16#93) -> 16#5A; gbx(16#94) -> 16#6B; gbx(16#95) -> 16#60; gbx(16#96) -> 16#7D; gbx(16#97) -> 16#76; gbx(16#98) -> 16#1F; gbx(16#99) -> 16#14; gbx(16#9A) -> 16#09; gbx(16#9B) -> 16#02; gbx(16#9C) -> 16#33; gbx(16#9D) -> 16#38; gbx(16#9E) -> 16#25; gbx(16#9F) -> 16#2E; gbx(16#A0) -> 16#8C; gbx(16#A1) -> 16#87; gbx(16#A2) -> 16#9A; gbx(16#A3) -> 16#91; gbx(16#A4) -> 16#A0; gbx(16#A5) -> 16#AB; gbx(16#A6) -> 16#B6; gbx(16#A7) -> 16#BD; gbx(16#A8) -> 16#D4; gbx(16#A9) -> 16#DF; gbx(16#AA) -> 16#C2; gbx(16#AB) -> 16#C9; gbx(16#AC) -> 16#F8; gbx(16#AD) -> 16#F3; gbx(16#AE) -> 16#EE; gbx(16#AF) -> 16#E5; gbx(16#B0) -> 16#3C; gbx(16#B1) -> 16#37; gbx(16#B2) -> 16#2A; gbx(16#B3) -> 16#21; gbx(16#B4) -> 16#10; gbx(16#B5) -> 16#1B; gbx(16#B6) -> 16#06; gbx(16#B7) -> 16#0D; gbx(16#B8) -> 16#64; gbx(16#B9) -> 16#6F; gbx(16#BA) -> 16#72; gbx(16#BB) -> 16#79; gbx(16#BC) -> 16#48; gbx(16#BD) -> 16#43; gbx(16#BE) -> 16#5E; gbx(16#BF) -> 16#55; gbx(16#C0) -> 16#01; gbx(16#C1) -> 16#0A; gbx(16#C2) -> 16#17; gbx(16#C3) -> 16#1C; gbx(16#C4) -> 16#2D; gbx(16#C5) -> 16#26; gbx(16#C6) -> 16#3B; gbx(16#C7) -> 16#30; gbx(16#C8) -> 16#59; gbx(16#C9) -> 16#52; gbx(16#CA) -> 16#4F; gbx(16#CB) -> 16#44; gbx(16#CC) -> 16#75; gbx(16#CD) -> 16#7E; gbx(16#CE) -> 16#63; gbx(16#CF) -> 16#68; gbx(16#D0) -> 16#B1; gbx(16#D1) -> 16#BA; gbx(16#D2) -> 16#A7; gbx(16#D3) -> 16#AC; gbx(16#D4) -> 16#9D; gbx(16#D5) -> 16#96; gbx(16#D6) -> 16#8B; gbx(16#D7) -> 16#80; gbx(16#D8) -> 16#E9; gbx(16#D9) -> 16#E2; gbx(16#DA) -> 16#FF; gbx(16#DB) -> 16#F4; gbx(16#DC) -> 16#C5; gbx(16#DD) -> 16#CE; gbx(16#DE) -> 16#D3; gbx(16#DF) -> 16#D8; gbx(16#E0) -> 16#7A; gbx(16#E1) -> 16#71; gbx(16#E2) -> 16#6C; gbx(16#E3) -> 16#67; gbx(16#E4) -> 16#56; gbx(16#E5) -> 16#5D; gbx(16#E6) -> 16#40; gbx(16#E7) -> 16#4B; gbx(16#E8) -> 16#22; gbx(16#E9) -> 16#29; gbx(16#EA) -> 16#34; gbx(16#EB) -> 16#3F; gbx(16#EC) -> 16#0E; gbx(16#ED) -> 16#05; gbx(16#EE) -> 16#18; gbx(16#EF) -> 16#13; gbx(16#F0) -> 16#CA; gbx(16#F1) -> 16#C1; gbx(16#F2) -> 16#DC; gbx(16#F3) -> 16#D7; gbx(16#F4) -> 16#E6; gbx(16#F5) -> 16#ED; gbx(16#F6) -> 16#F0; gbx(16#F7) -> 16#FB; gbx(16#F8) -> 16#92; gbx(16#F9) -> 16#99; gbx(16#FA) -> 16#84; gbx(16#FB) -> 16#8F; gbx(16#FC) -> 16#BE; gbx(16#FD) -> 16#B5; gbx(16#FE) -> 16#A8; gbx(16#FF) -> 16#A3. %% @private gdx(16#00) -> 16#00; gdx(16#01) -> 16#0D; gdx(16#02) -> 16#1A; gdx(16#03) -> 16#17; gdx(16#04) -> 16#34; gdx(16#05) -> 16#39; gdx(16#06) -> 16#2E; gdx(16#07) -> 16#23; gdx(16#08) -> 16#68; gdx(16#09) -> 16#65; gdx(16#0A) -> 16#72; gdx(16#0B) -> 16#7F; gdx(16#0C) -> 16#5C; gdx(16#0D) -> 16#51; gdx(16#0E) -> 16#46; gdx(16#0F) -> 16#4B; gdx(16#10) -> 16#D0; gdx(16#11) -> 16#DD; gdx(16#12) -> 16#CA; gdx(16#13) -> 16#C7; gdx(16#14) -> 16#E4; gdx(16#15) -> 16#E9; gdx(16#16) -> 16#FE; gdx(16#17) -> 16#F3; gdx(16#18) -> 16#B8; gdx(16#19) -> 16#B5; gdx(16#1A) -> 16#A2; gdx(16#1B) -> 16#AF; gdx(16#1C) -> 16#8C; gdx(16#1D) -> 16#81; gdx(16#1E) -> 16#96; gdx(16#1F) -> 16#9B; gdx(16#20) -> 16#BB; gdx(16#21) -> 16#B6; gdx(16#22) -> 16#A1; gdx(16#23) -> 16#AC; gdx(16#24) -> 16#8F; gdx(16#25) -> 16#82; gdx(16#26) -> 16#95; gdx(16#27) -> 16#98; gdx(16#28) -> 16#D3; gdx(16#29) -> 16#DE; gdx(16#2A) -> 16#C9; gdx(16#2B) -> 16#C4; gdx(16#2C) -> 16#E7; gdx(16#2D) -> 16#EA; gdx(16#2E) -> 16#FD; gdx(16#2F) -> 16#F0; gdx(16#30) -> 16#6B; gdx(16#31) -> 16#66; gdx(16#32) -> 16#71; gdx(16#33) -> 16#7C; gdx(16#34) -> 16#5F; gdx(16#35) -> 16#52; gdx(16#36) -> 16#45; gdx(16#37) -> 16#48; gdx(16#38) -> 16#03; gdx(16#39) -> 16#0E; gdx(16#3A) -> 16#19; gdx(16#3B) -> 16#14; gdx(16#3C) -> 16#37; gdx(16#3D) -> 16#3A; gdx(16#3E) -> 16#2D; gdx(16#3F) -> 16#20; gdx(16#40) -> 16#6D; gdx(16#41) -> 16#60; gdx(16#42) -> 16#77; gdx(16#43) -> 16#7A; gdx(16#44) -> 16#59; gdx(16#45) -> 16#54; gdx(16#46) -> 16#43; gdx(16#47) -> 16#4E; gdx(16#48) -> 16#05; gdx(16#49) -> 16#08; gdx(16#4A) -> 16#1F; gdx(16#4B) -> 16#12; gdx(16#4C) -> 16#31; gdx(16#4D) -> 16#3C; gdx(16#4E) -> 16#2B; gdx(16#4F) -> 16#26; gdx(16#50) -> 16#BD; gdx(16#51) -> 16#B0; gdx(16#52) -> 16#A7; gdx(16#53) -> 16#AA; gdx(16#54) -> 16#89; gdx(16#55) -> 16#84; gdx(16#56) -> 16#93; gdx(16#57) -> 16#9E; gdx(16#58) -> 16#D5; gdx(16#59) -> 16#D8; gdx(16#5A) -> 16#CF; gdx(16#5B) -> 16#C2; gdx(16#5C) -> 16#E1; gdx(16#5D) -> 16#EC; gdx(16#5E) -> 16#FB; gdx(16#5F) -> 16#F6; gdx(16#60) -> 16#D6; gdx(16#61) -> 16#DB; gdx(16#62) -> 16#CC; gdx(16#63) -> 16#C1; gdx(16#64) -> 16#E2; gdx(16#65) -> 16#EF; gdx(16#66) -> 16#F8; gdx(16#67) -> 16#F5; gdx(16#68) -> 16#BE; gdx(16#69) -> 16#B3; gdx(16#6A) -> 16#A4; gdx(16#6B) -> 16#A9; gdx(16#6C) -> 16#8A; gdx(16#6D) -> 16#87; gdx(16#6E) -> 16#90; gdx(16#6F) -> 16#9D; gdx(16#70) -> 16#06; gdx(16#71) -> 16#0B; gdx(16#72) -> 16#1C; gdx(16#73) -> 16#11; gdx(16#74) -> 16#32; gdx(16#75) -> 16#3F; gdx(16#76) -> 16#28; gdx(16#77) -> 16#25; gdx(16#78) -> 16#6E; gdx(16#79) -> 16#63; gdx(16#7A) -> 16#74; gdx(16#7B) -> 16#79; gdx(16#7C) -> 16#5A; gdx(16#7D) -> 16#57; gdx(16#7E) -> 16#40; gdx(16#7F) -> 16#4D; gdx(16#80) -> 16#DA; gdx(16#81) -> 16#D7; gdx(16#82) -> 16#C0; gdx(16#83) -> 16#CD; gdx(16#84) -> 16#EE; gdx(16#85) -> 16#E3; gdx(16#86) -> 16#F4; gdx(16#87) -> 16#F9; gdx(16#88) -> 16#B2; gdx(16#89) -> 16#BF; gdx(16#8A) -> 16#A8; gdx(16#8B) -> 16#A5; gdx(16#8C) -> 16#86; gdx(16#8D) -> 16#8B; gdx(16#8E) -> 16#9C; gdx(16#8F) -> 16#91; gdx(16#90) -> 16#0A; gdx(16#91) -> 16#07; gdx(16#92) -> 16#10; gdx(16#93) -> 16#1D; gdx(16#94) -> 16#3E; gdx(16#95) -> 16#33; gdx(16#96) -> 16#24; gdx(16#97) -> 16#29; gdx(16#98) -> 16#62; gdx(16#99) -> 16#6F; gdx(16#9A) -> 16#78; gdx(16#9B) -> 16#75; gdx(16#9C) -> 16#56; gdx(16#9D) -> 16#5B; gdx(16#9E) -> 16#4C; gdx(16#9F) -> 16#41; gdx(16#A0) -> 16#61; gdx(16#A1) -> 16#6C; gdx(16#A2) -> 16#7B; gdx(16#A3) -> 16#76; gdx(16#A4) -> 16#55; gdx(16#A5) -> 16#58; gdx(16#A6) -> 16#4F; gdx(16#A7) -> 16#42; gdx(16#A8) -> 16#09; gdx(16#A9) -> 16#04; gdx(16#AA) -> 16#13; gdx(16#AB) -> 16#1E; gdx(16#AC) -> 16#3D; gdx(16#AD) -> 16#30; gdx(16#AE) -> 16#27; gdx(16#AF) -> 16#2A; gdx(16#B0) -> 16#B1; gdx(16#B1) -> 16#BC; gdx(16#B2) -> 16#AB; gdx(16#B3) -> 16#A6; gdx(16#B4) -> 16#85; gdx(16#B5) -> 16#88; gdx(16#B6) -> 16#9F; gdx(16#B7) -> 16#92; gdx(16#B8) -> 16#D9; gdx(16#B9) -> 16#D4; gdx(16#BA) -> 16#C3; gdx(16#BB) -> 16#CE; gdx(16#BC) -> 16#ED; gdx(16#BD) -> 16#E0; gdx(16#BE) -> 16#F7; gdx(16#BF) -> 16#FA; gdx(16#C0) -> 16#B7; gdx(16#C1) -> 16#BA; gdx(16#C2) -> 16#AD; gdx(16#C3) -> 16#A0; gdx(16#C4) -> 16#83; gdx(16#C5) -> 16#8E; gdx(16#C6) -> 16#99; gdx(16#C7) -> 16#94; gdx(16#C8) -> 16#DF; gdx(16#C9) -> 16#D2; gdx(16#CA) -> 16#C5; gdx(16#CB) -> 16#C8; gdx(16#CC) -> 16#EB; gdx(16#CD) -> 16#E6; gdx(16#CE) -> 16#F1; gdx(16#CF) -> 16#FC; gdx(16#D0) -> 16#67; gdx(16#D1) -> 16#6A; gdx(16#D2) -> 16#7D; gdx(16#D3) -> 16#70; gdx(16#D4) -> 16#53; gdx(16#D5) -> 16#5E; gdx(16#D6) -> 16#49; gdx(16#D7) -> 16#44; gdx(16#D8) -> 16#0F; gdx(16#D9) -> 16#02; gdx(16#DA) -> 16#15; gdx(16#DB) -> 16#18; gdx(16#DC) -> 16#3B; gdx(16#DD) -> 16#36; gdx(16#DE) -> 16#21; gdx(16#DF) -> 16#2C; gdx(16#E0) -> 16#0C; gdx(16#E1) -> 16#01; gdx(16#E2) -> 16#16; gdx(16#E3) -> 16#1B; gdx(16#E4) -> 16#38; gdx(16#E5) -> 16#35; gdx(16#E6) -> 16#22; gdx(16#E7) -> 16#2F; gdx(16#E8) -> 16#64; gdx(16#E9) -> 16#69; gdx(16#EA) -> 16#7E; gdx(16#EB) -> 16#73; gdx(16#EC) -> 16#50; gdx(16#ED) -> 16#5D; gdx(16#EE) -> 16#4A; gdx(16#EF) -> 16#47; gdx(16#F0) -> 16#DC; gdx(16#F1) -> 16#D1; gdx(16#F2) -> 16#C6; gdx(16#F3) -> 16#CB; gdx(16#F4) -> 16#E8; gdx(16#F5) -> 16#E5; gdx(16#F6) -> 16#F2; gdx(16#F7) -> 16#FF; gdx(16#F8) -> 16#B4; gdx(16#F9) -> 16#B9; gdx(16#FA) -> 16#AE; gdx(16#FB) -> 16#A3; gdx(16#FC) -> 16#80; gdx(16#FD) -> 16#8D; gdx(16#FE) -> 16#9A; gdx(16#FF) -> 16#97. %% @private gex(16#00) -> 16#00; gex(16#01) -> 16#0E; gex(16#02) -> 16#1C; gex(16#03) -> 16#12; gex(16#04) -> 16#38; gex(16#05) -> 16#36; gex(16#06) -> 16#24; gex(16#07) -> 16#2A; gex(16#08) -> 16#70; gex(16#09) -> 16#7E; gex(16#0A) -> 16#6C; gex(16#0B) -> 16#62; gex(16#0C) -> 16#48; gex(16#0D) -> 16#46; gex(16#0E) -> 16#54; gex(16#0F) -> 16#5A; gex(16#10) -> 16#E0; gex(16#11) -> 16#EE; gex(16#12) -> 16#FC; gex(16#13) -> 16#F2; gex(16#14) -> 16#D8; gex(16#15) -> 16#D6; gex(16#16) -> 16#C4; gex(16#17) -> 16#CA; gex(16#18) -> 16#90; gex(16#19) -> 16#9E; gex(16#1A) -> 16#8C; gex(16#1B) -> 16#82; gex(16#1C) -> 16#A8; gex(16#1D) -> 16#A6; gex(16#1E) -> 16#B4; gex(16#1F) -> 16#BA; gex(16#20) -> 16#DB; gex(16#21) -> 16#D5; gex(16#22) -> 16#C7; gex(16#23) -> 16#C9; gex(16#24) -> 16#E3; gex(16#25) -> 16#ED; gex(16#26) -> 16#FF; gex(16#27) -> 16#F1; gex(16#28) -> 16#AB; gex(16#29) -> 16#A5; gex(16#2A) -> 16#B7; gex(16#2B) -> 16#B9; gex(16#2C) -> 16#93; gex(16#2D) -> 16#9D; gex(16#2E) -> 16#8F; gex(16#2F) -> 16#81; gex(16#30) -> 16#3B; gex(16#31) -> 16#35; gex(16#32) -> 16#27; gex(16#33) -> 16#29; gex(16#34) -> 16#03; gex(16#35) -> 16#0D; gex(16#36) -> 16#1F; gex(16#37) -> 16#11; gex(16#38) -> 16#4B; gex(16#39) -> 16#45; gex(16#3A) -> 16#57; gex(16#3B) -> 16#59; gex(16#3C) -> 16#73; gex(16#3D) -> 16#7D; gex(16#3E) -> 16#6F; gex(16#3F) -> 16#61; gex(16#40) -> 16#AD; gex(16#41) -> 16#A3; gex(16#42) -> 16#B1; gex(16#43) -> 16#BF; gex(16#44) -> 16#95; gex(16#45) -> 16#9B; gex(16#46) -> 16#89; gex(16#47) -> 16#87; gex(16#48) -> 16#DD; gex(16#49) -> 16#D3; gex(16#4A) -> 16#C1; gex(16#4B) -> 16#CF; gex(16#4C) -> 16#E5; gex(16#4D) -> 16#EB; gex(16#4E) -> 16#F9; gex(16#4F) -> 16#F7; gex(16#50) -> 16#4D; gex(16#51) -> 16#43; gex(16#52) -> 16#51; gex(16#53) -> 16#5F; gex(16#54) -> 16#75; gex(16#55) -> 16#7B; gex(16#56) -> 16#69; gex(16#57) -> 16#67; gex(16#58) -> 16#3D; gex(16#59) -> 16#33; gex(16#5A) -> 16#21; gex(16#5B) -> 16#2F; gex(16#5C) -> 16#05; gex(16#5D) -> 16#0B; gex(16#5E) -> 16#19; gex(16#5F) -> 16#17; gex(16#60) -> 16#76; gex(16#61) -> 16#78; gex(16#62) -> 16#6A; gex(16#63) -> 16#64; gex(16#64) -> 16#4E; gex(16#65) -> 16#40; gex(16#66) -> 16#52; gex(16#67) -> 16#5C; gex(16#68) -> 16#06; gex(16#69) -> 16#08; gex(16#6A) -> 16#1A; gex(16#6B) -> 16#14; gex(16#6C) -> 16#3E; gex(16#6D) -> 16#30; gex(16#6E) -> 16#22; gex(16#6F) -> 16#2C; gex(16#70) -> 16#96; gex(16#71) -> 16#98; gex(16#72) -> 16#8A; gex(16#73) -> 16#84; gex(16#74) -> 16#AE; gex(16#75) -> 16#A0; gex(16#76) -> 16#B2; gex(16#77) -> 16#BC; gex(16#78) -> 16#E6; gex(16#79) -> 16#E8; gex(16#7A) -> 16#FA; gex(16#7B) -> 16#F4; gex(16#7C) -> 16#DE; gex(16#7D) -> 16#D0; gex(16#7E) -> 16#C2; gex(16#7F) -> 16#CC; gex(16#80) -> 16#41; gex(16#81) -> 16#4F; gex(16#82) -> 16#5D; gex(16#83) -> 16#53; gex(16#84) -> 16#79; gex(16#85) -> 16#77; gex(16#86) -> 16#65; gex(16#87) -> 16#6B; gex(16#88) -> 16#31; gex(16#89) -> 16#3F; gex(16#8A) -> 16#2D; gex(16#8B) -> 16#23; gex(16#8C) -> 16#09; gex(16#8D) -> 16#07; gex(16#8E) -> 16#15; gex(16#8F) -> 16#1B; gex(16#90) -> 16#A1; gex(16#91) -> 16#AF; gex(16#92) -> 16#BD; gex(16#93) -> 16#B3; gex(16#94) -> 16#99; gex(16#95) -> 16#97; gex(16#96) -> 16#85; gex(16#97) -> 16#8B; gex(16#98) -> 16#D1; gex(16#99) -> 16#DF; gex(16#9A) -> 16#CD; gex(16#9B) -> 16#C3; gex(16#9C) -> 16#E9; gex(16#9D) -> 16#E7; gex(16#9E) -> 16#F5; gex(16#9F) -> 16#FB; gex(16#A0) -> 16#9A; gex(16#A1) -> 16#94; gex(16#A2) -> 16#86; gex(16#A3) -> 16#88; gex(16#A4) -> 16#A2; gex(16#A5) -> 16#AC; gex(16#A6) -> 16#BE; gex(16#A7) -> 16#B0; gex(16#A8) -> 16#EA; gex(16#A9) -> 16#E4; gex(16#AA) -> 16#F6; gex(16#AB) -> 16#F8; gex(16#AC) -> 16#D2; gex(16#AD) -> 16#DC; gex(16#AE) -> 16#CE; gex(16#AF) -> 16#C0; gex(16#B0) -> 16#7A; gex(16#B1) -> 16#74; gex(16#B2) -> 16#66; gex(16#B3) -> 16#68; gex(16#B4) -> 16#42; gex(16#B5) -> 16#4C; gex(16#B6) -> 16#5E; gex(16#B7) -> 16#50; gex(16#B8) -> 16#0A; gex(16#B9) -> 16#04; gex(16#BA) -> 16#16; gex(16#BB) -> 16#18; gex(16#BC) -> 16#32; gex(16#BD) -> 16#3C; gex(16#BE) -> 16#2E; gex(16#BF) -> 16#20; gex(16#C0) -> 16#EC; gex(16#C1) -> 16#E2; gex(16#C2) -> 16#F0; gex(16#C3) -> 16#FE; gex(16#C4) -> 16#D4; gex(16#C5) -> 16#DA; gex(16#C6) -> 16#C8; gex(16#C7) -> 16#C6; gex(16#C8) -> 16#9C; gex(16#C9) -> 16#92; gex(16#CA) -> 16#80; gex(16#CB) -> 16#8E; gex(16#CC) -> 16#A4; gex(16#CD) -> 16#AA; gex(16#CE) -> 16#B8; gex(16#CF) -> 16#B6; gex(16#D0) -> 16#0C; gex(16#D1) -> 16#02; gex(16#D2) -> 16#10; gex(16#D3) -> 16#1E; gex(16#D4) -> 16#34; gex(16#D5) -> 16#3A; gex(16#D6) -> 16#28; gex(16#D7) -> 16#26; gex(16#D8) -> 16#7C; gex(16#D9) -> 16#72; gex(16#DA) -> 16#60; gex(16#DB) -> 16#6E; gex(16#DC) -> 16#44; gex(16#DD) -> 16#4A; gex(16#DE) -> 16#58; gex(16#DF) -> 16#56; gex(16#E0) -> 16#37; gex(16#E1) -> 16#39; gex(16#E2) -> 16#2B; gex(16#E3) -> 16#25; gex(16#E4) -> 16#0F; gex(16#E5) -> 16#01; gex(16#E6) -> 16#13; gex(16#E7) -> 16#1D; gex(16#E8) -> 16#47; gex(16#E9) -> 16#49; gex(16#EA) -> 16#5B; gex(16#EB) -> 16#55; gex(16#EC) -> 16#7F; gex(16#ED) -> 16#71; gex(16#EE) -> 16#63; gex(16#EF) -> 16#6D; gex(16#F0) -> 16#D7; gex(16#F1) -> 16#D9; gex(16#F2) -> 16#CB; gex(16#F3) -> 16#C5; gex(16#F4) -> 16#EF; gex(16#F5) -> 16#E1; gex(16#F6) -> 16#F3; gex(16#F7) -> 16#FD; gex(16#F8) -> 16#A7; gex(16#F9) -> 16#A9; gex(16#FA) -> 16#BB; gex(16#FB) -> 16#B5; gex(16#FC) -> 16#9F; gex(16#FD) -> 16#91; gex(16#FE) -> 16#83; gex(16#FF) -> 16#8D. %% @private isBox(16#00) -> 16#52; isBox(16#01) -> 16#09; isBox(16#02) -> 16#6A; isBox(16#03) -> 16#D5; isBox(16#04) -> 16#30; isBox(16#05) -> 16#36; isBox(16#06) -> 16#A5; isBox(16#07) -> 16#38; isBox(16#08) -> 16#BF; isBox(16#09) -> 16#40; isBox(16#0A) -> 16#A3; isBox(16#0B) -> 16#9E; isBox(16#0C) -> 16#81; isBox(16#0D) -> 16#F3; isBox(16#0E) -> 16#D7; isBox(16#0F) -> 16#FB; isBox(16#10) -> 16#7C; isBox(16#11) -> 16#E3; isBox(16#12) -> 16#39; isBox(16#13) -> 16#82; isBox(16#14) -> 16#9B; isBox(16#15) -> 16#2F; isBox(16#16) -> 16#FF; isBox(16#17) -> 16#87; isBox(16#18) -> 16#34; isBox(16#19) -> 16#8E; isBox(16#1A) -> 16#43; isBox(16#1B) -> 16#44; isBox(16#1C) -> 16#C4; isBox(16#1D) -> 16#DE; isBox(16#1E) -> 16#E9; isBox(16#1F) -> 16#CB; isBox(16#20) -> 16#54; isBox(16#21) -> 16#7B; isBox(16#22) -> 16#94; isBox(16#23) -> 16#32; isBox(16#24) -> 16#A6; isBox(16#25) -> 16#C2; isBox(16#26) -> 16#23; isBox(16#27) -> 16#3D; isBox(16#28) -> 16#EE; isBox(16#29) -> 16#4C; isBox(16#2A) -> 16#95; isBox(16#2B) -> 16#0B; isBox(16#2C) -> 16#42; isBox(16#2D) -> 16#FA; isBox(16#2E) -> 16#C3; isBox(16#2F) -> 16#4E; isBox(16#30) -> 16#08; isBox(16#31) -> 16#2E; isBox(16#32) -> 16#A1; isBox(16#33) -> 16#66; isBox(16#34) -> 16#28; isBox(16#35) -> 16#D9; isBox(16#36) -> 16#24; isBox(16#37) -> 16#B2; isBox(16#38) -> 16#76; isBox(16#39) -> 16#5B; isBox(16#3A) -> 16#A2; isBox(16#3B) -> 16#49; isBox(16#3C) -> 16#6D; isBox(16#3D) -> 16#8B; isBox(16#3E) -> 16#D1; isBox(16#3F) -> 16#25; isBox(16#40) -> 16#72; isBox(16#41) -> 16#F8; isBox(16#42) -> 16#F6; isBox(16#43) -> 16#64; isBox(16#44) -> 16#86; isBox(16#45) -> 16#68; isBox(16#46) -> 16#98; isBox(16#47) -> 16#16; isBox(16#48) -> 16#D4; isBox(16#49) -> 16#A4; isBox(16#4A) -> 16#5C; isBox(16#4B) -> 16#CC; isBox(16#4C) -> 16#5D; isBox(16#4D) -> 16#65; isBox(16#4E) -> 16#B6; isBox(16#4F) -> 16#92; isBox(16#50) -> 16#6C; isBox(16#51) -> 16#70; isBox(16#52) -> 16#48; isBox(16#53) -> 16#50; isBox(16#54) -> 16#FD; isBox(16#55) -> 16#ED; isBox(16#56) -> 16#B9; isBox(16#57) -> 16#DA; isBox(16#58) -> 16#5E; isBox(16#59) -> 16#15; isBox(16#5A) -> 16#46; isBox(16#5B) -> 16#57; isBox(16#5C) -> 16#A7; isBox(16#5D) -> 16#8D; isBox(16#5E) -> 16#9D; isBox(16#5F) -> 16#84; isBox(16#60) -> 16#90; isBox(16#61) -> 16#D8; isBox(16#62) -> 16#AB; isBox(16#63) -> 16#00; isBox(16#64) -> 16#8C; isBox(16#65) -> 16#BC; isBox(16#66) -> 16#D3; isBox(16#67) -> 16#0A; isBox(16#68) -> 16#F7; isBox(16#69) -> 16#E4; isBox(16#6A) -> 16#58; isBox(16#6B) -> 16#05; isBox(16#6C) -> 16#B8; isBox(16#6D) -> 16#B3; isBox(16#6E) -> 16#45; isBox(16#6F) -> 16#06; isBox(16#70) -> 16#D0; isBox(16#71) -> 16#2C; isBox(16#72) -> 16#1E; isBox(16#73) -> 16#8F; isBox(16#74) -> 16#CA; isBox(16#75) -> 16#3F; isBox(16#76) -> 16#0F; isBox(16#77) -> 16#02; isBox(16#78) -> 16#C1; isBox(16#79) -> 16#AF; isBox(16#7A) -> 16#BD; isBox(16#7B) -> 16#03; isBox(16#7C) -> 16#01; isBox(16#7D) -> 16#13; isBox(16#7E) -> 16#8A; isBox(16#7F) -> 16#6B; isBox(16#80) -> 16#3A; isBox(16#81) -> 16#91; isBox(16#82) -> 16#11; isBox(16#83) -> 16#41; isBox(16#84) -> 16#4F; isBox(16#85) -> 16#67; isBox(16#86) -> 16#DC; isBox(16#87) -> 16#EA; isBox(16#88) -> 16#97; isBox(16#89) -> 16#F2; isBox(16#8A) -> 16#CF; isBox(16#8B) -> 16#CE; isBox(16#8C) -> 16#F0; isBox(16#8D) -> 16#B4; isBox(16#8E) -> 16#E6; isBox(16#8F) -> 16#73; isBox(16#90) -> 16#96; isBox(16#91) -> 16#AC; isBox(16#92) -> 16#74; isBox(16#93) -> 16#22; isBox(16#94) -> 16#E7; isBox(16#95) -> 16#AD; isBox(16#96) -> 16#35; isBox(16#97) -> 16#85; isBox(16#98) -> 16#E2; isBox(16#99) -> 16#F9; isBox(16#9A) -> 16#37; isBox(16#9B) -> 16#E8; isBox(16#9C) -> 16#1C; isBox(16#9D) -> 16#75; isBox(16#9E) -> 16#DF; isBox(16#9F) -> 16#6E; isBox(16#A0) -> 16#47; isBox(16#A1) -> 16#F1; isBox(16#A2) -> 16#1A; isBox(16#A3) -> 16#71; isBox(16#A4) -> 16#1D; isBox(16#A5) -> 16#29; isBox(16#A6) -> 16#C5; isBox(16#A7) -> 16#89; isBox(16#A8) -> 16#6F; isBox(16#A9) -> 16#B7; isBox(16#AA) -> 16#62; isBox(16#AB) -> 16#0E; isBox(16#AC) -> 16#AA; isBox(16#AD) -> 16#18; isBox(16#AE) -> 16#BE; isBox(16#AF) -> 16#1B; isBox(16#B0) -> 16#FC; isBox(16#B1) -> 16#56; isBox(16#B2) -> 16#3E; isBox(16#B3) -> 16#4B; isBox(16#B4) -> 16#C6; isBox(16#B5) -> 16#D2; isBox(16#B6) -> 16#79; isBox(16#B7) -> 16#20; isBox(16#B8) -> 16#9A; isBox(16#B9) -> 16#DB; isBox(16#BA) -> 16#C0; isBox(16#BB) -> 16#FE; isBox(16#BC) -> 16#78; isBox(16#BD) -> 16#CD; isBox(16#BE) -> 16#5A; isBox(16#BF) -> 16#F4; isBox(16#C0) -> 16#1F; isBox(16#C1) -> 16#DD; isBox(16#C2) -> 16#A8; isBox(16#C3) -> 16#33; isBox(16#C4) -> 16#88; isBox(16#C5) -> 16#07; isBox(16#C6) -> 16#C7; isBox(16#C7) -> 16#31; isBox(16#C8) -> 16#B1; isBox(16#C9) -> 16#12; isBox(16#CA) -> 16#10; isBox(16#CB) -> 16#59; isBox(16#CC) -> 16#27; isBox(16#CD) -> 16#80; isBox(16#CE) -> 16#EC; isBox(16#CF) -> 16#5F; isBox(16#D0) -> 16#60; isBox(16#D1) -> 16#51; isBox(16#D2) -> 16#7F; isBox(16#D3) -> 16#A9; isBox(16#D4) -> 16#19; isBox(16#D5) -> 16#B5; isBox(16#D6) -> 16#4A; isBox(16#D7) -> 16#0D; isBox(16#D8) -> 16#2D; isBox(16#D9) -> 16#E5; isBox(16#DA) -> 16#7A; isBox(16#DB) -> 16#9F; isBox(16#DC) -> 16#93; isBox(16#DD) -> 16#C9; isBox(16#DE) -> 16#9C; isBox(16#DF) -> 16#EF; isBox(16#E0) -> 16#A0; isBox(16#E1) -> 16#E0; isBox(16#E2) -> 16#3B; isBox(16#E3) -> 16#4D; isBox(16#E4) -> 16#AE; isBox(16#E5) -> 16#2A; isBox(16#E6) -> 16#F5; isBox(16#E7) -> 16#B0; isBox(16#E8) -> 16#C8; isBox(16#E9) -> 16#EB; isBox(16#EA) -> 16#BB; isBox(16#EB) -> 16#3C; isBox(16#EC) -> 16#83; isBox(16#ED) -> 16#53; isBox(16#EE) -> 16#99; isBox(16#EF) -> 16#61; isBox(16#F0) -> 16#17; isBox(16#F1) -> 16#2B; isBox(16#F2) -> 16#04; isBox(16#F3) -> 16#7E; isBox(16#F4) -> 16#BA; isBox(16#F5) -> 16#77; isBox(16#F6) -> 16#D6; isBox(16#F7) -> 16#26; isBox(16#F8) -> 16#E1; isBox(16#F9) -> 16#69; isBox(16#FA) -> 16#14; isBox(16#FB) -> 16#63; isBox(16#FC) -> 16#55; isBox(16#FD) -> 16#21; isBox(16#FE) -> 16#0C; isBox(16#FF) -> 16#7D. %% @private rcon(16#00) -> 16#8D; rcon(16#01) -> 16#01; rcon(16#02) -> 16#02; rcon(16#03) -> 16#04; rcon(16#04) -> 16#08; rcon(16#05) -> 16#10; rcon(16#06) -> 16#20; rcon(16#07) -> 16#40; rcon(16#08) -> 16#80; rcon(16#09) -> 16#1B; rcon(16#0A) -> 16#36; rcon(16#0B) -> 16#6C; rcon(16#0C) -> 16#D8; rcon(16#0D) -> 16#AB; rcon(16#0E) -> 16#4D; rcon(16#0F) -> 16#9A; rcon(16#10) -> 16#2F; rcon(16#11) -> 16#5E; rcon(16#12) -> 16#BC; rcon(16#13) -> 16#63; rcon(16#14) -> 16#C6; rcon(16#15) -> 16#97; rcon(16#16) -> 16#35; rcon(16#17) -> 16#6A; rcon(16#18) -> 16#D4; rcon(16#19) -> 16#B3; rcon(16#1A) -> 16#7D; rcon(16#1B) -> 16#FA; rcon(16#1C) -> 16#EF; rcon(16#1D) -> 16#C5; rcon(16#1E) -> 16#91; rcon(16#1F) -> 16#39; rcon(16#20) -> 16#72; rcon(16#21) -> 16#E4; rcon(16#22) -> 16#D3; rcon(16#23) -> 16#BD; rcon(16#24) -> 16#61; rcon(16#25) -> 16#C2; rcon(16#26) -> 16#9F; rcon(16#27) -> 16#25; rcon(16#28) -> 16#4A; rcon(16#29) -> 16#94; rcon(16#2A) -> 16#33; rcon(16#2B) -> 16#66; rcon(16#2C) -> 16#CC; rcon(16#2D) -> 16#83; rcon(16#2E) -> 16#1D; rcon(16#2F) -> 16#3A; rcon(16#30) -> 16#74; rcon(16#31) -> 16#E8; rcon(16#32) -> 16#CB; rcon(16#33) -> 16#8D; rcon(16#34) -> 16#01; rcon(16#35) -> 16#02; rcon(16#36) -> 16#04; rcon(16#37) -> 16#08; rcon(16#38) -> 16#10; rcon(16#39) -> 16#20; rcon(16#3A) -> 16#40; rcon(16#3B) -> 16#80; rcon(16#3C) -> 16#1B; rcon(16#3D) -> 16#36; rcon(16#3E) -> 16#6C; rcon(16#3F) -> 16#D8; rcon(16#40) -> 16#AB; rcon(16#41) -> 16#4D; rcon(16#42) -> 16#9A; rcon(16#43) -> 16#2F; rcon(16#44) -> 16#5E; rcon(16#45) -> 16#BC; rcon(16#46) -> 16#63; rcon(16#47) -> 16#C6; rcon(16#48) -> 16#97; rcon(16#49) -> 16#35; rcon(16#4A) -> 16#6A; rcon(16#4B) -> 16#D4; rcon(16#4C) -> 16#B3; rcon(16#4D) -> 16#7D; rcon(16#4E) -> 16#FA; rcon(16#4F) -> 16#EF; rcon(16#50) -> 16#C5; rcon(16#51) -> 16#91; rcon(16#52) -> 16#39; rcon(16#53) -> 16#72; rcon(16#54) -> 16#E4; rcon(16#55) -> 16#D3; rcon(16#56) -> 16#BD; rcon(16#57) -> 16#61; rcon(16#58) -> 16#C2; rcon(16#59) -> 16#9F; rcon(16#5A) -> 16#25; rcon(16#5B) -> 16#4A; rcon(16#5C) -> 16#94; rcon(16#5D) -> 16#33; rcon(16#5E) -> 16#66; rcon(16#5F) -> 16#CC; rcon(16#60) -> 16#83; rcon(16#61) -> 16#1D; rcon(16#62) -> 16#3A; rcon(16#63) -> 16#74; rcon(16#64) -> 16#E8; rcon(16#65) -> 16#CB; rcon(16#66) -> 16#8D; rcon(16#67) -> 16#01; rcon(16#68) -> 16#02; rcon(16#69) -> 16#04; rcon(16#6A) -> 16#08; rcon(16#6B) -> 16#10; rcon(16#6C) -> 16#20; rcon(16#6D) -> 16#40; rcon(16#6E) -> 16#80; rcon(16#6F) -> 16#1B; rcon(16#70) -> 16#36; rcon(16#71) -> 16#6C; rcon(16#72) -> 16#D8; rcon(16#73) -> 16#AB; rcon(16#74) -> 16#4D; rcon(16#75) -> 16#9A; rcon(16#76) -> 16#2F; rcon(16#77) -> 16#5E; rcon(16#78) -> 16#BC; rcon(16#79) -> 16#63; rcon(16#7A) -> 16#C6; rcon(16#7B) -> 16#97; rcon(16#7C) -> 16#35; rcon(16#7D) -> 16#6A; rcon(16#7E) -> 16#D4; rcon(16#7F) -> 16#B3; rcon(16#80) -> 16#7D; rcon(16#81) -> 16#FA; rcon(16#82) -> 16#EF; rcon(16#83) -> 16#C5; rcon(16#84) -> 16#91; rcon(16#85) -> 16#39; rcon(16#86) -> 16#72; rcon(16#87) -> 16#E4; rcon(16#88) -> 16#D3; rcon(16#89) -> 16#BD; rcon(16#8A) -> 16#61; rcon(16#8B) -> 16#C2; rcon(16#8C) -> 16#9F; rcon(16#8D) -> 16#25; rcon(16#8E) -> 16#4A; rcon(16#8F) -> 16#94; rcon(16#90) -> 16#33; rcon(16#91) -> 16#66; rcon(16#92) -> 16#CC; rcon(16#93) -> 16#83; rcon(16#94) -> 16#1D; rcon(16#95) -> 16#3A; rcon(16#96) -> 16#74; rcon(16#97) -> 16#E8; rcon(16#98) -> 16#CB; rcon(16#99) -> 16#8D; rcon(16#9A) -> 16#01; rcon(16#9B) -> 16#02; rcon(16#9C) -> 16#04; rcon(16#9D) -> 16#08; rcon(16#9E) -> 16#10; rcon(16#9F) -> 16#20; rcon(16#A0) -> 16#40; rcon(16#A1) -> 16#80; rcon(16#A2) -> 16#1B; rcon(16#A3) -> 16#36; rcon(16#A4) -> 16#6C; rcon(16#A5) -> 16#D8; rcon(16#A6) -> 16#AB; rcon(16#A7) -> 16#4D; rcon(16#A8) -> 16#9A; rcon(16#A9) -> 16#2F; rcon(16#AA) -> 16#5E; rcon(16#AB) -> 16#BC; rcon(16#AC) -> 16#63; rcon(16#AD) -> 16#C6; rcon(16#AE) -> 16#97; rcon(16#AF) -> 16#35; rcon(16#B0) -> 16#6A; rcon(16#B1) -> 16#D4; rcon(16#B2) -> 16#B3; rcon(16#B3) -> 16#7D; rcon(16#B4) -> 16#FA; rcon(16#B5) -> 16#EF; rcon(16#B6) -> 16#C5; rcon(16#B7) -> 16#91; rcon(16#B8) -> 16#39; rcon(16#B9) -> 16#72; rcon(16#BA) -> 16#E4; rcon(16#BB) -> 16#D3; rcon(16#BC) -> 16#BD; rcon(16#BD) -> 16#61; rcon(16#BE) -> 16#C2; rcon(16#BF) -> 16#9F; rcon(16#C0) -> 16#25; rcon(16#C1) -> 16#4A; rcon(16#C2) -> 16#94; rcon(16#C3) -> 16#33; rcon(16#C4) -> 16#66; rcon(16#C5) -> 16#CC; rcon(16#C6) -> 16#83; rcon(16#C7) -> 16#1D; rcon(16#C8) -> 16#3A; rcon(16#C9) -> 16#74; rcon(16#CA) -> 16#E8; rcon(16#CB) -> 16#CB; rcon(16#CC) -> 16#8D; rcon(16#CD) -> 16#01; rcon(16#CE) -> 16#02; rcon(16#CF) -> 16#04; rcon(16#D0) -> 16#08; rcon(16#D1) -> 16#10; rcon(16#D2) -> 16#20; rcon(16#D3) -> 16#40; rcon(16#D4) -> 16#80; rcon(16#D5) -> 16#1B; rcon(16#D6) -> 16#36; rcon(16#D7) -> 16#6C; rcon(16#D8) -> 16#D8; rcon(16#D9) -> 16#AB; rcon(16#DA) -> 16#4D; rcon(16#DB) -> 16#9A; rcon(16#DC) -> 16#2F; rcon(16#DD) -> 16#5E; rcon(16#DE) -> 16#BC; rcon(16#DF) -> 16#63; rcon(16#E0) -> 16#C6; rcon(16#E1) -> 16#97; rcon(16#E2) -> 16#35; rcon(16#E3) -> 16#6A; rcon(16#E4) -> 16#D4; rcon(16#E5) -> 16#B3; rcon(16#E6) -> 16#7D; rcon(16#E7) -> 16#FA; rcon(16#E8) -> 16#EF; rcon(16#E9) -> 16#C5; rcon(16#EA) -> 16#91; rcon(16#EB) -> 16#39; rcon(16#EC) -> 16#72; rcon(16#ED) -> 16#E4; rcon(16#EE) -> 16#D3; rcon(16#EF) -> 16#BD; rcon(16#F0) -> 16#61; rcon(16#F1) -> 16#C2; rcon(16#F2) -> 16#9F; rcon(16#F3) -> 16#25; rcon(16#F4) -> 16#4A; rcon(16#F5) -> 16#94; rcon(16#F6) -> 16#33; rcon(16#F7) -> 16#66; rcon(16#F8) -> 16#CC; rcon(16#F9) -> 16#83; rcon(16#FA) -> 16#1D; rcon(16#FB) -> 16#3A; rcon(16#FC) -> 16#74; rcon(16#FD) -> 16#E8; rcon(16#FE) -> 16#CB. %% @private sBox(16#00) -> 16#63; sBox(16#01) -> 16#7C; sBox(16#02) -> 16#77; sBox(16#03) -> 16#7B; sBox(16#04) -> 16#F2; sBox(16#05) -> 16#6B; sBox(16#06) -> 16#6F; sBox(16#07) -> 16#C5; sBox(16#08) -> 16#30; sBox(16#09) -> 16#01; sBox(16#0A) -> 16#67; sBox(16#0B) -> 16#2B; sBox(16#0C) -> 16#FE; sBox(16#0D) -> 16#D7; sBox(16#0E) -> 16#AB; sBox(16#0F) -> 16#76; sBox(16#10) -> 16#CA; sBox(16#11) -> 16#82; sBox(16#12) -> 16#C9; sBox(16#13) -> 16#7D; sBox(16#14) -> 16#FA; sBox(16#15) -> 16#59; sBox(16#16) -> 16#47; sBox(16#17) -> 16#F0; sBox(16#18) -> 16#AD; sBox(16#19) -> 16#D4; sBox(16#1A) -> 16#A2; sBox(16#1B) -> 16#AF; sBox(16#1C) -> 16#9C; sBox(16#1D) -> 16#A4; sBox(16#1E) -> 16#72; sBox(16#1F) -> 16#C0; sBox(16#20) -> 16#B7; sBox(16#21) -> 16#FD; sBox(16#22) -> 16#93; sBox(16#23) -> 16#26; sBox(16#24) -> 16#36; sBox(16#25) -> 16#3F; sBox(16#26) -> 16#F7; sBox(16#27) -> 16#CC; sBox(16#28) -> 16#34; sBox(16#29) -> 16#A5; sBox(16#2A) -> 16#E5; sBox(16#2B) -> 16#F1; sBox(16#2C) -> 16#71; sBox(16#2D) -> 16#D8; sBox(16#2E) -> 16#31; sBox(16#2F) -> 16#15; sBox(16#30) -> 16#04; sBox(16#31) -> 16#C7; sBox(16#32) -> 16#23; sBox(16#33) -> 16#C3; sBox(16#34) -> 16#18; sBox(16#35) -> 16#96; sBox(16#36) -> 16#05; sBox(16#37) -> 16#9A; sBox(16#38) -> 16#07; sBox(16#39) -> 16#12; sBox(16#3A) -> 16#80; sBox(16#3B) -> 16#E2; sBox(16#3C) -> 16#EB; sBox(16#3D) -> 16#27; sBox(16#3E) -> 16#B2; sBox(16#3F) -> 16#75; sBox(16#40) -> 16#09; sBox(16#41) -> 16#83; sBox(16#42) -> 16#2C; sBox(16#43) -> 16#1A; sBox(16#44) -> 16#1B; sBox(16#45) -> 16#6E; sBox(16#46) -> 16#5A; sBox(16#47) -> 16#A0; sBox(16#48) -> 16#52; sBox(16#49) -> 16#3B; sBox(16#4A) -> 16#D6; sBox(16#4B) -> 16#B3; sBox(16#4C) -> 16#29; sBox(16#4D) -> 16#E3; sBox(16#4E) -> 16#2F; sBox(16#4F) -> 16#84; sBox(16#50) -> 16#53; sBox(16#51) -> 16#D1; sBox(16#52) -> 16#00; sBox(16#53) -> 16#ED; sBox(16#54) -> 16#20; sBox(16#55) -> 16#FC; sBox(16#56) -> 16#B1; sBox(16#57) -> 16#5B; sBox(16#58) -> 16#6A; sBox(16#59) -> 16#CB; sBox(16#5A) -> 16#BE; sBox(16#5B) -> 16#39; sBox(16#5C) -> 16#4A; sBox(16#5D) -> 16#4C; sBox(16#5E) -> 16#58; sBox(16#5F) -> 16#CF; sBox(16#60) -> 16#D0; sBox(16#61) -> 16#EF; sBox(16#62) -> 16#AA; sBox(16#63) -> 16#FB; sBox(16#64) -> 16#43; sBox(16#65) -> 16#4D; sBox(16#66) -> 16#33; sBox(16#67) -> 16#85; sBox(16#68) -> 16#45; sBox(16#69) -> 16#F9; sBox(16#6A) -> 16#02; sBox(16#6B) -> 16#7F; sBox(16#6C) -> 16#50; sBox(16#6D) -> 16#3C; sBox(16#6E) -> 16#9F; sBox(16#6F) -> 16#A8; sBox(16#70) -> 16#51; sBox(16#71) -> 16#A3; sBox(16#72) -> 16#40; sBox(16#73) -> 16#8F; sBox(16#74) -> 16#92; sBox(16#75) -> 16#9D; sBox(16#76) -> 16#38; sBox(16#77) -> 16#F5; sBox(16#78) -> 16#BC; sBox(16#79) -> 16#B6; sBox(16#7A) -> 16#DA; sBox(16#7B) -> 16#21; sBox(16#7C) -> 16#10; sBox(16#7D) -> 16#FF; sBox(16#7E) -> 16#F3; sBox(16#7F) -> 16#D2; sBox(16#80) -> 16#CD; sBox(16#81) -> 16#0C; sBox(16#82) -> 16#13; sBox(16#83) -> 16#EC; sBox(16#84) -> 16#5F; sBox(16#85) -> 16#97; sBox(16#86) -> 16#44; sBox(16#87) -> 16#17; sBox(16#88) -> 16#C4; sBox(16#89) -> 16#A7; sBox(16#8A) -> 16#7E; sBox(16#8B) -> 16#3D; sBox(16#8C) -> 16#64; sBox(16#8D) -> 16#5D; sBox(16#8E) -> 16#19; sBox(16#8F) -> 16#73; sBox(16#90) -> 16#60; sBox(16#91) -> 16#81; sBox(16#92) -> 16#4F; sBox(16#93) -> 16#DC; sBox(16#94) -> 16#22; sBox(16#95) -> 16#2A; sBox(16#96) -> 16#90; sBox(16#97) -> 16#88; sBox(16#98) -> 16#46; sBox(16#99) -> 16#EE; sBox(16#9A) -> 16#B8; sBox(16#9B) -> 16#14; sBox(16#9C) -> 16#DE; sBox(16#9D) -> 16#5E; sBox(16#9E) -> 16#0B; sBox(16#9F) -> 16#DB; sBox(16#A0) -> 16#E0; sBox(16#A1) -> 16#32; sBox(16#A2) -> 16#3A; sBox(16#A3) -> 16#0A; sBox(16#A4) -> 16#49; sBox(16#A5) -> 16#06; sBox(16#A6) -> 16#24; sBox(16#A7) -> 16#5C; sBox(16#A8) -> 16#C2; sBox(16#A9) -> 16#D3; sBox(16#AA) -> 16#AC; sBox(16#AB) -> 16#62; sBox(16#AC) -> 16#91; sBox(16#AD) -> 16#95; sBox(16#AE) -> 16#E4; sBox(16#AF) -> 16#79; sBox(16#B0) -> 16#E7; sBox(16#B1) -> 16#C8; sBox(16#B2) -> 16#37; sBox(16#B3) -> 16#6D; sBox(16#B4) -> 16#8D; sBox(16#B5) -> 16#D5; sBox(16#B6) -> 16#4E; sBox(16#B7) -> 16#A9; sBox(16#B8) -> 16#6C; sBox(16#B9) -> 16#56; sBox(16#BA) -> 16#F4; sBox(16#BB) -> 16#EA; sBox(16#BC) -> 16#65; sBox(16#BD) -> 16#7A; sBox(16#BE) -> 16#AE; sBox(16#BF) -> 16#08; sBox(16#C0) -> 16#BA; sBox(16#C1) -> 16#78; sBox(16#C2) -> 16#25; sBox(16#C3) -> 16#2E; sBox(16#C4) -> 16#1C; sBox(16#C5) -> 16#A6; sBox(16#C6) -> 16#B4; sBox(16#C7) -> 16#C6; sBox(16#C8) -> 16#E8; sBox(16#C9) -> 16#DD; sBox(16#CA) -> 16#74; sBox(16#CB) -> 16#1F; sBox(16#CC) -> 16#4B; sBox(16#CD) -> 16#BD; sBox(16#CE) -> 16#8B; sBox(16#CF) -> 16#8A; sBox(16#D0) -> 16#70; sBox(16#D1) -> 16#3E; sBox(16#D2) -> 16#B5; sBox(16#D3) -> 16#66; sBox(16#D4) -> 16#48; sBox(16#D5) -> 16#03; sBox(16#D6) -> 16#F6; sBox(16#D7) -> 16#0E; sBox(16#D8) -> 16#61; sBox(16#D9) -> 16#35; sBox(16#DA) -> 16#57; sBox(16#DB) -> 16#B9; sBox(16#DC) -> 16#86; sBox(16#DD) -> 16#C1; sBox(16#DE) -> 16#1D; sBox(16#DF) -> 16#9E; sBox(16#E0) -> 16#E1; sBox(16#E1) -> 16#F8; sBox(16#E2) -> 16#98; sBox(16#E3) -> 16#11; sBox(16#E4) -> 16#69; sBox(16#E5) -> 16#D9; sBox(16#E6) -> 16#8E; sBox(16#E7) -> 16#94; sBox(16#E8) -> 16#9B; sBox(16#E9) -> 16#1E; sBox(16#EA) -> 16#87; sBox(16#EB) -> 16#E9; sBox(16#EC) -> 16#CE; sBox(16#ED) -> 16#55; sBox(16#EE) -> 16#28; sBox(16#EF) -> 16#DF; sBox(16#F0) -> 16#8C; sBox(16#F1) -> 16#A1; sBox(16#F2) -> 16#89; sBox(16#F3) -> 16#0D; sBox(16#F4) -> 16#BF; sBox(16#F5) -> 16#E6; sBox(16#F6) -> 16#42; sBox(16#F7) -> 16#68; sBox(16#F8) -> 16#41; sBox(16#F9) -> 16#99; sBox(16#FA) -> 16#2D; sBox(16#FB) -> 16#0F; sBox(16#FC) -> 16#B0; sBox(16#FD) -> 16#54; sBox(16#FE) -> 16#BB; sBox(16#FF) -> 16#16. erlang-jose-1.10.1/src/jwa/jose_jwa_hchacha20.erl0000644000232200023220000000401013605433351022022 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc XChaCha: eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 %%% See https://tools.ietf.org/html/draft-irtf-cfrg-xchacha %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_hchacha20). %% API -export([hash/2]). %%==================================================================== %% API functions %%==================================================================== hash(Key, Nonce) when is_binary(Key) andalso bit_size(Key) =:= 256 andalso is_binary(Nonce) andalso bit_size(Nonce) =:= 128 -> State = << "expand 32-byte k", Key:256/bitstring, Nonce:128/bitstring >>, WS0 = list_to_tuple([Word || << Word:32/unsigned-little-integer-unit:1 >> <= State]), WS1 = rounds(WS0, 10), serialize(WS1). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private inner_block(State0) when is_tuple(State0) andalso tuple_size(State0) =:= 16 -> State1 = jose_jwa_chacha20:column_round(State0), State2 = jose_jwa_chacha20:diagonal_round(State1), State2. %% @private rounds(S, 0) -> S; rounds(S, N) when is_integer(N) andalso N > 0 -> rounds(inner_block(S), N - 1). %% @private serialize({Z00, Z01, Z02, Z03, _Z04, _Z05, _Z06, _Z07, _Z08, _Z09, _Z10, _Z11, Z12, Z13, Z14, Z15}) -> << Z00:32/unsigned-little-integer-unit:1, Z01:32/unsigned-little-integer-unit:1, Z02:32/unsigned-little-integer-unit:1, Z03:32/unsigned-little-integer-unit:1, Z12:32/unsigned-little-integer-unit:1, Z13:32/unsigned-little-integer-unit:1, Z14:32/unsigned-little-integer-unit:1, Z15:32/unsigned-little-integer-unit:1 >>. erlang-jose-1.10.1/src/jose_block_encryptor.erl0000644000232200023220000000267713605433351022077 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 10 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_block_encryptor). -callback block_decrypt(Cipher, Key, CipherText) -> PlainText | error when Cipher :: {atom(), pos_integer()}, Key :: bitstring(), CipherText :: binary(), PlainText :: binary(). -callback block_encrypt(Cipher, Key, PlainText) -> CipherText when Cipher :: {atom(), pos_integer()}, Key :: bitstring(), PlainText :: binary(), CipherText :: binary(). -optional_callbacks([block_decrypt/3]). -optional_callbacks([block_encrypt/3]). -callback block_decrypt(Cipher, Key, IV, CipherText) -> PlainText | error when Cipher :: {atom(), pos_integer()}, Key :: bitstring(), IV :: bitstring(), CipherText :: binary() | {binary(), binary(), binary()}, PlainText :: binary(). -callback block_encrypt(Cipher, Key, IV, PlainText) -> CipherText when Cipher :: {atom(), pos_integer()}, Key :: bitstring(), IV :: bitstring(), PlainText :: binary() | {binary(), binary()}, CipherText :: binary() | {binary(), binary()}. erlang-jose-1.10.1/src/jose_curve25519_libdecaf.erl0000644000232200023220000000377113605433351022237 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 01 Mar 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_curve25519_libdecaf). -behaviour(jose_curve25519). %% jose_curve25519 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed25519_sign/2]). -export([ed25519_verify/3]). -export([ed25519ph_sign/2]). -export([ed25519ph_verify/3]). -export([x25519_keypair/0]). -export([x25519_keypair/1]). -export([x25519_secret_to_public/1]). -export([x25519_shared_secret/2]). %%==================================================================== %% jose_curve25519 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> libdecaf_curve25519:eddsa_keypair(). eddsa_keypair(Seed) -> libdecaf_curve25519:eddsa_keypair(Seed). eddsa_secret_to_public(SecretKey) -> libdecaf_curve25519:eddsa_secret_to_pk(SecretKey). % Ed25519 ed25519_sign(Message, SecretKey) -> libdecaf_curve25519:ed25519_sign(Message, SecretKey). ed25519_verify(Signature, Message, PublicKey) -> libdecaf_curve25519:ed25519_verify(Signature, Message, PublicKey). % Ed25519ph ed25519ph_sign(Message, SecretKey) -> libdecaf_curve25519:ed25519ph_sign(Message, SecretKey). ed25519ph_verify(Signature, Message, PublicKey) -> libdecaf_curve25519:ed25519ph_verify(Signature, Message, PublicKey). % X25519 x25519_keypair() -> libdecaf_curve25519:x25519_keypair(). x25519_keypair(Seed) -> libdecaf_curve25519:x25519_keypair(Seed). x25519_secret_to_public(SecretKey) -> libdecaf_curve25519:x25519(SecretKey). x25519_shared_secret(MySecretKey, YourPublicKey) -> libdecaf_curve25519:x25519(MySecretKey, YourPublicKey). erlang-jose-1.10.1/src/jose_curve25519_libsodium.erl0000644000232200023220000000440113605433351022464 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 02 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_curve25519_libsodium). -behaviour(jose_curve25519). %% jose_curve25519 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed25519_sign/2]). -export([ed25519_verify/3]). -export([ed25519ph_sign/2]). -export([ed25519ph_verify/3]). -export([x25519_keypair/0]). -export([x25519_keypair/1]). -export([x25519_secret_to_public/1]). -export([x25519_shared_secret/2]). %% Macros -define(PH(M), libsodium_crypto_hash_sha512:crypto_hash_sha512(M)). %%==================================================================== %% jose_curve25519 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> libsodium_crypto_sign_ed25519:keypair(). eddsa_keypair(Seed) -> libsodium_crypto_sign_ed25519:seed_keypair(Seed). eddsa_secret_to_public(SecretKey) -> {PK, _} = libsodium_crypto_sign_ed25519:seed_keypair(SecretKey), PK. % Ed25519 ed25519_sign(Message, SecretKey) -> libsodium_crypto_sign_ed25519:detached(Message, SecretKey). ed25519_verify(Signature, Message, PublicKey) -> try libsodium_crypto_sign_ed25519:verify_detached(Signature, Message, PublicKey) of 0 -> true; _ -> false catch _:_ -> false end. % Ed25519ph ed25519ph_sign(Message, SecretKey) -> ed25519_sign(?PH(Message), SecretKey). ed25519ph_verify(Signature, Message, PublicKey) -> ed25519_verify(Signature, ?PH(Message), PublicKey). % X25519 x25519_keypair() -> libsodium_crypto_box_curve25519xsalsa20poly1305:keypair(). x25519_keypair(SK = << _:32/binary >>) -> PK = x25519_secret_to_public(SK), {PK, SK}. x25519_secret_to_public(SecretKey) -> libsodium_crypto_scalarmult_curve25519:base(SecretKey). x25519_shared_secret(MySecretKey, YourPublicKey) -> libsodium_crypto_scalarmult_curve25519:crypto_scalarmult_curve25519(MySecretKey, YourPublicKey). erlang-jose-1.10.1/src/jose_sha3.erl0000644000232200023220000000325213605433351017524 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 11 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_sha3). -callback sha3_224(InputBytes::binary()) -> OutputBytes::binary(). -callback sha3_256(InputBytes::binary()) -> OutputBytes::binary(). -callback sha3_384(InputBytes::binary()) -> OutputBytes::binary(). -callback sha3_512(InputBytes::binary()) -> OutputBytes::binary(). -callback shake128(InputBytes::binary(), OutputByteLen::integer()) -> OutputBytes::binary(). -callback shake256(InputBytes::binary(), OutputByteLen::integer()) -> OutputBytes::binary(). %% jose_sha3 callbacks -export([sha3_224/1]). -export([sha3_256/1]). -export([sha3_384/1]). -export([sha3_512/1]). -export([shake128/2]). -export([shake256/2]). %% Macros -define(JOSE_SHA3, (jose:sha3_module())). %%==================================================================== %% jose_sha3 callbacks %%==================================================================== sha3_224(InputBytes) -> ?JOSE_SHA3:sha3_224(InputBytes). sha3_256(InputBytes) -> ?JOSE_SHA3:sha3_256(InputBytes). sha3_384(InputBytes) -> ?JOSE_SHA3:sha3_384(InputBytes). sha3_512(InputBytes) -> ?JOSE_SHA3:sha3_512(InputBytes). shake128(InputBytes, OutputByteLen) -> ?JOSE_SHA3:shake128(InputBytes, OutputByteLen). shake256(InputBytes, OutputByteLen) -> ?JOSE_SHA3:shake256(InputBytes, OutputByteLen). erlang-jose-1.10.1/src/jwe/0000755000232200023220000000000013605433351015725 5ustar debalancedebalanceerlang-jose-1.10.1/src/jwe/jose_jwe_alg_pbes2.erl0000644000232200023220000003145113605433351022160 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 22 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg_pbes2). -behaviour(jose_jwe). -behaviour(jose_jwe_alg). -include("jose_jwk.hrl"). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_alg callbacks -export([generate_key/3]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([next_cek/3]). %% API -export([hmac_supported/0]). -export([wrap_supported/0]). %% Types -record(jose_jwe_alg_pbes2, { hmac = undefined :: undefined | sha256 | sha384 | sha512, salt = undefined :: undefined | binary(), iter = undefined :: undefined | pos_integer(), wrap = undefined :: undefined | aes_gcm_kw | aes_kw | c20p_kw | xc20p_kw, bits = undefined :: undefined | 128 | 192 | 256, iv = undefined :: undefined | binary(), tag = undefined :: undefined | binary() }). -type alg() :: #jose_jwe_alg_pbes2{}. -export_type([alg/0]). -define(PBES2_HS256_A128GCMKW, #jose_jwe_alg_pbes2{hmac=sha256, wrap=aes_gcm_kw, bits=128}). -define(PBES2_HS384_A192GCMKW, #jose_jwe_alg_pbes2{hmac=sha384, wrap=aes_gcm_kw, bits=192}). -define(PBES2_HS512_A256GCMKW, #jose_jwe_alg_pbes2{hmac=sha512, wrap=aes_gcm_kw, bits=256}). -define(PBES2_HS256_A128KW, #jose_jwe_alg_pbes2{hmac=sha256, wrap=aes_kw, bits=128}). -define(PBES2_HS384_A192KW, #jose_jwe_alg_pbes2{hmac=sha384, wrap=aes_kw, bits=192}). -define(PBES2_HS512_A256KW, #jose_jwe_alg_pbes2{hmac=sha512, wrap=aes_kw, bits=256}). -define(PBES2_HS512_C20PKW, #jose_jwe_alg_pbes2{hmac=sha512, wrap=c20p_kw, bits=256}). -define(PBES2_HS512_XC20PKW, #jose_jwe_alg_pbes2{hmac=sha512, wrap=xc20p_kw, bits=256}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"PBES2-HS256+A128GCMKW">> }) -> from_map_pbes2(maps:remove(<<"alg">>, F), ?PBES2_HS256_A128GCMKW); from_map(F = #{ <<"alg">> := <<"PBES2-HS384+A192GCMKW">> }) -> from_map_pbes2(maps:remove(<<"alg">>, F), ?PBES2_HS384_A192GCMKW); from_map(F = #{ <<"alg">> := <<"PBES2-HS512+A256GCMKW">> }) -> from_map_pbes2(maps:remove(<<"alg">>, F), ?PBES2_HS512_A256GCMKW); from_map(F = #{ <<"alg">> := <<"PBES2-HS256+A128KW">> }) -> from_map_pbes2(maps:remove(<<"alg">>, F), ?PBES2_HS256_A128KW); from_map(F = #{ <<"alg">> := <<"PBES2-HS384+A192KW">> }) -> from_map_pbes2(maps:remove(<<"alg">>, F), ?PBES2_HS384_A192KW); from_map(F = #{ <<"alg">> := <<"PBES2-HS512+A256KW">> }) -> from_map_pbes2(maps:remove(<<"alg">>, F), ?PBES2_HS512_A256KW); from_map(F = #{ <<"alg">> := <<"PBES2-HS512+C20PKW">> }) -> from_map_pbes2(maps:remove(<<"alg">>, F), ?PBES2_HS512_C20PKW); from_map(F = #{ <<"alg">> := <<"PBES2-HS512+XC20PKW">> }) -> from_map_pbes2(maps:remove(<<"alg">>, F), ?PBES2_HS512_XC20PKW). to_map(A = ?PBES2_HS256_A128GCMKW, F) -> to_map_pbes2(F#{ <<"alg">> => <<"PBES2-HS256+A128GCMKW">> }, A); to_map(A = ?PBES2_HS384_A192GCMKW, F) -> to_map_pbes2(F#{ <<"alg">> => <<"PBES2-HS384+A192GCMKW">> }, A); to_map(A = ?PBES2_HS512_A256GCMKW, F) -> to_map_pbes2(F#{ <<"alg">> => <<"PBES2-HS512+A256GCMKW">> }, A); to_map(A = ?PBES2_HS256_A128KW, F) -> to_map_pbes2(F#{ <<"alg">> => <<"PBES2-HS256+A128KW">> }, A); to_map(A = ?PBES2_HS384_A192KW, F) -> to_map_pbes2(F#{ <<"alg">> => <<"PBES2-HS384+A192KW">> }, A); to_map(A = ?PBES2_HS512_A256KW, F) -> to_map_pbes2(F#{ <<"alg">> => <<"PBES2-HS512+A256KW">> }, A); to_map(A = ?PBES2_HS512_C20PKW, F) -> to_map_pbes2(F#{ <<"alg">> => <<"PBES2-HS512+C20PKW">> }, A); to_map(A = ?PBES2_HS512_XC20PKW, F) -> to_map_pbes2(F#{ <<"alg">> => <<"PBES2-HS512+XC20PKW">> }, A). %%==================================================================== %% jose_jwe_alg callbacks %%==================================================================== generate_key(_Fields, {ENCModule, ENC}, ALG=#jose_jwe_alg_pbes2{}) -> jose_jwe_alg:generate_key({oct, 16}, maps:get(<<"alg">>, to_map(ALG, #{})), ENCModule:algorithm(ENC)). key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=aes_gcm_kw, bits=Bits, iv=IV, tag=TAG}) when is_binary(Password) andalso is_binary(IV) andalso is_binary(TAG) -> {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), jose_jwa:block_decrypt({aes_gcm, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=aes_kw, bits=Bits}) when is_binary(Password) -> {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), jose_jwa_aes_kw:unwrap(EncryptedKey, DerivedKey); key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=c20p_kw, bits=Bits, iv=IV, tag=TAG}) when is_binary(Password) andalso is_binary(IV) andalso is_binary(TAG) -> {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), jose_jwa:block_decrypt({chacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(Password, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=xc20p_kw, bits=Bits, iv=IV, tag=TAG}) when is_binary(Password) andalso is_binary(IV) andalso is_binary(TAG) -> {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), jose_jwa:block_decrypt({xchacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(#jose_jwk{kty={KTYModule, KTY}}, EncryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{}) -> key_decrypt(KTYModule:derive_key(KTY), EncryptedKey, JWEPBES2). key_encrypt(Password, DecryptedKey, ALG0=#jose_jwe_alg_pbes2{bits=Bits, salt=undefined}) -> ALG1 = ALG0#jose_jwe_alg_pbes2{salt=wrap_salt(crypto:strong_rand_bytes(Bits div 8), ALG0)}, key_encrypt(Password, DecryptedKey, ALG1); key_encrypt(Password, DecryptedKey, ALG0=#jose_jwe_alg_pbes2{bits=Bits, iter=undefined}) -> ALG1 = ALG0#jose_jwe_alg_pbes2{iter=(Bits * 32)}, key_encrypt(Password, DecryptedKey, ALG1); key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=aes_gcm_kw, bits=Bits, iv=IV}) when is_binary(Password) andalso is_binary(DecryptedKey) andalso is_binary(Salt) andalso is_integer(Iterations) andalso is_binary(IV) -> {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), {CipherText, CipherTag} = jose_jwa:block_encrypt({aes_gcm, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }}; key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=aes_kw, bits=Bits}) when is_binary(Password) andalso is_binary(DecryptedKey) andalso is_binary(Salt) andalso is_integer(Iterations) -> {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), {jose_jwa_aes_kw:wrap(DecryptedKey, DerivedKey), JWEPBES2}; key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=c20p_kw, bits=Bits, iv=IV}) when is_binary(Password) andalso is_binary(DecryptedKey) andalso is_binary(Salt) andalso is_integer(Iterations) andalso is_binary(IV) -> {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), {CipherText, CipherTag} = jose_jwa:block_encrypt({chacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }}; key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{hmac=HMAC, salt=Salt, iter=Iterations, wrap=xc20p_kw, bits=Bits, iv=IV}) when is_binary(Password) andalso is_binary(DecryptedKey) andalso is_binary(Salt) andalso is_integer(Iterations) andalso is_binary(IV) -> {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2({hmac, HMAC}, Password, Salt, Iterations, (Bits div 8) + (Bits rem 8)), {CipherText, CipherTag} = jose_jwa:block_encrypt({xchacha20_poly1305, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEPBES2#jose_jwe_alg_pbes2{ tag = CipherTag }}; key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{wrap=aes_gcm_kw, iv=undefined}) when is_binary(Password) -> key_encrypt(Password, DecryptedKey, JWEPBES2#jose_jwe_alg_pbes2{ iv = crypto:strong_rand_bytes(12) }); key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{wrap=c20p_kw, iv=undefined}) when is_binary(Password) -> key_encrypt(Password, DecryptedKey, JWEPBES2#jose_jwe_alg_pbes2{ iv = crypto:strong_rand_bytes(12) }); key_encrypt(Password, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{wrap=xc20p_kw, iv=undefined}) when is_binary(Password) -> key_encrypt(Password, DecryptedKey, JWEPBES2#jose_jwe_alg_pbes2{ iv = crypto:strong_rand_bytes(24) }); key_encrypt(#jose_jwk{kty={KTYModule, KTY}}, DecryptedKey, JWEPBES2=#jose_jwe_alg_pbes2{}) -> key_encrypt(KTYModule:derive_key(KTY), DecryptedKey, JWEPBES2). next_cek(_Key, {ENCModule, ENC}, ALG=#jose_jwe_alg_pbes2{}) -> {ENCModule:next_cek(ENC), ALG}. %%==================================================================== %% API functions %%==================================================================== hmac_supported() -> [sha256, sha384, sha512]. wrap_supported() -> [128, 192, 256]. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private from_map_pbes2(F = #{ <<"p2c">> := P2C }, H) -> from_map_pbes2(maps:remove(<<"p2c">>, F), H#jose_jwe_alg_pbes2{ iter = P2C }); from_map_pbes2(F = #{ <<"p2s">> := P2S }, H) -> from_map_pbes2(maps:remove(<<"p2s">>, F), H#jose_jwe_alg_pbes2{ salt = wrap_salt(jose_jwa_base64url:decode(P2S), H) }); from_map_pbes2(F=#{ <<"iv">> := IV }, H) -> from_map_pbes2(maps:remove(<<"iv">>, F), H#jose_jwe_alg_pbes2{ iv = jose_jwa_base64url:decode(IV) }); from_map_pbes2(F=#{ <<"tag">> := TAG }, H) -> from_map_pbes2(maps:remove(<<"tag">>, F), H#jose_jwe_alg_pbes2{ tag = jose_jwa_base64url:decode(TAG) }); from_map_pbes2(F, H) -> {H, F}. %% @private to_map_pbes2(F, H=#jose_jwe_alg_pbes2{ iter = P2C }) when is_integer(P2C) -> to_map_pbes2(F#{ <<"p2c">> => P2C }, H#jose_jwe_alg_pbes2{ iter = undefined }); to_map_pbes2(F, H=#jose_jwe_alg_pbes2{ salt = P2S }) when is_binary(P2S) -> to_map_pbes2(F#{ <<"p2s">> => jose_jwa_base64url:encode(unwrap_salt(P2S, H)) }, H#jose_jwe_alg_pbes2{ salt = undefined }); to_map_pbes2(F, H=#jose_jwe_alg_pbes2{ iv = IV }) when is_binary(IV) -> to_map_pbes2(F#{ <<"iv">> => jose_jwa_base64url:encode(IV) }, H#jose_jwe_alg_pbes2{ iv = undefined }); to_map_pbes2(F, H=#jose_jwe_alg_pbes2{ tag = TAG }) when is_binary(TAG) -> to_map_pbes2(F#{ <<"tag">> => jose_jwa_base64url:encode(TAG) }, H#jose_jwe_alg_pbes2{ tag = undefined }); to_map_pbes2(F, _) -> F. %% @private wrap_salt(SaltInput, ?PBES2_HS256_A128GCMKW) -> << "PBES2-HS256+A128GCMKW", 0, SaltInput/binary >>; wrap_salt(SaltInput, ?PBES2_HS384_A192GCMKW) -> << "PBES2-HS384+A192GCMKW", 0, SaltInput/binary >>; wrap_salt(SaltInput, ?PBES2_HS512_A256GCMKW) -> << "PBES2-HS512+A256GCMKW", 0, SaltInput/binary >>; wrap_salt(SaltInput, ?PBES2_HS256_A128KW) -> << "PBES2-HS256+A128KW", 0, SaltInput/binary >>; wrap_salt(SaltInput, ?PBES2_HS384_A192KW) -> << "PBES2-HS384+A192KW", 0, SaltInput/binary >>; wrap_salt(SaltInput, ?PBES2_HS512_A256KW) -> << "PBES2-HS512+A256KW", 0, SaltInput/binary >>; wrap_salt(SaltInput, ?PBES2_HS512_C20PKW) -> << "PBES2-HS512+C20PKW", 0, SaltInput/binary >>; wrap_salt(SaltInput, ?PBES2_HS512_XC20PKW) -> << "PBES2-HS512+XC20PKW", 0, SaltInput/binary >>. %% @private unwrap_salt(<< "PBES2-HS256+A128GCMKW", 0, SaltInput/binary >>, ?PBES2_HS256_A128GCMKW) -> SaltInput; unwrap_salt(<< "PBES2-HS384+A192GCMKW", 0, SaltInput/binary >>, ?PBES2_HS384_A192GCMKW) -> SaltInput; unwrap_salt(<< "PBES2-HS512+A256GCMKW", 0, SaltInput/binary >>, ?PBES2_HS512_A256GCMKW) -> SaltInput; unwrap_salt(<< "PBES2-HS256+A128KW", 0, SaltInput/binary >>, ?PBES2_HS256_A128KW) -> SaltInput; unwrap_salt(<< "PBES2-HS384+A192KW", 0, SaltInput/binary >>, ?PBES2_HS384_A192KW) -> SaltInput; unwrap_salt(<< "PBES2-HS512+A256KW", 0, SaltInput/binary >>, ?PBES2_HS512_A256KW) -> SaltInput; unwrap_salt(<< "PBES2-HS512+C20PKW", 0, SaltInput/binary >>, ?PBES2_HS512_C20PKW) -> SaltInput; unwrap_salt(<< "PBES2-HS512+XC20PKW", 0, SaltInput/binary >>, ?PBES2_HS512_XC20PKW) -> SaltInput. erlang-jose-1.10.1/src/jwe/jose_jwe_enc_c20p.erl0000644000232200023220000000437413605433351021717 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 31 May 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_enc_c20p). -behaviour(jose_jwe). -behaviour(jose_jwe_enc). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_enc callbacks -export([algorithm/1]). -export([bits/1]). -export([block_decrypt/4]). -export([block_encrypt/4]). -export([next_cek/1]). -export([next_iv/1]). %% API -export([cipher_supported/0]). %% Types -type enc() :: {chacha20_poly1305, 256}. -export_type([enc/0]). %% Macros -define(CHACHA20_POLY1305, {chacha20_poly1305, 256}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"enc">> := <<"C20P">> }) -> {?CHACHA20_POLY1305, maps:remove(<<"enc">>, F)}. to_map(?CHACHA20_POLY1305, F) -> F#{ <<"enc">> => <<"C20P">> }. %%==================================================================== %% jose_jwe_enc callbacks %%==================================================================== algorithm(?CHACHA20_POLY1305) -> <<"C20P">>. bits(?CHACHA20_POLY1305) -> 256. block_decrypt({AAD, CipherText, CipherTag}, CEK, IV, ?CHACHA20_POLY1305) -> jose_jwa:block_decrypt(?CHACHA20_POLY1305, CEK, IV, {AAD, CipherText, CipherTag}). block_encrypt({AAD, PlainText}, CEK, IV, ?CHACHA20_POLY1305) -> jose_jwa:block_encrypt(?CHACHA20_POLY1305, CEK, IV, {AAD, PlainText}). next_cek(?CHACHA20_POLY1305) -> crypto:strong_rand_bytes(32). next_iv(?CHACHA20_POLY1305) -> crypto:strong_rand_bytes(12). %%==================================================================== %% API functions %%==================================================================== cipher_supported() -> [chacha20_poly1305]. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwe/jose_jwe_alg_ecdh_es.erl0000644000232200023220000003672013605433351022543 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg_ecdh_es). -behaviour(jose_jwe). -behaviour(jose_jwe_alg). -include_lib("public_key/include/public_key.hrl"). -include("jose_jwk.hrl"). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_alg callbacks -export([generate_key/3]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([next_cek/3]). %% API -export([algorithm/1]). %% Types -type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'ECParameters'{}} | term(). -record(jose_jwe_alg_ecdh_es, { epk = undefined :: undefined | {ec_public_key(), map()}, apu = undefined :: undefined | binary(), apv = undefined :: undefined | binary(), wrap = undefined :: undefined | aes_gcm_kw | aes_kw | c20p_kw | xc20p_kw, bits = undefined :: undefined | 128 | 192 | 256, iv = undefined :: undefined | binary(), tag = undefined :: undefined | binary() }). -type alg() :: #jose_jwe_alg_ecdh_es{}. -export_type([alg/0]). -define(ECDH_ES, #jose_jwe_alg_ecdh_es{}). -define(ECDH_ES_A128GCMKW, #jose_jwe_alg_ecdh_es{wrap=aes_gcm_kw, bits=128}). -define(ECDH_ES_A192GCMKW, #jose_jwe_alg_ecdh_es{wrap=aes_gcm_kw, bits=192}). -define(ECDH_ES_A256GCMKW, #jose_jwe_alg_ecdh_es{wrap=aes_gcm_kw, bits=256}). -define(ECDH_ES_A128KW, #jose_jwe_alg_ecdh_es{wrap=aes_kw, bits=128}). -define(ECDH_ES_A192KW, #jose_jwe_alg_ecdh_es{wrap=aes_kw, bits=192}). -define(ECDH_ES_A256KW, #jose_jwe_alg_ecdh_es{wrap=aes_kw, bits=256}). -define(ECDH_ES_C20PKW, #jose_jwe_alg_ecdh_es{wrap=c20p_kw, bits=256}). -define(ECDH_ES_XC20PKW, #jose_jwe_alg_ecdh_es{wrap=xc20p_kw, bits=256}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"ECDH-ES">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES); from_map(F = #{ <<"alg">> := <<"ECDH-ES+A128GCMKW">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES_A128GCMKW); from_map(F = #{ <<"alg">> := <<"ECDH-ES+A192GCMKW">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES_A192GCMKW); from_map(F = #{ <<"alg">> := <<"ECDH-ES+A256GCMKW">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES_A256GCMKW); from_map(F = #{ <<"alg">> := <<"ECDH-ES+A128KW">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES_A128KW); from_map(F = #{ <<"alg">> := <<"ECDH-ES+A192KW">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES_A192KW); from_map(F = #{ <<"alg">> := <<"ECDH-ES+A256KW">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES_A256KW); from_map(F = #{ <<"alg">> := <<"ECDH-ES+C20PKW">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES_C20PKW); from_map(F = #{ <<"alg">> := <<"ECDH-ES+XC20PKW">> }) -> from_map_ecdh_es(maps:remove(<<"alg">>, F), ?ECDH_ES_XC20PKW). to_map(A = ?ECDH_ES_A128GCMKW, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES+A128GCMKW">> }, A); to_map(A = ?ECDH_ES_A192GCMKW, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES+A192GCMKW">> }, A); to_map(A = ?ECDH_ES_A256GCMKW, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES+A256GCMKW">> }, A); to_map(A = ?ECDH_ES_A128KW, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES+A128KW">> }, A); to_map(A = ?ECDH_ES_A192KW, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES+A192KW">> }, A); to_map(A = ?ECDH_ES_A256KW, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES+A256KW">> }, A); to_map(A = ?ECDH_ES_C20PKW, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES+C20PKW">> }, A); to_map(A = ?ECDH_ES_XC20PKW, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES+XC20PKW">> }, A); to_map(A = ?ECDH_ES, F) -> to_map_ecdh_es(F#{ <<"alg">> => <<"ECDH-ES">> }, A). %%==================================================================== %% jose_jwe_alg callbacks %%==================================================================== generate_key(_Fields, {ENCModule, ENC}, ALG=#jose_jwe_alg_ecdh_es{epk=EphemeralPublicJWK=#jose_jwk{}}) -> jose_jwe_alg:generate_key(EphemeralPublicJWK, maps:get(<<"alg">>, to_map(ALG, #{})), ENCModule:algorithm(ENC)); generate_key(_Fields, {ENCModule, ENC}, ALG=#jose_jwe_alg_ecdh_es{}) -> jose_jwe_alg:generate_key({ec, <<"P-521">>}, maps:get(<<"alg">>, to_map(ALG, #{})), ENCModule:algorithm(ENC)). key_decrypt({UEphemeralKey=#jose_jwk{}, VStaticSecretKey=#jose_jwk{}}, EncryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{epk=UEphemeralPublicKey=#jose_jwk{}}) -> case jose_jwk:thumbprint(UEphemeralKey) =:= jose_jwk:thumbprint(UEphemeralPublicKey) of true -> key_decrypt(VStaticSecretKey, EncryptedKey, JWEECDHES); false -> error end; key_decrypt({UEphemeralPublicKey=#jose_jwk{}, VStaticSecretKey=#jose_jwk{}}, EncryptedKey, JWEECDHES0=#jose_jwe_alg_ecdh_es{epk=undefined}) -> JWEECDHES = JWEECDHES0#jose_jwe_alg_ecdh_es{epk=UEphemeralPublicKey}, key_decrypt(VStaticSecretKey, EncryptedKey, JWEECDHES); key_decrypt(VStaticSecretKey=#jose_jwk{}, EncryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{epk=UEphemeralPublicKey=#jose_jwk{}}) -> Z = jose_jwk:shared_secret(UEphemeralPublicKey, VStaticSecretKey), key_decrypt(Z, EncryptedKey, JWEECDHES); key_decrypt(Z, {ENCModule, ENC, <<>>}, #jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=undefined, bits=undefined}) when is_binary(Z) -> Algorithm = ENCModule:algorithm(ENC), KeyDataLen = ENCModule:bits(ENC), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), DerivedKey; key_decrypt(Z, {_ENCModule, _ENC, EncryptedKey}, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=aes_gcm_kw, bits=KeyDataLen, iv=IV, tag=TAG}) when is_binary(Z) andalso is_binary(IV) andalso is_binary(TAG) -> Algorithm = algorithm(JWEECDHES), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), jose_jwa:block_decrypt({aes_gcm, KeyDataLen}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(Z, {_ENCModule, _ENC, EncryptedKey}, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=aes_kw, bits=KeyDataLen}) when is_binary(Z) -> Algorithm = algorithm(JWEECDHES), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), jose_jwa_aes_kw:unwrap(EncryptedKey, DerivedKey); key_decrypt(Z, {_ENCModule, _ENC, EncryptedKey}, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=c20p_kw, bits=KeyDataLen, iv=IV, tag=TAG}) when is_binary(Z) andalso is_binary(IV) andalso is_binary(TAG) -> Algorithm = algorithm(JWEECDHES), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), jose_jwa:block_decrypt({chacha20_poly1305, KeyDataLen}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(Z, {_ENCModule, _ENC, EncryptedKey}, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=xc20p_kw, bits=KeyDataLen, iv=IV, tag=TAG}) when is_binary(Z) andalso is_binary(IV) andalso is_binary(TAG) -> Algorithm = algorithm(JWEECDHES), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), jose_jwa:block_decrypt({xchacha20_poly1305, KeyDataLen}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}). key_encrypt(_Key, _DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{wrap=undefined, bits=undefined}) -> {<<>>, JWEECDHES}; key_encrypt({VStaticPublicKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}}, DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{epk=UEphemeralPublicKey=#jose_jwk{}}) -> case jose_jwk:thumbprint(UEphemeralSecretKey) =:= jose_jwk:thumbprint(UEphemeralPublicKey) of true -> Z = jose_jwk:shared_secret(VStaticPublicKey, UEphemeralSecretKey), key_encrypt(Z, DecryptedKey, JWEECDHES); false -> error end; key_encrypt({VStaticPublicKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}}, DecryptedKey, JWEECDHES0=#jose_jwe_alg_ecdh_es{epk=undefined}) -> UEphemeralPublicKey = jose_jwk:to_public(UEphemeralSecretKey), JWEECDHES1 = JWEECDHES0#jose_jwe_alg_ecdh_es{epk=UEphemeralPublicKey}, key_encrypt({VStaticPublicKey, UEphemeralSecretKey}, DecryptedKey, JWEECDHES1); key_encrypt(#jose_jwk{kty={KTYModule, KTY}}, DecryptedKey, JWEECDHES) -> DerivedKey = KTYModule:derive_key(KTY), key_encrypt(DerivedKey, DecryptedKey, JWEECDHES); key_encrypt(Z, DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=aes_gcm_kw, bits=KeyDataLen, iv=IV}) when is_binary(Z) andalso is_binary(IV) -> Algorithm = algorithm(JWEECDHES), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {CipherText, CipherTag} = jose_jwa:block_encrypt({aes_gcm, KeyDataLen}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEECDHES#jose_jwe_alg_ecdh_es{ tag = CipherTag }}; key_encrypt(Z, DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=aes_kw, bits=KeyDataLen}) when is_binary(Z) -> Algorithm = algorithm(JWEECDHES), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {jose_jwa_aes_kw:wrap(DecryptedKey, DerivedKey), JWEECDHES}; key_encrypt(Z, DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=c20p_kw, bits=KeyDataLen, iv=IV}) when is_binary(Z) andalso is_binary(IV) -> Algorithm = algorithm(JWEECDHES), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {CipherText, CipherTag} = jose_jwa:block_encrypt({chacha20_poly1305, KeyDataLen}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEECDHES#jose_jwe_alg_ecdh_es{ tag = CipherTag }}; key_encrypt(Z, DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=xc20p_kw, bits=KeyDataLen, iv=IV}) when is_binary(Z) andalso is_binary(IV) -> Algorithm = algorithm(JWEECDHES), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {CipherText, CipherTag} = jose_jwa:block_encrypt({xchacha20_poly1305, KeyDataLen}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEECDHES#jose_jwe_alg_ecdh_es{ tag = CipherTag }}; key_encrypt(Z, DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{wrap=aes_gcm_kw, iv=undefined}) when is_binary(Z) -> key_encrypt(Z, DecryptedKey, JWEECDHES#jose_jwe_alg_ecdh_es{ iv = crypto:strong_rand_bytes(12) }); key_encrypt(Z, DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{wrap=c20p_kw, iv=undefined}) when is_binary(Z) -> key_encrypt(Z, DecryptedKey, JWEECDHES#jose_jwe_alg_ecdh_es{ iv = crypto:strong_rand_bytes(12) }); key_encrypt(Z, DecryptedKey, JWEECDHES=#jose_jwe_alg_ecdh_es{wrap=xc20p_kw, iv=undefined}) when is_binary(Z) -> key_encrypt(Z, DecryptedKey, JWEECDHES#jose_jwe_alg_ecdh_es{ iv = crypto:strong_rand_bytes(24) }). next_cek({VStaticPublicKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}}, {ENCModule, ENC}, JWEECDHES=#jose_jwe_alg_ecdh_es{bits=undefined, epk=UEphemeralPublicKey=#jose_jwk{}}) -> case jose_jwk:thumbprint(UEphemeralSecretKey) =:= jose_jwk:thumbprint(UEphemeralPublicKey) of true -> Z = jose_jwk:shared_secret(VStaticPublicKey, UEphemeralSecretKey), next_cek(Z, {ENCModule, ENC}, JWEECDHES); false -> error end; next_cek({VStaticPublicKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}}, {ENCModule, ENC}, JWEECDHES0=#jose_jwe_alg_ecdh_es{wrap=undefined, bits=undefined, epk=undefined}) -> UEphemeralPublicKey = jose_jwk:to_public(UEphemeralSecretKey), JWEECDHES1 = JWEECDHES0#jose_jwe_alg_ecdh_es{epk=UEphemeralPublicKey}, next_cek({VStaticPublicKey, UEphemeralSecretKey}, {ENCModule, ENC}, JWEECDHES1); next_cek(#jose_jwk{kty={KTYModule, KTY}}, {ENC, ENCModule}, JWEECDHES=#jose_jwe_alg_ecdh_es{wrap=undefined, bits=undefined}) -> DerivedKey = KTYModule:derive_key(KTY), next_cek(DerivedKey, {ENCModule, ENC}, JWEECDHES); next_cek(Z, {ENCModule, ENC}, JWEECDHES=#jose_jwe_alg_ecdh_es{apu=APU, apv=APV, wrap=undefined, bits=undefined}) when is_binary(Z) -> Algorithm = ENCModule:algorithm(ENC), KeyDataLen = ENCModule:bits(ENC), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {DerivedKey, JWEECDHES}; next_cek(_Key, {ENCModule, ENC}, JWEECDHES=#jose_jwe_alg_ecdh_es{}) -> {ENCModule:next_cek(ENC), JWEECDHES}. %%==================================================================== %% API functions %%==================================================================== algorithm(?ECDH_ES_A128GCMKW) -> <<"ECDH-ES+A128GCMKW">>; algorithm(?ECDH_ES_A192GCMKW) -> <<"ECDH-ES+A192GCMKW">>; algorithm(?ECDH_ES_A256GCMKW) -> <<"ECDH-ES+A256GCMKW">>; algorithm(?ECDH_ES_A128KW) -> <<"ECDH-ES+A128KW">>; algorithm(?ECDH_ES_A192KW) -> <<"ECDH-ES+A192KW">>; algorithm(?ECDH_ES_A256KW) -> <<"ECDH-ES+A256KW">>; algorithm(?ECDH_ES_C20PKW) -> <<"ECDH-ES+C20PKW">>; algorithm(?ECDH_ES_XC20PKW) -> <<"ECDH-ES+XC20PKW">>; algorithm(?ECDH_ES) -> <<"ECDH-ES">>. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private from_map_ecdh_es(F = #{ <<"epk">> := EPK }, H) -> from_map_ecdh_es(maps:remove(<<"epk">>, F), H#jose_jwe_alg_ecdh_es{ epk = jose_jwk:from_map(EPK) }); from_map_ecdh_es(F = #{ <<"apu">> := APU }, H) -> from_map_ecdh_es(maps:remove(<<"apu">>, F), H#jose_jwe_alg_ecdh_es{ apu = jose_jwa_base64url:decode(APU) }); from_map_ecdh_es(F = #{ <<"apv">> := APV }, H) -> from_map_ecdh_es(maps:remove(<<"apv">>, F), H#jose_jwe_alg_ecdh_es{ apv = jose_jwa_base64url:decode(APV) }); from_map_ecdh_es(F=#{ <<"iv">> := IV }, H) -> from_map_ecdh_es(maps:remove(<<"iv">>, F), H#jose_jwe_alg_ecdh_es{ iv = jose_jwa_base64url:decode(IV) }); from_map_ecdh_es(F=#{ <<"tag">> := TAG }, H) -> from_map_ecdh_es(maps:remove(<<"tag">>, F), H#jose_jwe_alg_ecdh_es{ tag = jose_jwa_base64url:decode(TAG) }); from_map_ecdh_es(F, H) -> {H, F}. %% @private to_map_ecdh_es(F, H=#jose_jwe_alg_ecdh_es{ epk = EPK = #jose_jwk{} }) -> to_map_ecdh_es(F#{ <<"epk">> => element(2, jose_jwk:to_public_map(EPK)) }, H#jose_jwe_alg_ecdh_es{ epk = undefined }); to_map_ecdh_es(F, H=#jose_jwe_alg_ecdh_es{ apu = APU }) when is_binary(APU) -> to_map_ecdh_es(F#{ <<"apu">> => jose_jwa_base64url:encode(APU) }, H#jose_jwe_alg_ecdh_es{ apu = undefined }); to_map_ecdh_es(F, H=#jose_jwe_alg_ecdh_es{ apv = APV }) when is_binary(APV) -> to_map_ecdh_es(F#{ <<"apv">> => jose_jwa_base64url:encode(APV) }, H#jose_jwe_alg_ecdh_es{ apv = undefined }); to_map_ecdh_es(F, H=#jose_jwe_alg_ecdh_es{ iv = IV }) when is_binary(IV) -> to_map_ecdh_es(F#{ <<"iv">> => jose_jwa_base64url:encode(IV) }, H#jose_jwe_alg_ecdh_es{ iv = undefined }); to_map_ecdh_es(F, H=#jose_jwe_alg_ecdh_es{ tag = TAG }) when is_binary(TAG) -> to_map_ecdh_es(F#{ <<"tag">> => jose_jwa_base64url:encode(TAG) }, H#jose_jwe_alg_ecdh_es{ tag = undefined }); to_map_ecdh_es(F, _) -> F. erlang-jose-1.10.1/src/jwe/jose_jwe_alg_rsa.erl0000644000232200023220000000602713605433351021733 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 22 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg_rsa). -behaviour(jose_jwe). -behaviour(jose_jwe_alg). -include("jose_jwk.hrl"). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_alg callbacks -export([generate_key/3]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([next_cek/3]). %% API %% Types -record(jose_jwe_alg_rsa, { algorithm = undefined :: undefined | rsa1_5 | rsa_oaep | rsa_oaep_256 }). -type alg() :: #jose_jwe_alg_rsa{}. -export_type([alg/0]). -define(RSA1_5, #jose_jwe_alg_rsa{algorithm=rsa1_5}). -define(RSA_OAEP, #jose_jwe_alg_rsa{algorithm=rsa_oaep}). -define(RSA_OAEP_256, #jose_jwe_alg_rsa{algorithm=rsa_oaep_256}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"RSA1_5">> }) -> {?RSA1_5, maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"RSA-OAEP">> }) -> {?RSA_OAEP, maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"RSA-OAEP-256">> }) -> {?RSA_OAEP_256, maps:remove(<<"alg">>, F)}. to_map(?RSA1_5, F) -> F#{ <<"alg">> => <<"RSA1_5">> }; to_map(?RSA_OAEP, F) -> F#{ <<"alg">> => <<"RSA-OAEP">> }; to_map(?RSA_OAEP_256, F) -> F#{ <<"alg">> => <<"RSA-OAEP-256">> }. %%==================================================================== %% jose_jwe_alg callbacks %%==================================================================== generate_key(_Fields, {ENCModule, ENC}, ?RSA1_5) -> jose_jwe_alg:generate_key({rsa, 2048}, <<"RSA1_5">>, ENCModule:algorithm(ENC)); generate_key(_Fields, {ENCModule, ENC}, ?RSA_OAEP) -> jose_jwe_alg:generate_key({rsa, 2048}, <<"RSA-OAEP">>, ENCModule:algorithm(ENC)); generate_key(_Fields, {ENCModule, ENC}, ?RSA_OAEP_256) -> jose_jwe_alg:generate_key({rsa, 2048}, <<"RSA-OAEP-256">>, ENCModule:algorithm(ENC)). key_decrypt(#jose_jwk{kty={KTYModule, KTY}}, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_rsa{algorithm=Algorithm}) -> KTYModule:decrypt_private(EncryptedKey, Algorithm, KTY). key_encrypt(#jose_jwk{kty={KTYModule, KTY}}, DecryptedKey, JWERSA=#jose_jwe_alg_rsa{algorithm=Algorithm}) -> {KTYModule:encrypt_public(DecryptedKey, Algorithm, KTY), JWERSA}. next_cek(_Key, {ENCModule, ENC}, ALG=#jose_jwe_alg_rsa{}) -> {ENCModule:next_cek(ENC), ALG}. %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwe/jose_jwe_enc_aes.erl0000644000232200023220000001462713605433351021725 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 22 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_enc_aes). -behaviour(jose_jwe). -behaviour(jose_jwe_enc). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_enc callbacks -export([algorithm/1]). -export([bits/1]). -export([block_decrypt/4]). -export([block_encrypt/4]). -export([next_cek/1]). -export([next_iv/1]). %% API -export([cipher_supported/0]). -export([hmac_supported/0]). %% Types -type cipher() :: aes_cbc | aes_gcm. -type key_size() :: 128 | 192 | 256. -record(jose_jwe_enc_aes, { cipher = undefined :: undefined | {cipher(), key_size()}, bits = undefined :: undefined | pos_integer(), cek_len = undefined :: undefined | pos_integer(), iv_len = undefined :: undefined | pos_integer(), enc_len = undefined :: undefined | pos_integer(), mac_len = undefined :: undefined | pos_integer(), tag_len = undefined :: undefined | pos_integer(), hmac = undefined :: undefined | sha256 | sha384 | sha512 }). -type enc() :: #jose_jwe_enc_aes{}. -export_type([enc/0]). -define(AES_128_CBC_HMAC_SHA_256, #jose_jwe_enc_aes{ cipher = {aes_cbc, 128}, bits = 256, cek_len = 32, iv_len = 16, enc_len = 16, mac_len = 16, tag_len = 16, hmac = sha256 }). -define(AES_192_CBC_HMAC_SHA_384, #jose_jwe_enc_aes{ cipher = {aes_cbc, 192}, bits = 384, cek_len = 48, iv_len = 16, enc_len = 24, mac_len = 24, tag_len = 24, hmac = sha384 }). -define(AES_256_CBC_HMAC_SHA_512, #jose_jwe_enc_aes{ cipher = {aes_cbc, 256}, bits = 512, cek_len = 64, iv_len = 16, enc_len = 32, mac_len = 32, tag_len = 32, hmac = sha512 }). -define(AES_128_GCM, #jose_jwe_enc_aes{ cipher = {aes_gcm, 128}, bits = 128, cek_len = 16, iv_len = 12 }). -define(AES_192_GCM, #jose_jwe_enc_aes{ cipher = {aes_gcm, 192}, bits = 192, cek_len = 24, iv_len = 12 }). -define(AES_256_GCM, #jose_jwe_enc_aes{ cipher = {aes_gcm, 256}, bits = 256, cek_len = 32, iv_len = 12 }). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"enc">> := <<"A128CBC-HS256">> }) -> {?AES_128_CBC_HMAC_SHA_256, maps:remove(<<"enc">>, F)}; from_map(F = #{ <<"enc">> := <<"A192CBC-HS384">> }) -> {?AES_192_CBC_HMAC_SHA_384, maps:remove(<<"enc">>, F)}; from_map(F = #{ <<"enc">> := <<"A256CBC-HS512">> }) -> {?AES_256_CBC_HMAC_SHA_512, maps:remove(<<"enc">>, F)}; from_map(F = #{ <<"enc">> := <<"A128GCM">> }) -> {?AES_128_GCM, maps:remove(<<"enc">>, F)}; from_map(F = #{ <<"enc">> := <<"A192GCM">> }) -> {?AES_192_GCM, maps:remove(<<"enc">>, F)}; from_map(F = #{ <<"enc">> := <<"A256GCM">> }) -> {?AES_256_GCM, maps:remove(<<"enc">>, F)}. to_map(?AES_128_CBC_HMAC_SHA_256, F) -> F#{ <<"enc">> => <<"A128CBC-HS256">> }; to_map(?AES_192_CBC_HMAC_SHA_384, F) -> F#{ <<"enc">> => <<"A192CBC-HS384">> }; to_map(?AES_256_CBC_HMAC_SHA_512, F) -> F#{ <<"enc">> => <<"A256CBC-HS512">> }; to_map(?AES_128_GCM, F) -> F#{ <<"enc">> => <<"A128GCM">> }; to_map(?AES_192_GCM, F) -> F#{ <<"enc">> => <<"A192GCM">> }; to_map(?AES_256_GCM, F) -> F#{ <<"enc">> => <<"A256GCM">> }. %%==================================================================== %% jose_jwe_enc callbacks %%==================================================================== algorithm(?AES_128_CBC_HMAC_SHA_256) -> <<"A128CBC-HS256">>; algorithm(?AES_192_CBC_HMAC_SHA_384) -> <<"A192CBC-HS384">>; algorithm(?AES_256_CBC_HMAC_SHA_512) -> <<"A256CBC-HS512">>; algorithm(?AES_128_GCM) -> <<"A128GCM">>; algorithm(?AES_192_GCM) -> <<"A192GCM">>; algorithm(?AES_256_GCM) -> <<"A256GCM">>. bits(#jose_jwe_enc_aes{bits=Bits}) -> Bits. block_decrypt({AAD, CipherText, CipherTag}, CEK, IV, #jose_jwe_enc_aes{ cipher=Cipher, cek_len=CEKLen, hmac=undefined}) when byte_size(CEK) =:= CEKLen andalso bit_size(IV) > 0 -> jose_jwa:block_decrypt(Cipher, CEK, IV, {AAD, CipherText, CipherTag}); block_decrypt({AAD, CipherText, CipherTag}, CEK, IV, #jose_jwe_enc_aes{ cipher=Cipher, cek_len=CEKLen, iv_len=IVLen, enc_len=EncLen, mac_len=MacLen, tag_len=TagLen, hmac=HMAC}) when byte_size(CEK) =:= CEKLen andalso byte_size(IV) =:= IVLen -> << MacKey:MacLen/binary, EncKey:EncLen/binary >> = CEK, AADLength = << (bit_size(AAD)):1/unsigned-big-integer-unit:64 >>, MacData = << AAD/binary, IV/binary, CipherText/binary, AADLength/binary >>, case crypto:hmac(HMAC, MacKey, MacData) of << CipherTag:TagLen/binary, _/binary >> -> PlainText = jose_jwa_pkcs7:unpad(jose_jwa:block_decrypt(Cipher, EncKey, IV, CipherText)), PlainText; _ -> error end. block_encrypt({AAD, PlainText}, CEK, IV, #jose_jwe_enc_aes{ cipher=Cipher, cek_len=CEKLen, hmac=undefined}) when byte_size(CEK) =:= CEKLen andalso bit_size(IV) > 0 -> jose_jwa:block_encrypt(Cipher, CEK, IV, {AAD, PlainText}); block_encrypt({AAD, PlainText}, CEK, IV, #jose_jwe_enc_aes{ cipher=Cipher, cek_len=CEKLen, iv_len=IVLen, enc_len=EncLen, mac_len=MacLen, tag_len=TagLen, hmac=HMAC}) when byte_size(CEK) =:= CEKLen andalso byte_size(IV) =:= IVLen -> << MacKey:MacLen/binary, EncKey:EncLen/binary, _/binary >> = CEK, CipherText = jose_jwa:block_encrypt(Cipher, EncKey, IV, jose_jwa_pkcs7:pad(PlainText)), AADLength = << (bit_size(AAD)):1/unsigned-big-integer-unit:64 >>, MacData = << AAD/binary, IV/binary, CipherText/binary, AADLength/binary >>, << CipherTag:TagLen/binary, _/binary >> = crypto:hmac(HMAC, MacKey, MacData), {CipherText, CipherTag}. next_cek(#jose_jwe_enc_aes{cek_len=CEKLen}) -> crypto:strong_rand_bytes(CEKLen). next_iv(#jose_jwe_enc_aes{iv_len=IVLen}) -> crypto:strong_rand_bytes(IVLen). %%==================================================================== %% API functions %%==================================================================== cipher_supported() -> [aes_cbc, aes_gcm]. hmac_supported() -> [sha256, sha384, sha512]. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwe/jose_jwe_alg_xc20p_kw.erl0000644000232200023220000001012413605433351022574 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg_xc20p_kw). -behaviour(jose_jwe). -behaviour(jose_jwe_alg). -include("jose_jwk.hrl"). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_alg callbacks -export([generate_key/3]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([next_cek/3]). %% API %% Types -record(jose_jwe_alg_xc20p_kw, { iv = undefined :: undefined | binary(), tag = undefined :: undefined | binary() }). -type alg() :: #jose_jwe_alg_xc20p_kw{}. -export_type([alg/0]). %% Macros -define(BITS, 256). -define(XC20PKW, #jose_jwe_alg_xc20p_kw{}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"XC20PKW">> }) -> from_map_xc20p(?XC20PKW, maps:remove(<<"alg">>, F)). to_map(A = ?XC20PKW, F) -> to_map_xc20p(A, F#{ <<"alg">> => <<"XC20PKW">> }). %%==================================================================== %% jose_jwe_alg callbacks %%==================================================================== generate_key(_Fields, {ENCModule, ENC}, ALG=#jose_jwe_alg_xc20p_kw{}) -> jose_jwe_alg:generate_key({oct, (?BITS div 8)}, maps:get(<<"alg">>, to_map(ALG, #{})), ENCModule:algorithm(ENC)). key_decrypt(DerivedKey, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_xc20p_kw{iv=IV, tag=TAG}) when is_binary(DerivedKey) andalso bit_size(DerivedKey) =:= ?BITS andalso is_binary(IV) andalso is_binary(TAG) -> jose_jwa:block_decrypt({xchacha20_poly1305, ?BITS}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(#jose_jwk{kty={KTYModule, KTY}}, EncryptedKey, JWEXC20PKW=#jose_jwe_alg_xc20p_kw{}) -> key_decrypt(KTYModule:derive_key(KTY), EncryptedKey, JWEXC20PKW). key_encrypt(DerivedKey, DecryptedKey, JWEXC20PKW=#jose_jwe_alg_xc20p_kw{iv=IV}) when is_binary(DerivedKey) andalso bit_size(DerivedKey) =:= ?BITS andalso is_binary(IV) -> {CipherText, CipherTag} = jose_jwa:block_encrypt({xchacha20_poly1305, ?BITS}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEXC20PKW#jose_jwe_alg_xc20p_kw{ tag = CipherTag }}; key_encrypt(DerivedKey, DecryptedKey, JWEXC20PKW=#jose_jwe_alg_xc20p_kw{iv=undefined}) -> key_encrypt(DerivedKey, DecryptedKey, JWEXC20PKW#jose_jwe_alg_xc20p_kw{ iv = crypto:strong_rand_bytes(24) }); key_encrypt(#jose_jwk{kty={KTYModule, KTY}}, DecryptedKey, JWEXC20PKW=#jose_jwe_alg_xc20p_kw{}) -> key_encrypt(KTYModule:derive_key(KTY), DecryptedKey, JWEXC20PKW). next_cek(_Key, {ENCModule, ENC}, ALG=#jose_jwe_alg_xc20p_kw{}) -> {ENCModule:next_cek(ENC), ALG}. %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private from_map_xc20p(A, F=#{ <<"iv">> := IV }) -> from_map_xc20p(A#jose_jwe_alg_xc20p_kw{ iv = jose_jwa_base64url:decode(IV) }, maps:remove(<<"iv">>, F)); from_map_xc20p(A, F=#{ <<"tag">> := TAG }) -> from_map_xc20p(A#jose_jwe_alg_xc20p_kw{ tag = jose_jwa_base64url:decode(TAG) }, maps:remove(<<"tag">>, F)); from_map_xc20p(A, F) -> {A, F}. %% @private to_map_xc20p(#jose_jwe_alg_xc20p_kw{ iv = undefined, tag = undefined }, F) -> F; to_map_xc20p(A=#jose_jwe_alg_xc20p_kw{ iv = IV }, F) when is_binary(IV) -> to_map_xc20p(A#jose_jwe_alg_xc20p_kw{ iv = undefined }, F#{ <<"iv">> => jose_jwa_base64url:encode(IV) }); to_map_xc20p(A=#jose_jwe_alg_xc20p_kw{ tag = TAG }, F) when is_binary(TAG) -> to_map_xc20p(A#jose_jwe_alg_xc20p_kw{ tag = undefined }, F#{ <<"tag">> => jose_jwa_base64url:encode(TAG) }). erlang-jose-1.10.1/src/jwe/jose_jwe_alg_aes_kw.erl0000644000232200023220000001332313605433351022414 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg_aes_kw). -behaviour(jose_jwe). -behaviour(jose_jwe_alg). -include("jose_jwk.hrl"). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_alg callbacks -export([generate_key/3]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([next_cek/3]). %% API %% Types -record(jose_jwe_alg_aes_kw, { bits = undefined :: undefined | 128 | 192 | 256, gcm = false :: boolean(), iv = undefined :: undefined | binary(), tag = undefined :: undefined | binary() }). -type alg() :: #jose_jwe_alg_aes_kw{}. -export_type([alg/0]). -define(A128KW, #jose_jwe_alg_aes_kw{bits=128, gcm=false}). -define(A192KW, #jose_jwe_alg_aes_kw{bits=192, gcm=false}). -define(A256KW, #jose_jwe_alg_aes_kw{bits=256, gcm=false}). -define(A128GCMKW, #jose_jwe_alg_aes_kw{bits=128, gcm=true}). -define(A192GCMKW, #jose_jwe_alg_aes_kw{bits=192, gcm=true}). -define(A256GCMKW, #jose_jwe_alg_aes_kw{bits=256, gcm=true}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"A128KW">> }) -> {?A128KW, maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"A192KW">> }) -> {?A192KW, maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"A256KW">> }) -> {?A256KW, maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"A128GCMKW">> }) -> from_map_aes_gcm(?A128GCMKW, maps:remove(<<"alg">>, F)); from_map(F = #{ <<"alg">> := <<"A192GCMKW">> }) -> from_map_aes_gcm(?A192GCMKW, maps:remove(<<"alg">>, F)); from_map(F = #{ <<"alg">> := <<"A256GCMKW">> }) -> from_map_aes_gcm(?A256GCMKW, maps:remove(<<"alg">>, F)). to_map(?A128KW, F) -> F#{ <<"alg">> => <<"A128KW">> }; to_map(?A192KW, F) -> F#{ <<"alg">> => <<"A192KW">> }; to_map(?A256KW, F) -> F#{ <<"alg">> => <<"A256KW">> }; to_map(A = ?A128GCMKW, F) -> to_map_aes_gcm(A, F#{ <<"alg">> => <<"A128GCMKW">> }); to_map(A = ?A192GCMKW, F) -> to_map_aes_gcm(A, F#{ <<"alg">> => <<"A192GCMKW">> }); to_map(A = ?A256GCMKW, F) -> to_map_aes_gcm(A, F#{ <<"alg">> => <<"A256GCMKW">> }). %%==================================================================== %% jose_jwe_alg callbacks %%==================================================================== generate_key(_Fields, {ENCModule, ENC}, ALG=#jose_jwe_alg_aes_kw{bits=Bits}) -> jose_jwe_alg:generate_key({oct, (Bits div 8)}, maps:get(<<"alg">>, to_map(ALG, #{})), ENCModule:algorithm(ENC)). key_decrypt(DerivedKey, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_aes_kw{bits=Bits, gcm=false}) when is_binary(DerivedKey) andalso bit_size(DerivedKey) =:= Bits -> jose_jwa_aes_kw:unwrap(EncryptedKey, DerivedKey); key_decrypt(DerivedKey, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_aes_kw{bits=Bits, gcm=true, iv=IV, tag=TAG}) when is_binary(DerivedKey) andalso bit_size(DerivedKey) =:= Bits andalso is_binary(IV) andalso is_binary(TAG) -> jose_jwa:block_decrypt({aes_gcm, Bits}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(#jose_jwk{kty={KTYModule, KTY}}, EncryptedKey, JWEAESKW=#jose_jwe_alg_aes_kw{}) -> key_decrypt(KTYModule:derive_key(KTY), EncryptedKey, JWEAESKW). key_encrypt(DerivedKey, DecryptedKey, JWEAESKW=#jose_jwe_alg_aes_kw{bits=Bits, gcm=false}) when is_binary(DerivedKey) andalso bit_size(DerivedKey) =:= Bits -> {jose_jwa_aes_kw:wrap(DecryptedKey, DerivedKey), JWEAESKW}; key_encrypt(DerivedKey, DecryptedKey, JWEAESKW=#jose_jwe_alg_aes_kw{bits=Bits, gcm=true, iv=IV}) when is_binary(DerivedKey) andalso bit_size(DerivedKey) =:= Bits andalso is_binary(IV) -> {CipherText, CipherTag} = jose_jwa:block_encrypt({aes_gcm, Bits}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEAESKW#jose_jwe_alg_aes_kw{ tag = CipherTag }}; key_encrypt(DerivedKey, DecryptedKey, JWEAESKW=#jose_jwe_alg_aes_kw{gcm=true, iv=undefined}) -> key_encrypt(DerivedKey, DecryptedKey, JWEAESKW#jose_jwe_alg_aes_kw{ iv = crypto:strong_rand_bytes(12) }); key_encrypt(#jose_jwk{kty={KTYModule, KTY}}, DecryptedKey, JWEAESKW=#jose_jwe_alg_aes_kw{}) -> key_encrypt(KTYModule:derive_key(KTY), DecryptedKey, JWEAESKW). next_cek(_Key, {ENCModule, ENC}, ALG=#jose_jwe_alg_aes_kw{}) -> {ENCModule:next_cek(ENC), ALG}. %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private from_map_aes_gcm(A, F=#{ <<"iv">> := IV }) -> from_map_aes_gcm(A#jose_jwe_alg_aes_kw{ iv = jose_jwa_base64url:decode(IV) }, maps:remove(<<"iv">>, F)); from_map_aes_gcm(A, F=#{ <<"tag">> := TAG }) -> from_map_aes_gcm(A#jose_jwe_alg_aes_kw{ tag = jose_jwa_base64url:decode(TAG) }, maps:remove(<<"tag">>, F)); from_map_aes_gcm(A, F) -> {A, F}. %% @private to_map_aes_gcm(#jose_jwe_alg_aes_kw{ iv = undefined, tag = undefined }, F) -> F; to_map_aes_gcm(A=#jose_jwe_alg_aes_kw{ iv = IV }, F) when is_binary(IV) -> to_map_aes_gcm(A#jose_jwe_alg_aes_kw{ iv = undefined }, F#{ <<"iv">> => jose_jwa_base64url:encode(IV) }); to_map_aes_gcm(A=#jose_jwe_alg_aes_kw{ tag = TAG }, F) when is_binary(TAG) -> to_map_aes_gcm(A#jose_jwe_alg_aes_kw{ tag = undefined }, F#{ <<"tag">> => jose_jwa_base64url:encode(TAG) }). erlang-jose-1.10.1/src/jwe/jose_jwe.erl0000644000232200023220000003465613605433351020254 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 21 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe). -include("jose_jwe.hrl"). -include("jose_jwk.hrl"). -callback from_map(Fields) -> State when Fields :: map(), State :: any(). -callback to_map(State, Fields) -> Map when State :: any(), Fields :: map(), Map :: map(). %% Decode API -export([from/1]). -export([from_binary/1]). -export([from_file/1]). -export([from_map/1]). %% Encode API -export([to_binary/1]). -export([to_file/2]). -export([to_map/1]). %% API -export([block_decrypt/2]). -export([block_encrypt/3]). -export([block_encrypt/4]). -export([block_encrypt/5]). -export([compact/1]). -export([compress/2]). -export([expand/1]). -export([generate_key/1]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([merge/2]). -export([next_cek/2]). -export([next_iv/1]). -export([uncompress/2]). -define(ALG_AES_KW_MODULE, jose_jwe_alg_aes_kw). -define(ALG_C20P_KW_MODULE, jose_jwe_alg_c20p_kw). -define(ALG_XC20P_KW_MODULE, jose_jwe_alg_xc20p_kw). -define(ALG_DIR_MODULE, jose_jwe_alg_dir). -define(ALG_ECDH_1PU_MODULE, jose_jwe_alg_ecdh_1pu). -define(ALG_ECDH_ES_MODULE, jose_jwe_alg_ecdh_es). -define(ALG_PBES2_MODULE, jose_jwe_alg_pbes2). -define(ALG_RSA_MODULE, jose_jwe_alg_rsa). -define(ENC_AES_MODULE, jose_jwe_enc_aes). -define(ENC_C20P_MODULE, jose_jwe_enc_c20p). -define(ENC_XC20P_MODULE, jose_jwe_enc_xc20p). -define(ZIP_MODULE, jose_jwe_zip). %%==================================================================== %% Decode API functions %%==================================================================== from({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> from_map({Modules, Map}); from({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> from_binary({Modules, Binary}); from(JWE=#jose_jwe{}) -> JWE; from(Other) when is_map(Other) orelse is_binary(Other) -> from({#{}, Other}). from_binary({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> from_map({Modules, jose:decode(Binary)}); from_binary(Binary) when is_binary(Binary) -> from_binary({#{}, Binary}). from_file({Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_binary({Modules, Binary}); ReadError -> ReadError end; from_file(File) when is_binary(File) orelse is_list(File) -> from_file({#{}, File}). from_map(Map) when is_map(Map) -> from_map({#{}, Map}); from_map({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> from_map({#jose_jwe{}, Modules, Map}); from_map({JWE, Modules = #{ alg := Module }, Map=#{ <<"alg">> := _ }}) -> {ALG, Fields} = Module:from_map(Map), from_map({JWE#jose_jwe{ alg = {Module, ALG} }, maps:remove(alg, Modules), Fields}); from_map({JWE, Modules = #{ enc := Module }, Map=#{ <<"enc">> := _ }}) -> {ENC, Fields} = Module:from_map(Map), from_map({JWE#jose_jwe{ enc = {Module, ENC} }, maps:remove(enc, Modules), Fields}); from_map({JWE, Modules = #{ zip := Module }, Map=#{ <<"zip">> := _ }}) -> {ZIP, Fields} = Module:from_map(Map), from_map({JWE#jose_jwe{ zip = {Module, ZIP} }, maps:remove(zip, Modules), Fields}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "A", _, _, _, "GCMKW", _/binary >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_AES_KW_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "A", _, _, _, "KW", _/binary >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_AES_KW_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "C20PKW" >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_C20P_KW_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "dir", _/binary >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_DIR_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "ECDH-1PU", _/binary >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_ECDH_1PU_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "ECDH-ES", _/binary >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_ECDH_ES_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "PBES2", _/binary >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_PBES2_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "RSA", _/binary >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_RSA_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"alg">> := << "XC20PKW" >> }}) -> from_map({JWE, Modules#{ alg => ?ALG_XC20P_KW_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"enc">> := << "A", _/binary >> }}) -> from_map({JWE, Modules#{ enc => ?ENC_AES_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"enc">> := << "C20P" >> }}) -> from_map({JWE, Modules#{ enc => ?ENC_C20P_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"enc">> := << "XC20P" >> }}) -> from_map({JWE, Modules#{ enc => ?ENC_XC20P_MODULE }, Map}); from_map({JWE, Modules, Map=#{ <<"zip">> := << "DEF" >> }}) -> from_map({JWE, Modules#{ zip => ?ZIP_MODULE }, Map}); from_map({#jose_jwe{ alg = undefined, enc = undefined }, _Modules, _Map}) -> {error, {missing_required_keys, [<<"alg">>, <<"enc">>]}}; from_map({JWE, _Modules, Fields}) -> case {maps:is_key(<<"alg">>, Fields), maps:is_key(<<"enc">>, Fields)} of {true, true} -> {error, {invalid_fields, [{<<"alg">>, maps:get(<<"alg">>, Fields)}, {<<"enc">>, maps:get(<<"enc">>, Fields)}]}}; {true, false} -> {error, {invalid_fields, [{<<"alg">>, maps:get(<<"alg">>, Fields)}]}}; {false, true} -> {error, {invalid_fields, [{<<"enc">>, maps:get(<<"enc">>, Fields)}]}}; {false, false} -> JWE#jose_jwe{ fields = Fields } end. %%==================================================================== %% Encode API functions %%==================================================================== to_binary(JWE=#jose_jwe{}) -> {Modules, Map} = to_map(JWE), {Modules, jose:encode(Map)}; to_binary(Other) -> to_binary(from(Other)). to_file(File, JWE=#jose_jwe{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_binary(JWE), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_file(File, Other) when is_binary(File) orelse is_list(File) -> to_file(File, from(Other)). to_map(JWE=#jose_jwe{fields=Fields}) -> record_to_map(JWE, #{}, Fields); to_map(Other) -> to_map(from(Other)). %%==================================================================== %% API functions %%==================================================================== block_decrypt(Key, EncryptedMap) when is_map(EncryptedMap) -> block_decrypt(Key, {#{}, EncryptedMap}); block_decrypt(Key, EncryptedBinary) when is_binary(EncryptedBinary) -> block_decrypt(Key, expand(EncryptedBinary)); block_decrypt(Key, {Modules, EncryptedBinary}) when is_binary(EncryptedBinary) -> block_decrypt(Key, expand({Modules, EncryptedBinary})); block_decrypt(Key, {Modules, EncryptedMap=#{ <<"protected">> := Protected, <<"encrypted_key">> := EncodedEncryptedKey, <<"iv">> := EncodedIV, <<"ciphertext">> := EncodedCipherText, <<"tag">> := EncodedCipherTag}}) -> case maps:is_key(<<"aad">>, EncryptedMap) of false -> JWE = #jose_jwe{enc={ENCModule, ENC}} = from_binary({Modules, jose_jwa_base64url:decode(Protected)}), EncryptedKey = jose_jwa_base64url:decode(EncodedEncryptedKey), IV = jose_jwa_base64url:decode(EncodedIV), CipherText = jose_jwa_base64url:decode(EncodedCipherText), CipherTag = jose_jwa_base64url:decode(EncodedCipherTag), case key_decrypt(Key, EncryptedKey, JWE) of error -> {error, JWE}; CEK when is_binary(CEK) -> PlainText = uncompress(ENCModule:block_decrypt({Protected, CipherText, CipherTag}, CEK, IV, ENC), JWE), {PlainText, JWE} end; true -> EncodedAAD = maps:get(<<"aad">>, EncryptedMap), ConcatAAD = << Protected/binary, $., EncodedAAD/binary >>, JWE = #jose_jwe{enc={ENCModule, ENC}} = from_binary({Modules, jose_jwa_base64url:decode(Protected)}), EncryptedKey = jose_jwa_base64url:decode(EncodedEncryptedKey), IV = jose_jwa_base64url:decode(EncodedIV), CipherText = jose_jwa_base64url:decode(EncodedCipherText), CipherTag = jose_jwa_base64url:decode(EncodedCipherTag), case key_decrypt(Key, EncryptedKey, JWE) of error -> {error, JWE}; CEK when is_binary(CEK) -> PlainText = uncompress(ENCModule:block_decrypt({ConcatAAD, CipherText, CipherTag}, CEK, IV, ENC), JWE), {PlainText, JWE} end end. block_encrypt(Key, Block, JWE0=#jose_jwe{}) -> {CEK, JWE1} = next_cek(Key, JWE0), block_encrypt(Key, Block, CEK, JWE1); block_encrypt(Key, PlainText, Other) -> block_encrypt(Key, PlainText, from(Other)). block_encrypt(Key, Block, CEK, JWE=#jose_jwe{}) -> IV = next_iv(JWE), block_encrypt(Key, Block, CEK, IV, JWE); block_encrypt(Key, Block, CEK, Other) -> block_encrypt(Key, Block, CEK, from(Other)). block_encrypt(Key, PlainText, CEK, IV, JWE0=#jose_jwe{enc={ENCModule, ENC}}) when is_binary(PlainText) -> {EncryptedKey, JWE1} = key_encrypt(Key, CEK, JWE0), {Modules, ProtectedBinary} = to_binary(JWE1), Protected = jose_jwa_base64url:encode(ProtectedBinary), {CipherText, CipherTag} = ENCModule:block_encrypt({Protected, compress(PlainText, JWE1)}, CEK, IV, ENC), {Modules, #{ <<"protected">> => Protected, <<"encrypted_key">> => jose_jwa_base64url:encode(EncryptedKey), <<"iv">> => jose_jwa_base64url:encode(IV), <<"ciphertext">> => jose_jwa_base64url:encode(CipherText), <<"tag">> => jose_jwa_base64url:encode(CipherTag) }}; block_encrypt(Key, {AAD0, PlainText}, CEK, IV, JWE0=#jose_jwe{enc={ENCModule, ENC}}) when is_binary(AAD0) andalso is_binary(PlainText) -> {EncryptedKey, JWE1} = key_encrypt(Key, CEK, JWE0), {Modules, ProtectedBinary} = to_binary(JWE1), Protected = jose_jwa_base64url:encode(ProtectedBinary), AAD1 = jose_jwa_base64url:encode(AAD0), ConcatAAD = << Protected/binary, $., AAD1/binary >>, {CipherText, CipherTag} = ENCModule:block_encrypt({ConcatAAD, compress(PlainText, JWE1)}, CEK, IV, ENC), {Modules, #{ <<"protected">> => Protected, <<"encrypted_key">> => jose_jwa_base64url:encode(EncryptedKey), <<"iv">> => jose_jwa_base64url:encode(IV), <<"ciphertext">> => jose_jwa_base64url:encode(CipherText), <<"tag">> => jose_jwa_base64url:encode(CipherTag), <<"aad">> => AAD1 }}; block_encrypt(Key, Block, CEK, IV, Other) when is_binary(Block) orelse (is_tuple(Block) andalso tuple_size(Block) =:= 2) -> block_encrypt(Key, Block, CEK, IV, from(Other)). compact({Modules, EncryptedMap=#{ <<"protected">> := Protected, <<"encrypted_key">> := EncryptedKey, <<"iv">> := InitializationVector, <<"ciphertext">> := CipherText, <<"tag">> := AuthenticationTag}}) -> case maps:is_key(<<"aad">>, EncryptedMap) of false -> {Modules, << Protected/binary, $., EncryptedKey/binary, $., InitializationVector/binary, $., CipherText/binary, $., AuthenticationTag/binary >>}; true -> erlang:error({badarg, [{Modules, EncryptedMap}]}) end; compact(Map) when is_map(Map) -> compact({#{}, Map}). compress(PlainText, #jose_jwe{zip={Module, ZIP}}) -> Module:compress(PlainText, ZIP); compress(PlainText, #jose_jwe{}) -> PlainText; compress(PlainText, Other) -> compress(PlainText, from(Other)). expand({Modules, Binary}) when is_binary(Binary) -> case binary:split(Binary, <<".">>, [global]) of [Protected, EncryptedKey, InitializationVector, CipherText, AuthenticationTag] -> {Modules, #{ <<"protected">> => Protected, <<"encrypted_key">> => EncryptedKey, <<"iv">> => InitializationVector, <<"ciphertext">> => CipherText, <<"tag">> => AuthenticationTag }}; _ -> erlang:error({badarg, [{Modules, Binary}]}) end; expand(Binary) when is_binary(Binary) -> expand({#{}, Binary}). generate_key(List) when is_list(List) -> [generate_key(Element) || Element <- List]; generate_key(#jose_jwe{alg={ALGModule, ALG}, enc={ENCModule, ENC}, fields=Fields}) -> ALGModule:generate_key(Fields, {ENCModule, ENC}, ALG); generate_key(Other) -> generate_key(from(Other)). key_decrypt(Key, EncryptedKey, #jose_jwe{alg={ALGModule, ALG}, enc={ENCModule, ENC}}) -> ALGModule:key_decrypt(Key, {ENCModule, ENC, EncryptedKey}, ALG); key_decrypt(Key, EncryptedKey, JWE=#jose_jwe{}) -> erlang:error({badarg, [Key, EncryptedKey, JWE]}); key_decrypt(Key, EncryptedKey, Other) -> key_decrypt(Key, EncryptedKey, from(Other)). key_encrypt(Key, DecryptedKey, JWE0=#jose_jwe{alg={ALGModule, ALG0}}) -> {EncryptedKey, ALG1} = ALGModule:key_encrypt(Key, DecryptedKey, ALG0), JWE1 = JWE0#jose_jwe{alg={ALGModule, ALG1}}, {EncryptedKey, JWE1}; key_encrypt(Key, EncryptedKey, Other) -> key_encrypt(Key, EncryptedKey, from(Other)). merge(LeftJWE=#jose_jwe{}, RightMap) when is_map(RightMap) -> {Modules, LeftMap} = to_map(LeftJWE), from_map({Modules, maps:merge(LeftMap, RightMap)}); merge(LeftOther, RightJWE=#jose_jwe{}) -> merge(LeftOther, element(2, to_map(RightJWE))); merge(LeftOther, RightMap) when is_map(RightMap) -> merge(from(LeftOther), RightMap). next_cek(Key, JWE0=#jose_jwe{alg={ALGModule, ALG0}, enc={ENCModule, ENC}}) -> {DecryptedKey, ALG1} = ALGModule:next_cek(Key, {ENCModule, ENC}, ALG0), JWE1 = JWE0#jose_jwe{alg={ALGModule, ALG1}}, {DecryptedKey, JWE1}; next_cek(Key, Other) -> next_cek(Key, from(Other)). next_iv(#jose_jwe{enc={ENCModule, ENC}}) -> ENCModule:next_iv(ENC); next_iv(Other) -> next_iv(from(Other)). uncompress(CipherText, #jose_jwe{zip={Module, ZIP}}) -> Module:uncompress(CipherText, ZIP); uncompress(CipherText, #jose_jwe{}) -> CipherText; uncompress(CipherText, Other) -> uncompress(CipherText, from(Other)). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private record_to_map(JWE=#jose_jwe{alg={Module, ALG}}, Modules, Fields0) -> Fields1 = Module:to_map(ALG, Fields0), record_to_map(JWE#jose_jwe{alg=undefined}, Modules#{ alg => Module }, Fields1); record_to_map(JWE=#jose_jwe{enc={Module, ENC}}, Modules, Fields0) -> Fields1 = Module:to_map(ENC, Fields0), record_to_map(JWE#jose_jwe{enc=undefined}, Modules#{ enc => Module }, Fields1); record_to_map(JWE=#jose_jwe{zip={Module, ZIP}}, Modules, Fields0) -> Fields1 = Module:to_map(ZIP, Fields0), record_to_map(JWE#jose_jwe{zip=undefined}, Modules#{ zip => Module }, Fields1); record_to_map(_JWE, Modules, Fields) -> {Modules, Fields}. erlang-jose-1.10.1/src/jwe/jose_jwe_zip.erl0000644000232200023220000000440513605433351021123 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 22 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_zip). -behaviour(jose_jwe). -callback compress(Uncompressed, ZIP) -> Compressed when Uncompressed :: iodata(), ZIP :: any(), Compressed :: iodata(). -callback uncompress(Compressed, ZIP) -> Uncompressed when Compressed :: iodata(), ZIP :: any(), Uncompressed :: iodata(). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_zip callbacks -export([compress/2]). -export([uncompress/2]). %% API -export([zip_supported/0]). %% Types -type zip() :: zlib. -export_type([zip/0]). -define(DEF, zlib). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(Fields = #{ <<"zip">> := <<"DEF">> }) -> {?DEF, maps:remove(<<"zip">>, Fields)}. to_map(?DEF, Fields) -> Fields#{ <<"zip">> => <<"DEF">> }. %%==================================================================== %% jose_jwe_zip callbacks %%==================================================================== compress(Uncompressed, zlib) -> Z = zlib:open(), ok = zlib:deflateInit(Z, default, deflated, -15, 8, default), Compressed = zlib:deflate(Z, Uncompressed, finish), ok = zlib:deflateEnd(Z), ok = zlib:close(Z), iolist_to_binary(Compressed). uncompress(Compressed, zlib) -> Z = zlib:open(), ok = zlib:inflateInit(Z, -15), Uncompressed = zlib:inflate(Z, Compressed), ok = zlib:inflateEnd(Z), ok = zlib:close(Z), iolist_to_binary(Uncompressed). %%==================================================================== %% API functions %%==================================================================== zip_supported() -> [zlib]. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwe/jose_jwe_alg_dir.erl0000644000232200023220000000415713605433351021726 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg_dir). -behaviour(jose_jwe). -behaviour(jose_jwe_alg). -include("jose_jwk.hrl"). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_alg callbacks -export([generate_key/3]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([next_cek/3]). %% API %% Types -type alg() :: dir. -export_type([alg/0]). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"dir">> }) -> {dir, maps:remove(<<"alg">>, F)}. to_map(dir, F) -> F#{ <<"alg">> => <<"dir">> }. %%==================================================================== %% jose_jwe_alg callbacks %%==================================================================== generate_key(_Fields, {ENCModule, ENC}, dir) -> jose_jwe_alg:generate_key({oct, (ENCModule:bits(ENC) div 8)}, <<"dir">>, ENCModule:algorithm(ENC)). key_decrypt(Key, _EncryptedKey, dir) when is_binary(Key) -> Key; key_decrypt(#jose_jwk{kty={KTYModule, KTY}}, _EncryptedKey, dir) -> KTYModule:derive_key(KTY). key_encrypt(_Key, _DecryptedKey, dir) -> {<<>>, dir}. next_cek(Key, {_ENCModule, _ENC}, dir) when is_binary(Key) -> {Key, dir}; next_cek(#jose_jwk{kty={KTYModule, KTY}}, {ENCModule, ENC}, dir) -> next_cek(KTYModule:derive_key(KTY), {ENCModule, ENC}, dir). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwe/jose_jwe_alg.erl0000644000232200023220000000277513605433351021074 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg). -callback key_decrypt(Key, {ENCModule, ENC, EncryptedKey}, ALG) -> DecryptedKey when Key :: any(), ENCModule :: module(), ENC :: any(), EncryptedKey :: iodata(), ALG :: any(), DecryptedKey :: iodata(). -callback key_encrypt(Key, DecryptedKey, ALG) -> {EncryptedKey, NewALG} when Key :: any(), DecryptedKey :: iodata(), ALG :: any(), EncryptedKey :: iodata(), NewALG :: any(). -callback next_cek(Key, {ENCModule, ENC}, ALG) -> {DecryptedKey, NewALG} when Key :: any(), ENCModule :: module(), ENC :: any(), ALG :: any(), DecryptedKey :: iodata(), NewALG :: any(). %% API -export([generate_key/3]). %%==================================================================== %% API functions %%==================================================================== generate_key(Parameters, Algorithm, Encryption) -> jose_jwk:merge(jose_jwk:generate_key(Parameters), #{ <<"alg">> => Algorithm, <<"enc">> => Encryption, <<"use">> => <<"enc">> }). erlang-jose-1.10.1/src/jwe/jose_jwe_alg_ecdh_1pu.erl0000644000232200023220000004065713605433351022645 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc Key Agreement with Elliptic Curve Diffie-Hellman One-Pass Unified Model (ECDH-1PU) %%% See https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02 %%% %%% @end %%% Created : 29 Dec 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg_ecdh_1pu). -behaviour(jose_jwe). -behaviour(jose_jwe_alg). -include_lib("public_key/include/public_key.hrl"). -include("jose_jwk.hrl"). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_alg callbacks -export([generate_key/3]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([next_cek/3]). %% API -export([algorithm/1]). %% Types -type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'ECParameters'{}} | term(). -record(jose_jwe_alg_ecdh_1pu, { epk = undefined :: undefined | {ec_public_key(), map()}, apu = undefined :: undefined | binary(), apv = undefined :: undefined | binary(), wrap = undefined :: undefined | aes_gcm_kw | aes_kw | c20p_kw | xc20p_kw, bits = undefined :: undefined | 128 | 192 | 256, iv = undefined :: undefined | binary(), tag = undefined :: undefined | binary() }). -type alg() :: #jose_jwe_alg_ecdh_1pu{}. -export_type([alg/0]). -define(ECDH_1PU, #jose_jwe_alg_ecdh_1pu{}). -define(ECDH_1PU_A128GCMKW, #jose_jwe_alg_ecdh_1pu{wrap=aes_gcm_kw, bits=128}). -define(ECDH_1PU_A192GCMKW, #jose_jwe_alg_ecdh_1pu{wrap=aes_gcm_kw, bits=192}). -define(ECDH_1PU_A256GCMKW, #jose_jwe_alg_ecdh_1pu{wrap=aes_gcm_kw, bits=256}). -define(ECDH_1PU_A128KW, #jose_jwe_alg_ecdh_1pu{wrap=aes_kw, bits=128}). -define(ECDH_1PU_A192KW, #jose_jwe_alg_ecdh_1pu{wrap=aes_kw, bits=192}). -define(ECDH_1PU_A256KW, #jose_jwe_alg_ecdh_1pu{wrap=aes_kw, bits=256}). -define(ECDH_1PU_C20PKW, #jose_jwe_alg_ecdh_1pu{wrap=c20p_kw, bits=256}). -define(ECDH_1PU_XC20PKW, #jose_jwe_alg_ecdh_1pu{wrap=xc20p_kw, bits=256}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"ECDH-1PU">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU); from_map(F = #{ <<"alg">> := <<"ECDH-1PU+A128GCMKW">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU_A128GCMKW); from_map(F = #{ <<"alg">> := <<"ECDH-1PU+A192GCMKW">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU_A192GCMKW); from_map(F = #{ <<"alg">> := <<"ECDH-1PU+A256GCMKW">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU_A256GCMKW); from_map(F = #{ <<"alg">> := <<"ECDH-1PU+A128KW">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU_A128KW); from_map(F = #{ <<"alg">> := <<"ECDH-1PU+A192KW">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU_A192KW); from_map(F = #{ <<"alg">> := <<"ECDH-1PU+A256KW">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU_A256KW); from_map(F = #{ <<"alg">> := <<"ECDH-1PU+C20PKW">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU_C20PKW); from_map(F = #{ <<"alg">> := <<"ECDH-1PU+XC20PKW">> }) -> from_map_ecdh_1pu(maps:remove(<<"alg">>, F), ?ECDH_1PU_XC20PKW). to_map(A = ?ECDH_1PU_A128GCMKW, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU+A128GCMKW">> }, A); to_map(A = ?ECDH_1PU_A192GCMKW, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU+A192GCMKW">> }, A); to_map(A = ?ECDH_1PU_A256GCMKW, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU+A256GCMKW">> }, A); to_map(A = ?ECDH_1PU_A128KW, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU+A128KW">> }, A); to_map(A = ?ECDH_1PU_A192KW, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU+A192KW">> }, A); to_map(A = ?ECDH_1PU_A256KW, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU+A256KW">> }, A); to_map(A = ?ECDH_1PU_C20PKW, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU+C20PKW">> }, A); to_map(A = ?ECDH_1PU_XC20PKW, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU+XC20PKW">> }, A); to_map(A = ?ECDH_1PU, F) -> to_map_ecdh_1pu(F#{ <<"alg">> => <<"ECDH-1PU">> }, A). %%==================================================================== %% jose_jwe_alg callbacks %%==================================================================== generate_key(_Fields, {ENCModule, ENC}, ALG=#jose_jwe_alg_ecdh_1pu{epk=EphemeralPublicJWK=#jose_jwk{}}) -> jose_jwe_alg:generate_key(EphemeralPublicJWK, maps:get(<<"alg">>, to_map(ALG, #{})), ENCModule:algorithm(ENC)); generate_key(_Fields, {ENCModule, ENC}, ALG=#jose_jwe_alg_ecdh_1pu{}) -> jose_jwe_alg:generate_key({ec, <<"P-521">>}, maps:get(<<"alg">>, to_map(ALG, #{})), ENCModule:algorithm(ENC)). key_decrypt({UStaticPublicKey=#jose_jwk{}, VStaticSecretKey=#jose_jwk{}, UEphemeralKey=#jose_jwk{}}, EncryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{epk=UEphemeralPublicKey=#jose_jwk{}}) -> case jose_jwk:thumbprint(UEphemeralKey) =:= jose_jwk:thumbprint(UEphemeralPublicKey) of true -> key_decrypt({UStaticPublicKey, VStaticSecretKey}, EncryptedKey, JWEECDH1PU); false -> error end; key_decrypt({UStaticPublicKey=#jose_jwk{}, VStaticSecretKey=#jose_jwk{}, UEphemeralPublicKey=#jose_jwk{}}, EncryptedKey, JWEECDH1PU0=#jose_jwe_alg_ecdh_1pu{epk=undefined}) -> JWEECDH1PU = JWEECDH1PU0#jose_jwe_alg_ecdh_1pu{epk=UEphemeralPublicKey}, key_decrypt({UStaticPublicKey, VStaticSecretKey}, EncryptedKey, JWEECDH1PU); key_decrypt({UStaticPublicKey=#jose_jwk{}, VStaticSecretKey=#jose_jwk{}}, EncryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{epk=UEphemeralPublicKey=#jose_jwk{}}) -> Ze = jose_jwk:shared_secret(UEphemeralPublicKey, VStaticSecretKey), Zs = jose_jwk:shared_secret(UStaticPublicKey, VStaticSecretKey), Z = <>, key_decrypt(Z, EncryptedKey, JWEECDH1PU); key_decrypt(Z, {ENCModule, ENC, <<>>}, #jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=undefined, bits=undefined}) when is_binary(Z) -> Algorithm = ENCModule:algorithm(ENC), KeyDataLen = ENCModule:bits(ENC), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), DerivedKey; key_decrypt(Z, {_ENCModule, _ENC, EncryptedKey}, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=aes_gcm_kw, bits=KeyDataLen, iv=IV, tag=TAG}) when is_binary(Z) andalso is_binary(IV) andalso is_binary(TAG) -> Algorithm = algorithm(JWEECDH1PU), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), jose_jwa:block_decrypt({aes_gcm, KeyDataLen}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(Z, {_ENCModule, _ENC, EncryptedKey}, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=aes_kw, bits=KeyDataLen}) when is_binary(Z) -> Algorithm = algorithm(JWEECDH1PU), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), jose_jwa_aes_kw:unwrap(EncryptedKey, DerivedKey); key_decrypt(Z, {_ENCModule, _ENC, EncryptedKey}, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=c20p_kw, bits=KeyDataLen, iv=IV, tag=TAG}) when is_binary(Z) andalso is_binary(IV) andalso is_binary(TAG) -> Algorithm = algorithm(JWEECDH1PU), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), jose_jwa:block_decrypt({chacha20_poly1305, KeyDataLen}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(Z, {_ENCModule, _ENC, EncryptedKey}, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=xc20p_kw, bits=KeyDataLen, iv=IV, tag=TAG}) when is_binary(Z) andalso is_binary(IV) andalso is_binary(TAG) -> Algorithm = algorithm(JWEECDH1PU), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), jose_jwa:block_decrypt({xchacha20_poly1305, KeyDataLen}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}). key_encrypt(_Key, _DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{wrap=undefined, bits=undefined}) -> {<<>>, JWEECDH1PU}; key_encrypt({VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}}, DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{epk=UEphemeralPublicKey=#jose_jwk{}}) -> case jose_jwk:thumbprint(UEphemeralSecretKey) =:= jose_jwk:thumbprint(UEphemeralPublicKey) of true -> Ze = jose_jwk:shared_secret(VStaticPublicKey, UEphemeralSecretKey), Zs = jose_jwk:shared_secret(VStaticPublicKey, UStaticSecretKey), Z = <>, key_encrypt(Z, DecryptedKey, JWEECDH1PU); false -> error end; key_encrypt({VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}}, DecryptedKey, JWEECDH1PU0=#jose_jwe_alg_ecdh_1pu{wrap=undefined, bits=undefined, epk=undefined}) -> UEphemeralPublicKey = jose_jwk:to_public(UEphemeralSecretKey), JWEECDH1PU1 = JWEECDH1PU0#jose_jwe_alg_ecdh_1pu{epk=UEphemeralPublicKey}, key_encrypt({VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey}, DecryptedKey, JWEECDH1PU1); key_encrypt(#jose_jwk{kty={KTYModule, KTY}}, DecryptedKey, JWEECDH1PU) -> DerivedKey = KTYModule:derive_key(KTY), key_encrypt(DerivedKey, DecryptedKey, JWEECDH1PU); key_encrypt(Z, DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=aes_gcm_kw, bits=KeyDataLen, iv=IV}) when is_binary(Z) andalso is_binary(IV) -> Algorithm = algorithm(JWEECDH1PU), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {CipherText, CipherTag} = jose_jwa:block_encrypt({aes_gcm, KeyDataLen}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEECDH1PU#jose_jwe_alg_ecdh_1pu{ tag = CipherTag }}; key_encrypt(Z, DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=aes_kw, bits=KeyDataLen}) when is_binary(Z) -> Algorithm = algorithm(JWEECDH1PU), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {jose_jwa_aes_kw:wrap(DecryptedKey, DerivedKey), JWEECDH1PU}; key_encrypt(Z, DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=c20p_kw, bits=KeyDataLen, iv=IV}) when is_binary(Z) andalso is_binary(IV) -> Algorithm = algorithm(JWEECDH1PU), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {CipherText, CipherTag} = jose_jwa:block_encrypt({chacha20_poly1305, KeyDataLen}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEECDH1PU#jose_jwe_alg_ecdh_1pu{ tag = CipherTag }}; key_encrypt(Z, DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=xc20p_kw, bits=KeyDataLen, iv=IV}) when is_binary(Z) andalso is_binary(IV) -> Algorithm = algorithm(JWEECDH1PU), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {CipherText, CipherTag} = jose_jwa:block_encrypt({xchacha20_poly1305, KeyDataLen}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEECDH1PU#jose_jwe_alg_ecdh_1pu{ tag = CipherTag }}; key_encrypt(Z, DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{wrap=aes_gcm_kw, iv=undefined}) when is_binary(Z) -> key_encrypt(Z, DecryptedKey, JWEECDH1PU#jose_jwe_alg_ecdh_1pu{ iv = crypto:strong_rand_bytes(12) }); key_encrypt(Z, DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{wrap=c20p_kw, iv=undefined}) when is_binary(Z) -> key_encrypt(Z, DecryptedKey, JWEECDH1PU#jose_jwe_alg_ecdh_1pu{ iv = crypto:strong_rand_bytes(12) }); key_encrypt(Z, DecryptedKey, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{wrap=xc20p_kw, iv=undefined}) when is_binary(Z) -> key_encrypt(Z, DecryptedKey, JWEECDH1PU#jose_jwe_alg_ecdh_1pu{ iv = crypto:strong_rand_bytes(24) }). next_cek({VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}}, {ENCModule, ENC}, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{bits=undefined, epk=UEphemeralPublicKey=#jose_jwk{}}) -> case jose_jwk:thumbprint(UEphemeralSecretKey) =:= jose_jwk:thumbprint(UEphemeralPublicKey) of true -> Ze = jose_jwk:shared_secret(VStaticPublicKey, UEphemeralSecretKey), Zs = jose_jwk:shared_secret(VStaticPublicKey, UStaticSecretKey), Z = <>, next_cek(Z, {ENCModule, ENC}, JWEECDH1PU); false -> error end; next_cek({VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}}, {ENCModule, ENC}, JWEECDH1PU0=#jose_jwe_alg_ecdh_1pu{wrap=undefined, bits=undefined, epk=undefined}) -> UEphemeralPublicKey = jose_jwk:to_public(UEphemeralSecretKey), JWEECDH1PU1 = JWEECDH1PU0#jose_jwe_alg_ecdh_1pu{epk=UEphemeralPublicKey}, next_cek({VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey}, {ENCModule, ENC}, JWEECDH1PU1); next_cek(#jose_jwk{kty={KTYModule, KTY}}, {ENC, ENCModule}, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{wrap=undefined, bits=undefined}) -> DerivedKey = KTYModule:derive_key(KTY), next_cek(DerivedKey, {ENCModule, ENC}, JWEECDH1PU); next_cek(Z, {ENCModule, ENC}, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{apu=APU, apv=APV, wrap=undefined, bits=undefined}) when is_binary(Z) -> Algorithm = ENCModule:algorithm(ENC), KeyDataLen = ENCModule:bits(ENC), SuppPubInfo = << KeyDataLen:1/unsigned-big-integer-unit:32 >>, DerivedKey = jose_jwa_concat_kdf:kdf(sha256, Z, {Algorithm, APU, APV, SuppPubInfo}, KeyDataLen), {DerivedKey, JWEECDH1PU}; next_cek(_Key, {ENCModule, ENC}, JWEECDH1PU=#jose_jwe_alg_ecdh_1pu{}) -> {ENCModule:next_cek(ENC), JWEECDH1PU}. %%==================================================================== %% API functions %%==================================================================== algorithm(?ECDH_1PU_A128GCMKW) -> <<"ECDH-1PU+A128GCMKW">>; algorithm(?ECDH_1PU_A192GCMKW) -> <<"ECDH-1PU+A192GCMKW">>; algorithm(?ECDH_1PU_A256GCMKW) -> <<"ECDH-1PU+A256GCMKW">>; algorithm(?ECDH_1PU_A128KW) -> <<"ECDH-1PU+A128KW">>; algorithm(?ECDH_1PU_A192KW) -> <<"ECDH-1PU+A192KW">>; algorithm(?ECDH_1PU_A256KW) -> <<"ECDH-1PU+A256KW">>; algorithm(?ECDH_1PU_C20PKW) -> <<"ECDH-1PU+C20PKW">>; algorithm(?ECDH_1PU_XC20PKW) -> <<"ECDH-1PU+XC20PKW">>; algorithm(?ECDH_1PU) -> <<"ECDH-1PU">>. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private from_map_ecdh_1pu(F = #{ <<"epk">> := EPK }, H) -> from_map_ecdh_1pu(maps:remove(<<"epk">>, F), H#jose_jwe_alg_ecdh_1pu{ epk = jose_jwk:from_map(EPK) }); from_map_ecdh_1pu(F = #{ <<"apu">> := APU }, H) -> from_map_ecdh_1pu(maps:remove(<<"apu">>, F), H#jose_jwe_alg_ecdh_1pu{ apu = jose_jwa_base64url:decode(APU) }); from_map_ecdh_1pu(F = #{ <<"apv">> := APV }, H) -> from_map_ecdh_1pu(maps:remove(<<"apv">>, F), H#jose_jwe_alg_ecdh_1pu{ apv = jose_jwa_base64url:decode(APV) }); from_map_ecdh_1pu(F=#{ <<"iv">> := IV }, H) -> from_map_ecdh_1pu(maps:remove(<<"iv">>, F), H#jose_jwe_alg_ecdh_1pu{ iv = jose_jwa_base64url:decode(IV) }); from_map_ecdh_1pu(F=#{ <<"tag">> := TAG }, H) -> from_map_ecdh_1pu(maps:remove(<<"tag">>, F), H#jose_jwe_alg_ecdh_1pu{ tag = jose_jwa_base64url:decode(TAG) }); from_map_ecdh_1pu(F, H) -> {H, F}. %% @private to_map_ecdh_1pu(F, H=#jose_jwe_alg_ecdh_1pu{ epk = EPK = #jose_jwk{} }) -> to_map_ecdh_1pu(F#{ <<"epk">> => element(2, jose_jwk:to_public_map(EPK)) }, H#jose_jwe_alg_ecdh_1pu{ epk = undefined }); to_map_ecdh_1pu(F, H=#jose_jwe_alg_ecdh_1pu{ apu = APU }) when is_binary(APU) -> to_map_ecdh_1pu(F#{ <<"apu">> => jose_jwa_base64url:encode(APU) }, H#jose_jwe_alg_ecdh_1pu{ apu = undefined }); to_map_ecdh_1pu(F, H=#jose_jwe_alg_ecdh_1pu{ apv = APV }) when is_binary(APV) -> to_map_ecdh_1pu(F#{ <<"apv">> => jose_jwa_base64url:encode(APV) }, H#jose_jwe_alg_ecdh_1pu{ apv = undefined }); to_map_ecdh_1pu(F, H=#jose_jwe_alg_ecdh_1pu{ iv = IV }) when is_binary(IV) -> to_map_ecdh_1pu(F#{ <<"iv">> => jose_jwa_base64url:encode(IV) }, H#jose_jwe_alg_ecdh_1pu{ iv = undefined }); to_map_ecdh_1pu(F, H=#jose_jwe_alg_ecdh_1pu{ tag = TAG }) when is_binary(TAG) -> to_map_ecdh_1pu(F#{ <<"tag">> => jose_jwa_base64url:encode(TAG) }, H#jose_jwe_alg_ecdh_1pu{ tag = undefined }); to_map_ecdh_1pu(F, _) -> F. erlang-jose-1.10.1/src/jwe/jose_jwe_enc_xc20p.erl0000644000232200023220000000441613605433351022104 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_enc_xc20p). -behaviour(jose_jwe). -behaviour(jose_jwe_enc). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_enc callbacks -export([algorithm/1]). -export([bits/1]). -export([block_decrypt/4]). -export([block_encrypt/4]). -export([next_cek/1]). -export([next_iv/1]). %% API -export([cipher_supported/0]). %% Types -type enc() :: {xchacha20_poly1305, 256}. -export_type([enc/0]). %% Macros -define(XCHACHA20_POLY1305, {xchacha20_poly1305, 256}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"enc">> := <<"XC20P">> }) -> {?XCHACHA20_POLY1305, maps:remove(<<"enc">>, F)}. to_map(?XCHACHA20_POLY1305, F) -> F#{ <<"enc">> => <<"XC20P">> }. %%==================================================================== %% jose_jwe_enc callbacks %%==================================================================== algorithm(?XCHACHA20_POLY1305) -> <<"XC20P">>. bits(?XCHACHA20_POLY1305) -> 256. block_decrypt({AAD, CipherText, CipherTag}, CEK, IV, ?XCHACHA20_POLY1305) -> jose_jwa:block_decrypt(?XCHACHA20_POLY1305, CEK, IV, {AAD, CipherText, CipherTag}). block_encrypt({AAD, PlainText}, CEK, IV, ?XCHACHA20_POLY1305) -> jose_jwa:block_encrypt(?XCHACHA20_POLY1305, CEK, IV, {AAD, PlainText}). next_cek(?XCHACHA20_POLY1305) -> crypto:strong_rand_bytes(32). next_iv(?XCHACHA20_POLY1305) -> crypto:strong_rand_bytes(24). %%==================================================================== %% API functions %%==================================================================== cipher_supported() -> [xchacha20_poly1305]. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwe/jose_jwe_alg_c20p_kw.erl0000644000232200023220000001004513605433351022406 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_alg_c20p_kw). -behaviour(jose_jwe). -behaviour(jose_jwe_alg). -include("jose_jwk.hrl"). %% jose_jwe callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jwe_alg callbacks -export([generate_key/3]). -export([key_decrypt/3]). -export([key_encrypt/3]). -export([next_cek/3]). %% API %% Types -record(jose_jwe_alg_c20p_kw, { iv = undefined :: undefined | binary(), tag = undefined :: undefined | binary() }). -type alg() :: #jose_jwe_alg_c20p_kw{}. -export_type([alg/0]). %% Macros -define(BITS, 256). -define(C20PKW, #jose_jwe_alg_c20p_kw{}). %%==================================================================== %% jose_jwe callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"C20PKW">> }) -> from_map_c20p(?C20PKW, maps:remove(<<"alg">>, F)). to_map(A = ?C20PKW, F) -> to_map_c20p(A, F#{ <<"alg">> => <<"C20PKW">> }). %%==================================================================== %% jose_jwe_alg callbacks %%==================================================================== generate_key(_Fields, {ENCModule, ENC}, ALG=#jose_jwe_alg_c20p_kw{}) -> jose_jwe_alg:generate_key({oct, (?BITS div 8)}, maps:get(<<"alg">>, to_map(ALG, #{})), ENCModule:algorithm(ENC)). key_decrypt(DerivedKey, {_ENCModule, _ENC, EncryptedKey}, #jose_jwe_alg_c20p_kw{iv=IV, tag=TAG}) when is_binary(DerivedKey) andalso bit_size(DerivedKey) =:= ?BITS andalso is_binary(IV) andalso is_binary(TAG) -> jose_jwa:block_decrypt({chacha20_poly1305, ?BITS}, DerivedKey, IV, {<<>>, EncryptedKey, TAG}); key_decrypt(#jose_jwk{kty={KTYModule, KTY}}, EncryptedKey, JWEC20PKW=#jose_jwe_alg_c20p_kw{}) -> key_decrypt(KTYModule:derive_key(KTY), EncryptedKey, JWEC20PKW). key_encrypt(DerivedKey, DecryptedKey, JWEC20PKW=#jose_jwe_alg_c20p_kw{iv=IV}) when is_binary(DerivedKey) andalso bit_size(DerivedKey) =:= ?BITS andalso is_binary(IV) -> {CipherText, CipherTag} = jose_jwa:block_encrypt({chacha20_poly1305, ?BITS}, DerivedKey, IV, {<<>>, DecryptedKey}), {CipherText, JWEC20PKW#jose_jwe_alg_c20p_kw{ tag = CipherTag }}; key_encrypt(DerivedKey, DecryptedKey, JWEC20PKW=#jose_jwe_alg_c20p_kw{iv=undefined}) -> key_encrypt(DerivedKey, DecryptedKey, JWEC20PKW#jose_jwe_alg_c20p_kw{ iv = crypto:strong_rand_bytes(12) }); key_encrypt(#jose_jwk{kty={KTYModule, KTY}}, DecryptedKey, JWEC20PKW=#jose_jwe_alg_c20p_kw{}) -> key_encrypt(KTYModule:derive_key(KTY), DecryptedKey, JWEC20PKW). next_cek(_Key, {ENCModule, ENC}, ALG=#jose_jwe_alg_c20p_kw{}) -> {ENCModule:next_cek(ENC), ALG}. %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private from_map_c20p(A, F=#{ <<"iv">> := IV }) -> from_map_c20p(A#jose_jwe_alg_c20p_kw{ iv = jose_jwa_base64url:decode(IV) }, maps:remove(<<"iv">>, F)); from_map_c20p(A, F=#{ <<"tag">> := TAG }) -> from_map_c20p(A#jose_jwe_alg_c20p_kw{ tag = jose_jwa_base64url:decode(TAG) }, maps:remove(<<"tag">>, F)); from_map_c20p(A, F) -> {A, F}. %% @private to_map_c20p(#jose_jwe_alg_c20p_kw{ iv = undefined, tag = undefined }, F) -> F; to_map_c20p(A=#jose_jwe_alg_c20p_kw{ iv = IV }, F) when is_binary(IV) -> to_map_c20p(A#jose_jwe_alg_c20p_kw{ iv = undefined }, F#{ <<"iv">> => jose_jwa_base64url:encode(IV) }); to_map_c20p(A=#jose_jwe_alg_c20p_kw{ tag = TAG }, F) when is_binary(TAG) -> to_map_c20p(A#jose_jwe_alg_c20p_kw{ tag = undefined }, F#{ <<"tag">> => jose_jwa_base64url:encode(TAG) }). erlang-jose-1.10.1/src/jwe/jose_jwe_enc.erl0000644000232200023220000000255013605433351021065 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 29 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwe_enc). -callback algorithm(ENC) -> Algorithm when ENC :: any(), Algorithm :: iodata(). -callback bits(ENC) -> Bits when ENC :: any(), Bits :: non_neg_integer(). -optional_callbacks([algorithm/1]). -optional_callbacks([bits/1]). -callback block_decrypt({AAD, CipherText, CipherTag}, CEK, IV, ENC) -> PlainText | error when AAD :: iodata(), CipherText :: iodata(), CipherTag :: iodata(), CEK :: iodata(), IV :: iodata(), ENC :: any(), PlainText :: iodata(). -callback block_encrypt({AAD, PlainText}, CEK, IV, ENC) -> {CipherText, CipherTag} when AAD :: iodata(), PlainText :: iodata(), CEK :: iodata(), IV :: iodata(), ENC :: any(), CipherText :: iodata(), CipherTag :: iodata(). -callback next_cek(ENC) -> CEK when ENC :: any(), CEK :: iodata(). -callback next_iv(ENC) -> IV when ENC :: any(), IV :: iodata(). erlang-jose-1.10.1/src/jose_curve448_libdecaf.erl0000644000232200023220000000475513605433351022074 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 01 Mar 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_curve448_libdecaf). -behaviour(jose_curve448). %% jose_curve448 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed448_sign/2]). -export([ed448_sign/3]). -export([ed448_verify/3]). -export([ed448_verify/4]). -export([ed448ph_sign/2]). -export([ed448ph_sign/3]). -export([ed448ph_verify/3]). -export([ed448ph_verify/4]). -export([x448_keypair/0]). -export([x448_keypair/1]). -export([x448_secret_to_public/1]). -export([x448_shared_secret/2]). %%==================================================================== %% jose_curve448 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> libdecaf_curve448:eddsa_keypair(). eddsa_keypair(Seed) -> libdecaf_curve448:eddsa_keypair(Seed). eddsa_secret_to_public(SecretKey) -> libdecaf_curve448:eddsa_secret_to_pk(SecretKey). % Ed448 ed448_sign(Message, SecretKey) -> libdecaf_curve448:ed448_sign(Message, SecretKey). ed448_sign(Message, SecretKey, Context) -> libdecaf_curve448:ed448_sign(Message, SecretKey, Context). ed448_verify(Signature, Message, PublicKey) -> libdecaf_curve448:ed448_verify(Signature, Message, PublicKey). ed448_verify(Signature, Message, PublicKey, Context) -> libdecaf_curve448:ed448_verify(Signature, Message, PublicKey, Context). % Ed448ph ed448ph_sign(Message, SecretKey) -> libdecaf_curve448:ed448ph_sign(Message, SecretKey). ed448ph_sign(Message, SecretKey, Context) -> libdecaf_curve448:ed448ph_sign(Message, SecretKey, Context). ed448ph_verify(Signature, Message, PublicKey) -> libdecaf_curve448:ed448ph_verify(Signature, Message, PublicKey). ed448ph_verify(Signature, Message, PublicKey, Context) -> libdecaf_curve448:ed448ph_verify(Signature, Message, PublicKey, Context). % X448 x448_keypair() -> libdecaf_curve448:x448_keypair(). x448_keypair(Seed) -> libdecaf_curve448:x448_keypair(Seed). x448_secret_to_public(SecretKey) -> libdecaf_curve448:x448(SecretKey). x448_shared_secret(MySecretKey, YourPublicKey) -> libdecaf_curve448:x448(MySecretKey, YourPublicKey). erlang-jose-1.10.1/src/jwk/0000755000232200023220000000000013605433351015733 5ustar debalancedebalanceerlang-jose-1.10.1/src/jwk/jose_jwk_kty_okp_ed448ph.erl0000644000232200023220000001341213605433351023253 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 15 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_okp_ed448ph). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_use_sig). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_sig callbacks -export([sign/3]). -export([signer/2]). -export([verifier/2]). -export([verify/4]). %% API -export([from_okp/1]). -export([from_openssh_key/1]). -export([to_okp/1]). -export([to_openssh_key/2]). %% Macros -define(crv, <<"Ed448ph">>). -define(secretbytes, 57). -define(publickeybytes, 57). -define(secretkeybytes, 114). %% Types -type publickey() :: << _:456 >>. -type secretkey() :: << _:912 >>. -type key() :: publickey() | secretkey(). -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"d">> := D, <<"x">> := X }) -> << Secret:?secretbytes/binary >> = jose_jwa_base64url:decode(D), << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), SK = << Secret/binary, PK/binary >>, {SK, maps:without([<<"crv">>, <<"d">>, <<"kty">>, <<"x">>], F)}; from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"x">> := X }) -> << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), {PK, maps:without([<<"crv">>, <<"kty">>, <<"x">>], F)}. to_key(PK = << _:?publickeybytes/binary >>) -> PK; to_key(SK = << _:?secretkeybytes/binary >>) -> SK. to_map(PK = << _:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }; to_map(<< Secret:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"d">> => jose_jwa_base64url:encode(Secret), <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }. to_public_map(PK = << _:?publickeybytes/binary >>, F) -> to_map(PK, F); to_public_map(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> to_public_map(PK, F). to_thumbprint_map(K, F) -> maps:with([<<"crv">>, <<"kty">>, <<"x">>], to_public_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(Seed = << _:?secretbytes/binary >>) -> {_PK, SK} = jose_curve448:eddsa_keypair(Seed), {SK, #{}}; generate_key({okp, 'Ed448ph', Seed = << _:?secretbytes/binary >>}) -> generate_key(Seed); generate_key({okp, 'Ed448ph'}) -> {_PK, SK} = jose_curve448:eddsa_keypair(), {SK, #{}}. generate_key(KTY, Fields) when is_binary(KTY) andalso (byte_size(KTY) =:= ?publickeybytes orelse byte_size(KTY) =:= ?secretkeybytes) -> {NewKTY, OtherFields} = generate_key({okp, 'Ed448ph'}), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_sig callbacks %%==================================================================== sign(Message, ALG, SK = << _:?secretkeybytes/binary >>) when ALG =:= 'Ed448ph' orelse ALG =:= 'EdDSA' -> jose_curve448:ed448ph_sign(Message, SK). signer(<< _:?secretkeybytes/binary >>, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> #{ <<"alg">> => ALG }; signer(<< _:?secretkeybytes/binary >>, _Fields) -> #{ <<"alg">> => <<"EdDSA">> }. verifier(<< _:?publickeybytes/binary >>, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> [ALG]; verifier(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, Fields) -> verifier(PK, Fields); verifier(<< _:?publickeybytes/binary >>, _Fields) -> [?crv, <<"EdDSA">>]. verify(Message, ALG, Signature, << _:?secretbytes/binary, PK:?publickeybytes/binary >>) when ALG =:= 'Ed448ph' orelse ALG =:= 'EdDSA' -> verify(Message, ALG, Signature, PK); verify(Message, ALG, Signature, PK = << _:?publickeybytes/binary >>) when ALG =:= 'Ed448ph' orelse ALG =:= 'EdDSA' -> jose_curve448:ed448ph_verify(Signature, Message, PK). %%==================================================================== %% API functions %%==================================================================== from_okp({'Ed448ph', SK = << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>}) -> case jose_curve448:eddsa_secret_to_public(Secret) of PK -> {SK, #{}}; _ -> erlang:error(badarg) end; from_okp({'Ed448ph', PK = << _:?publickeybytes/binary >>}) -> {PK, #{}}. from_openssh_key({<<"ssh-ed448ph">>, _PK, SK, Comment}) -> {KTY, OtherFields} = from_okp({'Ed448ph', SK}), case Comment of <<>> -> {KTY, OtherFields}; _ -> {KTY, maps:merge(#{ <<"kid">> => Comment }, OtherFields)} end. to_okp(SK = << _:?secretkeybytes/binary >>) -> {'Ed448ph', SK}; to_okp(PK = << _:?publickeybytes/binary >>) -> {'Ed448ph', PK}. to_openssh_key(SK = << _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> Comment = maps:get(<<"kid">>, F, <<>>), jose_jwk_openssh_key:to_binary([[{{<<"ssh-ed448ph">>, PK}, {<<"ssh-ed448ph">>, PK, SK, Comment}}]]). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_kty.erl0000644000232200023220000001637113605433351021151 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 24 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty). -include_lib("jose_public_key.hrl"). -callback generate_key(Parameters) -> KTY when Parameters :: any(), KTY :: any(). -callback generate_key(KTY, Fields) -> NewKTY when KTY :: any(), Fields :: map(), NewKTY :: any(). -callback key_encryptor(KTY, Fields, Key) -> JWEMap when KTY :: any(), Fields :: map(), Key :: any(), JWEMap :: map(). %% API -export([from_key/1]). -export([from_oct/1]). -export([generate_key/1]). -export([key_encryptor/3]). -define(KTY_EC_MODULE, jose_jwk_kty_ec). -define(KTY_OCT_MODULE, jose_jwk_kty_oct). -define(KTY_RSA_MODULE, jose_jwk_kty_rsa). -define(KTY_OKP_Ed25519_MODULE, jose_jwk_kty_okp_ed25519). -define(KTY_OKP_Ed25519ph_MODULE, jose_jwk_kty_okp_ed25519ph). -define(KTY_OKP_X25519_MODULE, jose_jwk_kty_okp_x25519). -define(KTY_OKP_Ed448_MODULE, jose_jwk_kty_okp_ed448). -define(KTY_OKP_Ed448ph_MODULE, jose_jwk_kty_okp_ed448ph). -define(KTY_OKP_X448_MODULE, jose_jwk_kty_okp_x448). %%==================================================================== %% API functions %%==================================================================== from_key(ECPrivateKey=#'ECPrivateKey'{}) -> {?KTY_EC_MODULE, ?KTY_EC_MODULE:from_key(ECPrivateKey)}; from_key(ECPublicKey={#'ECPoint'{}, _}) -> {?KTY_EC_MODULE, ?KTY_EC_MODULE:from_key(ECPublicKey)}; from_key(EdDSA25519PrivateKey=#'jose_EdDSA25519PrivateKey'{}) -> {?KTY_OKP_Ed25519_MODULE, ?KTY_OKP_Ed25519_MODULE:from_key(EdDSA25519PrivateKey)}; from_key(EdDSA25519PublicKey=#'jose_EdDSA25519PublicKey'{}) -> {?KTY_OKP_Ed25519_MODULE, ?KTY_OKP_Ed25519_MODULE:from_key(EdDSA25519PublicKey)}; from_key(EdDSA448PrivateKey=#'jose_EdDSA448PrivateKey'{}) -> {?KTY_OKP_Ed448_MODULE, ?KTY_OKP_Ed448_MODULE:from_key(EdDSA448PrivateKey)}; from_key(EdDSA448PublicKey=#'jose_EdDSA448PublicKey'{}) -> {?KTY_OKP_Ed448_MODULE, ?KTY_OKP_Ed448_MODULE:from_key(EdDSA448PublicKey)}; from_key(X25519PrivateKey=#'jose_X25519PrivateKey'{}) -> {?KTY_OKP_X25519_MODULE, ?KTY_OKP_X25519_MODULE:from_key(X25519PrivateKey)}; from_key(X25519PublicKey=#'jose_X25519PublicKey'{}) -> {?KTY_OKP_X25519_MODULE, ?KTY_OKP_X25519_MODULE:from_key(X25519PublicKey)}; from_key(X448PrivateKey=#'jose_X448PrivateKey'{}) -> {?KTY_OKP_X448_MODULE, ?KTY_OKP_X448_MODULE:from_key(X448PrivateKey)}; from_key(X448PublicKey=#'jose_X448PublicKey'{}) -> {?KTY_OKP_X448_MODULE, ?KTY_OKP_X448_MODULE:from_key(X448PublicKey)}; from_key(RSAPrivateKey=#'RSAPrivateKey'{}) -> {?KTY_RSA_MODULE, ?KTY_RSA_MODULE:from_key(RSAPrivateKey)}; from_key(RSAPublicKey=#'RSAPublicKey'{}) -> {?KTY_RSA_MODULE, ?KTY_RSA_MODULE:from_key(RSAPublicKey)}; from_key(#'PrivateKeyInfo'{privateKeyAlgorithm=#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm=?rsaEncryption}, privateKey=PrivateKey}) -> from_key(public_key:der_decode('RSAPrivateKey', PrivateKey)); from_key(#'PrivateKeyInfo'{privateKeyAlgorithm=#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm=?'id-ecPublicKey'}, privateKey=PrivateKey}) -> from_key(public_key:der_decode('ECPrivateKey', PrivateKey)); from_key(UnknownKey) -> {error, {unknown_key, UnknownKey}}. from_oct(OCTBinary) when is_binary(OCTBinary) -> {?KTY_OCT_MODULE, ?KTY_OCT_MODULE:from_oct(OCTBinary)}; from_oct(UnknownKey) -> {error, {unknown_key, UnknownKey}}. generate_key(P=#'ECParameters'{}) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P=#'ECPrivateKey'{}) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P={#'ECPoint'{}, _}) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P={namedCurve, _}) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P) when is_atom(P) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P=#'RSAPrivateKey'{}) -> jose_jwk:generate_key({#{ kty => ?KTY_RSA_MODULE }, P}); generate_key(P=#'RSAPublicKey'{}) -> jose_jwk:generate_key({#{ kty => ?KTY_RSA_MODULE }, P}); generate_key(P) when is_integer(P) -> jose_jwk:generate_key({#{ kty => ?KTY_OCT_MODULE }, P}); generate_key(P={ec, #'ECParameters'{}}) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P={ec, #'ECPrivateKey'{}}) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P={ec, {#'ECPoint'{}, _}}) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P={ec, {namedCurve, _}}) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P={ec, Atom}) when is_atom(Atom) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P={ec, Binary}) when is_binary(Binary) -> jose_jwk:generate_key({#{ kty => ?KTY_EC_MODULE }, P}); generate_key(P={oct, Size}) when is_integer(Size) -> jose_jwk:generate_key({#{ kty => ?KTY_OCT_MODULE }, P}); generate_key(P={okp, 'Ed25519'}) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_Ed25519_MODULE }, P}); generate_key(P={okp, 'Ed25519ph'}) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_Ed25519ph_MODULE }, P}); generate_key(P={okp, 'X25519'}) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_X25519_MODULE }, P}); generate_key(P={okp, 'Ed25519', Seed}) when is_binary(Seed) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_Ed25519_MODULE }, P}); generate_key(P={okp, 'Ed25519ph', Seed}) when is_binary(Seed) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_Ed25519ph_MODULE }, P}); generate_key(P={okp, 'X25519', Seed}) when is_binary(Seed) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_X25519_MODULE }, P}); generate_key(P={okp, 'Ed448'}) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_Ed448_MODULE }, P}); generate_key(P={okp, 'Ed448ph'}) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_Ed448ph_MODULE }, P}); generate_key(P={okp, 'X448'}) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_X448_MODULE }, P}); generate_key(P={okp, 'Ed448', Seed}) when is_binary(Seed) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_Ed448_MODULE }, P}); generate_key(P={okp, 'Ed448ph', Seed}) when is_binary(Seed) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_Ed448ph_MODULE }, P}); generate_key(P={okp, 'X448', Seed}) when is_binary(Seed) -> jose_jwk:generate_key({#{ kty => ?KTY_OKP_X448_MODULE }, P}); generate_key(P={rsa, ModulusSize}) when is_integer(ModulusSize) -> jose_jwk:generate_key({#{ kty => ?KTY_RSA_MODULE }, P}); generate_key(P={rsa, ModulusSize, ExponentSize}) when is_integer(ModulusSize) andalso is_integer(ExponentSize) -> jose_jwk:generate_key({#{ kty => ?KTY_RSA_MODULE }, P}). key_encryptor(_KTY, _Fields, Key) when is_binary(Key) -> #{ <<"alg">> => <<"PBES2-HS256+A128KW">>, <<"cty">> => <<"jwk+json">>, <<"enc">> => case jose_jwa:is_block_cipher_supported({aes_gcm, 128}) of false -> <<"A128CBC-HS256">>; true -> <<"A128GCM">> end, <<"p2c">> => 4096, <<"p2s">> => jose_jwa_base64url:encode(crypto:strong_rand_bytes(16)) }. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_kty_okp_x25519.erl0000644000232200023220000002120113605433351022743 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 15 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_okp_x25519). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_use_enc). -include_lib("jose_public_key.hrl"). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_enc callbacks -export([block_encryptor/2]). -export([derive_key/2]). %% API -export([from_der/1]). -export([from_der/2]). -export([from_key/1]). -export([from_okp/1]). -export([from_openssh_key/1]). -export([from_pem/1]). -export([from_pem/2]). -export([to_der/1]). -export([to_der/2]). -export([to_okp/1]). -export([to_openssh_key/2]). -export([to_pem/1]). -export([to_pem/2]). %% Macros -define(crv, <<"X25519">>). -define(secretbytes, 32). -define(publickeybytes, 32). -define(secretkeybytes, 64). %% Types -type publickey() :: << _:256 >>. -type secretkey() :: << _:512 >>. -type key() :: publickey() | secretkey(). -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"d">> := D, <<"x">> := X }) -> << Secret:?secretbytes/binary >> = jose_jwa_base64url:decode(D), << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), SK = << Secret/binary, PK/binary >>, {SK, maps:without([<<"crv">>, <<"d">>, <<"kty">>, <<"x">>], F)}; from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"x">> := X }) -> << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), {PK, maps:without([<<"crv">>, <<"kty">>, <<"x">>], F)}. to_key(<< PublicKey:?publickeybytes/binary >>) -> #'jose_X25519PublicKey'{ publicKey = PublicKey }; to_key(<< PrivateKey:?secretbytes/binary, PublicKey:?publickeybytes/binary >>) -> #'jose_X25519PrivateKey'{ publicKey = #'jose_X25519PublicKey'{ publicKey = PublicKey }, privateKey = PrivateKey }. to_map(PK = << _:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }; to_map(<< Secret:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"d">> => jose_jwa_base64url:encode(Secret), <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }. to_public_map(PK = << _:?publickeybytes/binary >>, F) -> to_map(PK, F); to_public_map(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> to_public_map(PK, F). to_thumbprint_map(K, F) -> maps:with([<<"crv">>, <<"kty">>, <<"x">>], to_public_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(Seed = << _:?secretbytes/binary >>) -> {PK, SK} = jose_curve25519:x25519_keypair(Seed), {<< SK/binary, PK/binary >>, #{}}; generate_key({okp, 'X25519', Seed = << _:?secretbytes/binary >>}) -> generate_key(Seed); generate_key({okp, 'X25519'}) -> {PK, SK} = jose_curve25519:x25519_keypair(), {<< SK/binary, PK/binary >>, #{}}. generate_key(KTY, Fields) when is_binary(KTY) andalso (byte_size(KTY) =:= ?publickeybytes orelse byte_size(KTY) =:= ?secretkeybytes) -> {NewKTY, OtherFields} = generate_key({okp, 'X25519'}), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_enc callbacks %%==================================================================== block_encryptor(_KTY, Fields=#{ <<"alg">> := ALG, <<"enc">> := ENC, <<"use">> := <<"enc">> }) -> Folder = fun (K, V, F) when K =:= <<"apu">> orelse K =:= <<"apv">> orelse K =:= <<"epk">> orelse K =:= <<"skid">> -> maps:put(K, V, F); (_K, _V, F) -> F end, maps:fold(Folder, #{ <<"alg">> => ALG, <<"enc">> => ENC }, Fields); block_encryptor(KTY, Fields=#{ <<"alg">> := <<"ECDH-1PU", _/binary>> }) -> block_encryptor(KTY, maps:merge(Fields, #{ <<"enc">> => case jose_jwa:is_block_cipher_supported({aes_gcm, 128}) of false -> <<"A128CBC-HS256">>; true -> <<"A128GCM">> end, <<"use">> => <<"enc">> })); block_encryptor(KTY, Fields) -> block_encryptor(KTY, maps:merge(Fields, #{ <<"alg">> => <<"ECDH-ES">>, <<"enc">> => case jose_jwa:is_block_cipher_supported({aes_gcm, 128}) of false -> <<"A128CBC-HS256">>; true -> <<"A128GCM">> end, <<"use">> => <<"enc">> })). derive_key(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, SK = << _:?secretkeybytes/binary >>) -> derive_key(PK, SK); derive_key(PK = << _:?publickeybytes/binary >>, << Secret:?secretbytes/binary, _:?publickeybytes/binary >>) -> jose_curve25519:x25519_shared_secret(Secret, PK). %%==================================================================== %% API functions %%==================================================================== from_der(DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_der(Password, DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(Password, DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_key(#'jose_X25519PrivateKey'{publicKey=#'jose_X25519PublicKey'{publicKey=Public}, privateKey=Secret}) -> {<< Secret/binary, Public/binary >>, #{}}; from_key(#'jose_X25519PublicKey'{publicKey=Public}) -> {Public, #{}}. from_okp({'X25519', SK = << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>}) -> case jose_curve25519:x25519_secret_to_public(Secret) of PK -> {SK, #{}}; _ -> erlang:error(badarg) end; from_okp({'X25519', PK = << _:?publickeybytes/binary >>}) -> {PK, #{}}. from_openssh_key({<<"ssh-x25519">>, _PK, SK, Comment}) -> {KTY, OtherFields} = from_okp({'X25519', SK}), case Comment of <<>> -> {KTY, OtherFields}; _ -> {KTY, maps:merge(#{ <<"kid">> => Comment }, OtherFields)} end. from_pem(PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. from_pem(Password, PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(Password, PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. to_der(SK = << _:?secretkeybytes/binary >>) -> X25519PrivateKey = to_key(SK), jose_public_key:der_encode('X25519PrivateKey', X25519PrivateKey); to_der(PK = << _:?publickeybytes/binary >>) -> X25519PublicKey = to_key(PK), jose_public_key:der_encode('X25519PublicKey', X25519PublicKey). to_der(Password, SK = << _:?secretkeybytes/binary >>) -> X25519PrivateKey = to_key(SK), jose_jwk_der:to_binary(Password, 'X25519PrivateKey', X25519PrivateKey); to_der(Password, PK = << _:?publickeybytes/binary >>) -> X25519PublicKey = to_key(PK), jose_jwk_der:to_binary(Password, 'X25519PublicKey', X25519PublicKey). to_okp(SK = << _:?secretkeybytes/binary >>) -> {'X25519', SK}; to_okp(PK = << _:?publickeybytes/binary >>) -> {'X25519', PK}. to_openssh_key(SK = << _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> Comment = maps:get(<<"kid">>, F, <<>>), jose_jwk_openssh_key:to_binary([[{{<<"ssh-x25519">>, PK}, {<<"ssh-x25519">>, PK, SK, Comment}}]]). to_pem(SK = << _:?secretkeybytes/binary >>) -> X25519PrivateKey = to_key(SK), PEMEntry = jose_public_key:pem_entry_encode('X25519PrivateKey', X25519PrivateKey), jose_public_key:pem_encode([PEMEntry]); to_pem(PK = << _:?publickeybytes/binary >>) -> X25519PublicKey = to_key(PK), PEMEntry = jose_public_key:pem_entry_encode('X25519PublicKey', X25519PublicKey), jose_public_key:pem_encode([PEMEntry]). to_pem(Password, SK = << _:?secretkeybytes/binary >>) -> X25519PrivateKey = to_key(SK), jose_jwk_pem:to_binary(Password, 'PrivateKeyInfo', X25519PrivateKey); to_pem(Password, PK = << _:?publickeybytes/binary >>) -> X25519PublicKey = to_key(PK), jose_jwk_pem:to_binary(Password, 'X25519PublicKey', X25519PublicKey). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_set.erl0000644000232200023220000000161113605433351021124 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 21 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_set). -include("jose_jwk.hrl"). %% API -export([from_map/1]). -export([to_map/2]). %%==================================================================== %% API functions %%==================================================================== from_map(F=#{ <<"keys">> := Keys }) -> {[jose_jwk:from_map(Key) || Key <- Keys], maps:remove(<<"keys">>, F)}. to_map(Keys, F) -> F#{ <<"keys">> => [element(2, jose_jwk:to_map(Key)) || Key <- Keys] }. erlang-jose-1.10.1/src/jwk/jose_jwk_kty_rsa.erl0000644000232200023220000004404313605433351022013 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_rsa). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_use_enc). -behaviour(jose_jwk_use_sig). -include_lib("public_key/include/public_key.hrl"). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_enc callbacks -export([block_encryptor/2]). -export([decrypt_private/3]). -export([encrypt_public/3]). %% jose_jwk_use_sig callbacks -export([sign/3]). -export([signer/2]). -export([verifier/2]). -export([verify/4]). %% API -export([from_der/1]). -export([from_der/2]). -export([from_key/1]). -export([from_pem/1]). -export([from_pem/2]). -export([to_der/1]). -export([to_der/2]). -export([to_pem/1]). -export([to_pem/2]). %% Types -type key() :: #'RSAPrivateKey'{} | #'RSAPublicKey'{}. -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"RSA">>, <<"d">> := _ }) -> from_map_rsa_private_key(maps:remove(<<"kty">>, F), #'RSAPrivateKey'{ version = 'two-prime', otherPrimeInfos = 'asn1_NOVALUE' }); from_map(F = #{ <<"kty">> := <<"RSA">> }) -> from_map_rsa_public_key(maps:remove(<<"kty">>, F), #'RSAPublicKey'{}). to_key(RSAPrivateKey=#'RSAPrivateKey'{}) -> RSAPrivateKey; to_key(RSAPublicKey=#'RSAPublicKey'{}) -> RSAPublicKey. to_map(RSAPrivateKey=#'RSAPrivateKey'{version = 0}, F) -> to_map(RSAPrivateKey#'RSAPrivateKey'{version = 'two-prime'}, F); to_map(RSAPrivateKey=#'RSAPrivateKey'{version = 1}, F) -> to_map(RSAPrivateKey#'RSAPrivateKey'{version = 'multi'}, F); to_map(#'RSAPrivateKey'{ version = 'two-prime', otherPrimeInfos = 'asn1_NOVALUE', privateExponent = D, exponent1 = DP, exponent2 = DQ, publicExponent = E, modulus = N, prime1 = P, prime2 = Q, coefficient = QI}, F) -> F#{ <<"d">> => jose_jwa_base64url:encode(int_to_bin(D)), <<"dp">> => jose_jwa_base64url:encode(int_to_bin(DP)), <<"dq">> => jose_jwa_base64url:encode(int_to_bin(DQ)), <<"e">> => jose_jwa_base64url:encode(int_to_bin(E)), <<"kty">> => <<"RSA">>, <<"n">> => jose_jwa_base64url:encode(int_to_bin(N)), <<"p">> => jose_jwa_base64url:encode(int_to_bin(P)), <<"q">> => jose_jwa_base64url:encode(int_to_bin(Q)), <<"qi">> => jose_jwa_base64url:encode(int_to_bin(QI)) }; to_map(#'RSAPrivateKey'{ version = 'multi', otherPrimeInfos = OTH, privateExponent = D, exponent1 = DP, exponent2 = DQ, publicExponent = E, modulus = N, prime1 = P, prime2 = Q, coefficient = QI}, F) -> F#{ <<"d">> => jose_jwa_base64url:encode(int_to_bin(D)), <<"dp">> => jose_jwa_base64url:encode(int_to_bin(DP)), <<"dq">> => jose_jwa_base64url:encode(int_to_bin(DQ)), <<"e">> => jose_jwa_base64url:encode(int_to_bin(E)), <<"kty">> => <<"RSA">>, <<"n">> => jose_jwa_base64url:encode(int_to_bin(N)), <<"oth">> => [begin #{ <<"d">> => jose_jwa_base64url:encode(int_to_bin(OD)), <<"r">> => jose_jwa_base64url:encode(int_to_bin(OR)), <<"t">> => jose_jwa_base64url:encode(int_to_bin(OT)) } end || #'OtherPrimeInfo'{ prime = OR, exponent = OD, coefficient = OT} <- OTH], <<"p">> => jose_jwa_base64url:encode(int_to_bin(P)), <<"q">> => jose_jwa_base64url:encode(int_to_bin(Q)), <<"qi">> => jose_jwa_base64url:encode(int_to_bin(QI)) }; to_map(#'RSAPublicKey'{ publicExponent = E, modulus = N}, F) -> F#{ <<"e">> => jose_jwa_base64url:encode(int_to_bin(E)), <<"kty">> => <<"RSA">>, <<"n">> => jose_jwa_base64url:encode(int_to_bin(N)) }. to_public_map(K=#'RSAPrivateKey'{}, F) -> maps:without([<<"d">>, <<"dp">>, <<"dq">>, <<"p">>, <<"q">>, <<"qi">>, <<"oth">>], to_map(K, F)); to_public_map(K=#'RSAPublicKey'{}, F) -> to_map(K, F). to_thumbprint_map(K, F) -> maps:with([<<"e">>, <<"kty">>, <<"n">>], to_public_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(#'RSAPrivateKey'{ modulus = N, publicExponent = E }) -> generate_key({rsa, int_to_bit_size(N), E}); generate_key(#'RSAPublicKey'{ modulus = N, publicExponent = E }) -> generate_key({rsa, int_to_bit_size(N), E}); generate_key({rsa, ModulusSize}) when is_integer(ModulusSize) -> generate_key({rsa, ModulusSize, 65537}); generate_key({rsa, ModulusSize, ExponentSize}) when is_integer(ModulusSize) andalso is_integer(ExponentSize) -> try_generate_key([ public_key, cutkey ], ModulusSize, ExponentSize). generate_key(KTY, Fields) -> {NewKTY, OtherFields} = generate_key(KTY), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_enc callbacks %%==================================================================== block_encryptor(_KTY, #{ <<"alg">> := ALG, <<"enc">> := ENC, <<"use">> := <<"enc">> }) -> #{ <<"alg">> => ALG, <<"enc">> => ENC }; block_encryptor(_KTY, _Fields) -> #{ <<"alg">> => case jose_jwa:is_rsa_crypt_supported(rsa_oaep) of false -> <<"RSA1_5">>; true -> <<"RSA-OAEP">> end, <<"enc">> => case jose_jwa:is_block_cipher_supported({aes_gcm, 128}) of false -> <<"A128CBC-HS256">>; true -> <<"A128GCM">> end }. decrypt_private(CipherText, Options, RSAPrivateKey=#'RSAPrivateKey'{}) -> jose_jwa:decrypt_private(CipherText, RSAPrivateKey, Options). encrypt_public(PlainText, Options, RSAPublicKey=#'RSAPublicKey'{}) -> jose_jwa:encrypt_public(PlainText, RSAPublicKey, Options); encrypt_public(PlainText, Options, #'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent}) -> RSAPublicKey = #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}, encrypt_public(PlainText, Options, RSAPublicKey). %%==================================================================== %% jose_jwk_use_sig callbacks %%==================================================================== sign(Message, JWSALG, RSAPrivateKey=#'RSAPrivateKey'{}) -> {Padding, DigestType} = jws_alg_to_digest_type(JWSALG), jose_jwa:sign(Message, DigestType, RSAPrivateKey, Padding). signer(#'RSAPrivateKey'{}, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> #{ <<"alg">> => ALG }; signer(#'RSAPrivateKey'{}, _Fields) -> #{ <<"alg">> => case jose_jwa:is_rsa_sign_supported(rsa_pkcs1_pss_padding) of false -> <<"RS256">>; true -> <<"PS256">> end }. verifier(_KTY, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> [ALG]; verifier(#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent}, Fields) -> RSAPublicKey = #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}, verifier(RSAPublicKey, Fields); verifier(#'RSAPublicKey'{}, _Fields) -> case jose_jwa:is_rsa_sign_supported(rsa_pkcs1_pss_padding) of false -> [<<"RS256">>, <<"RS384">>, <<"RS512">>]; true -> [<<"PS256">>, <<"PS384">>, <<"PS512">>, <<"RS256">>, <<"RS384">>, <<"RS512">>] end. verify(Message, JWSALG, Signature, RSAPublicKey=#'RSAPublicKey'{}) -> try jws_alg_to_digest_type(JWSALG) of {Padding, DigestType} -> jose_jwa:verify(Message, DigestType, Signature, RSAPublicKey, Padding) catch error:{not_supported, _} -> false end; verify(Message, JWSALG, Signature, #'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent}) -> RSAPublicKey = #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}, verify(Message, JWSALG, Signature, RSAPublicKey). %%==================================================================== %% API functions %%==================================================================== from_der(DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_der(Password, PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_der:from_binary(Password, PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. from_key(RSAPrivateKey=#'RSAPrivateKey'{}) -> {RSAPrivateKey, #{}}; from_key(RSAPublicKey=#'RSAPublicKey'{}) -> {RSAPublicKey, #{}}. from_pem(PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. from_pem(Password, PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(Password, PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. to_der(RSAPrivateKey=#'RSAPrivateKey'{}) -> jose_public_key:der_encode('PrivateKeyInfo', RSAPrivateKey); to_der(RSAPublicKey=#'RSAPublicKey'{}) -> jose_public_key:der_encode('RSAPublicKey', RSAPublicKey). to_der(Password, RSAPrivateKey=#'RSAPrivateKey'{}) -> jose_jwk_der:to_binary(Password, 'PrivateKeyInfo', RSAPrivateKey); to_der(Password, RSAPublicKey=#'RSAPublicKey'{}) -> jose_jwk_der:to_binary(Password, 'RSAPublicKey', RSAPublicKey). to_pem(RSAPrivateKey=#'RSAPrivateKey'{}) -> PEMEntry = jose_public_key:pem_entry_encode('PrivateKeyInfo', RSAPrivateKey), jose_public_key:pem_encode([PEMEntry]); to_pem(RSAPublicKey=#'RSAPublicKey'{}) -> PEMEntry = jose_public_key:pem_entry_encode('RSAPublicKey', RSAPublicKey), jose_public_key:pem_encode([PEMEntry]). to_pem(Password, RSAPrivateKey=#'RSAPrivateKey'{}) -> jose_jwk_pem:to_binary(Password, 'PrivateKeyInfo', RSAPrivateKey); to_pem(Password, RSAPublicKey=#'RSAPublicKey'{}) -> jose_jwk_pem:to_binary(Password, 'RSAPublicKey', RSAPublicKey). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private convert_sfm_to_crt(Key=#'RSAPrivateKey'{ version = 'two-prime', otherPrimeInfos = 'asn1_NOVALUE', privateExponent = D, exponent1 = undefined, exponent2 = undefined, publicExponent = E, modulus = N, prime1 = undefined, prime2 = undefined, coefficient = undefined}) when is_integer(D) andalso is_integer(E) andalso is_integer(N) -> KTOT = D * E - 1, T = convert_sfm_to_crt_find_t(KTOT), A = 2, K = T, P0 = convert_sfm_to_crt_find_p(KTOT, T, K, A, N, D), Q0 = N div P0, {P, Q} = case Q0 > P0 of true -> {Q0, P0}; false -> {P0, Q0} end, DP = jose_jwa_math:mod(D, P - 1), DQ = jose_jwa_math:mod(D, Q - 1), QI = convert_sfm_to_crt_mod_inverse(Q, P), Key#'RSAPrivateKey'{ exponent1 = DP, exponent2 = DQ, prime1 = P, prime2 = Q, coefficient = QI }. %% @private convert_sfm_to_crt_egcd(0, B) -> {B, 0, 1}; convert_sfm_to_crt_egcd(A, B) -> {G, Y, X} = convert_sfm_to_crt_egcd(jose_jwa_math:mod(B, A), A), {G, X - (B div A) * Y, Y}. %% @private convert_sfm_to_crt_find_p(KTOT, T, K, A, N, D) when K < KTOT -> R = case jose_jwa_math:expmod(A, K, N) of C when C =/= 1 andalso C =/= (N - 1) -> case jose_jwa_math:expmod(C, 2, N) of 1 -> P0 = convert_sfm_to_crt_gcd(C + 1, N), {true, P0}; _ -> false end; _ -> false end, case R of {true, P} -> P; false -> convert_sfm_to_crt_find_p(KTOT, T, K * 2, A, N, D) end; convert_sfm_to_crt_find_p(KTOT, T, _K, A, N, D) -> convert_sfm_to_crt_find_p(KTOT, T, T, A + 2, N, D). %% @private convert_sfm_to_crt_find_t(T) when T > 0 andalso T rem 2 =:= 0 -> convert_sfm_to_crt_find_t(T div 2); convert_sfm_to_crt_find_t(T) -> T. %% @private convert_sfm_to_crt_gcd(A, 0) -> A; convert_sfm_to_crt_gcd(A, B) -> convert_sfm_to_crt_gcd(B, jose_jwa_math:mod(A, B)). %% @private convert_sfm_to_crt_mod_inverse(A, M) -> case convert_sfm_to_crt_egcd(A, M) of {1, X, _Y} -> jose_jwa_math:mod(X, M); _ -> no_inverse end. %% @private from_map_rsa_private_key(F = #{ <<"d">> := D }, Key) -> from_map_rsa_private_key(maps:remove(<<"d">>, F), Key#'RSAPrivateKey'{ privateExponent = crypto:bytes_to_integer(jose_jwa_base64url:decode(D)) }); from_map_rsa_private_key(F = #{ <<"dp">> := DP }, Key) -> from_map_rsa_private_key(maps:remove(<<"dp">>, F), Key#'RSAPrivateKey'{ exponent1 = crypto:bytes_to_integer(jose_jwa_base64url:decode(DP)) }); from_map_rsa_private_key(F = #{ <<"dq">> := DQ }, Key) -> from_map_rsa_private_key(maps:remove(<<"dq">>, F), Key#'RSAPrivateKey'{ exponent2 = crypto:bytes_to_integer(jose_jwa_base64url:decode(DQ)) }); from_map_rsa_private_key(F = #{ <<"e">> := E }, Key) -> from_map_rsa_private_key(maps:remove(<<"e">>, F), Key#'RSAPrivateKey'{ publicExponent = crypto:bytes_to_integer(jose_jwa_base64url:decode(E)) }); from_map_rsa_private_key(F = #{ <<"n">> := N }, Key) -> from_map_rsa_private_key(maps:remove(<<"n">>, F), Key#'RSAPrivateKey'{ modulus = crypto:bytes_to_integer(jose_jwa_base64url:decode(N)) }); from_map_rsa_private_key(F = #{ <<"p">> := P }, Key) -> from_map_rsa_private_key(maps:remove(<<"p">>, F), Key#'RSAPrivateKey'{ prime1 = crypto:bytes_to_integer(jose_jwa_base64url:decode(P)) }); from_map_rsa_private_key(F = #{ <<"q">> := Q }, Key) -> from_map_rsa_private_key(maps:remove(<<"q">>, F), Key#'RSAPrivateKey'{ prime2 = crypto:bytes_to_integer(jose_jwa_base64url:decode(Q)) }); from_map_rsa_private_key(F = #{ <<"qi">> := QI }, Key) -> from_map_rsa_private_key(maps:remove(<<"qi">>, F), Key#'RSAPrivateKey'{ coefficient = crypto:bytes_to_integer(jose_jwa_base64url:decode(QI)) }); from_map_rsa_private_key(F = #{ <<"oth">> := OTH }, Key) -> OtherPrimeInfos = [begin #'OtherPrimeInfo'{ prime = crypto:bytes_to_integer(jose_jwa_base64url:decode(OR)), exponent = crypto:bytes_to_integer(jose_jwa_base64url:decode(OD)), coefficient = crypto:bytes_to_integer(jose_jwa_base64url:decode(OT))} end || #{ <<"d">> := OD, <<"r">> := OR, <<"t">> := OT } <- OTH], from_map_rsa_private_key(maps:remove(<<"oth">>, F), Key#'RSAPrivateKey'{ version = 'multi', otherPrimeInfos = OtherPrimeInfos }); from_map_rsa_private_key(F, Key0=#'RSAPrivateKey'{ version = 'two-prime', otherPrimeInfos = 'asn1_NOVALUE', privateExponent = D, exponent1 = undefined, exponent2 = undefined, publicExponent = E, modulus = N, prime1 = undefined, prime2 = undefined, coefficient = undefined}) when is_integer(D) andalso is_integer(E) andalso is_integer(N) -> Ref = erlang:make_ref(), Parent = self(), {Child, Monitor} = spawn_monitor(fun() -> Parent ! {Ref, convert_sfm_to_crt(Key0)}, exit(normal) end), receive {Ref, Key} -> _ = erlang:demonitor(Monitor, [flush]), from_map_rsa_private_key(F, Key); {'DOWN', Monitor, process, Child, _Reason} -> erlang:error({badarg, [Key0]}) after 1000 -> true = erlang:exit(Child, kill), receive {Ref, Key} -> _ = erlang:demonitor(Monitor, [flush]), from_map_rsa_private_key(F, Key); {'DOWN', Monitor, process, Child, _Reason} -> erlang:error({badarg, [Key0]}) end end; from_map_rsa_private_key(F, Key) -> {Key, F}. %% @private from_map_rsa_public_key(F = #{ <<"e">> := E }, Key) -> from_map_rsa_public_key(maps:remove(<<"e">>, F), Key#'RSAPublicKey'{ publicExponent = crypto:bytes_to_integer(jose_jwa_base64url:decode(E)) }); from_map_rsa_public_key(F = #{ <<"n">> := N }, Key) -> from_map_rsa_public_key(maps:remove(<<"n">>, F), Key#'RSAPublicKey'{ modulus = crypto:bytes_to_integer(jose_jwa_base64url:decode(N)) }); from_map_rsa_public_key(F, Key) -> {Key, F}. %% @private int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); int_to_bin(X) -> int_to_bin_pos(X, []). %% @private int_to_bin_pos(0,Ds=[_|_]) -> list_to_binary(Ds); int_to_bin_pos(X,Ds) -> int_to_bin_pos(X bsr 8, [(X band 255)|Ds]). %% @private int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 -> list_to_binary(Ds); int_to_bin_neg(X,Ds) -> int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). %% @private int_to_bit_size(I) -> int_to_bit_size(I, 0). %% @private int_to_bit_size(0, B) -> B; int_to_bit_size(I, B) -> int_to_bit_size(I bsr 1, B + 1). %% @private jws_alg_to_digest_type('PS256') -> {rsa_pkcs1_pss_padding, sha256}; jws_alg_to_digest_type('PS384') -> {rsa_pkcs1_pss_padding, sha384}; jws_alg_to_digest_type('PS512') -> {rsa_pkcs1_pss_padding, sha512}; jws_alg_to_digest_type('RS256') -> {rsa_pkcs1_padding, sha256}; jws_alg_to_digest_type('RS384') -> {rsa_pkcs1_padding, sha384}; jws_alg_to_digest_type('RS512') -> {rsa_pkcs1_padding, sha512}; jws_alg_to_digest_type(ALG) -> erlang:error({not_supported, [ALG]}). %% @private try_generate_key([public_key | Methods], ModulusSize, ExponentSize) -> case code:ensure_loaded(crypto) of {module, crypto} -> case code:ensure_loaded(public_key) of {module, public_key} -> _ = application:ensure_all_started(public_key), case erlang:function_exported(crypto, generate_key, 2) andalso erlang:function_exported(crypto, generate_key, 3) of true -> try public_key:generate_key({rsa, ModulusSize, ExponentSize}) of Key = #'RSAPrivateKey'{} -> {Key, #{}} catch Class:Reason -> erlang:error({public_key_error, {Class, Reason}}) end; false -> try_generate_key(Methods, ModulusSize, ExponentSize) end; _ -> try_generate_key(Methods, ModulusSize, ExponentSize) end; _ -> try_generate_key(Methods, ModulusSize, ExponentSize) end; try_generate_key([cutkey | Methods], ModulusSize, ExponentSize) -> case code:ensure_loaded(cutkey) of {module, cutkey} -> _ = application:ensure_all_started(cutkey), try cutkey:rsa(ModulusSize, ExponentSize, [{return, key}]) of {ok, Key=#'RSAPrivateKey'{}} -> {Key, #{}}; {error, Reason} -> erlang:error({cutkey_error, Reason}) catch Class:Reason -> erlang:error({cutkey_error, {Class, Reason}}) end; _ -> try_generate_key(Methods, ModulusSize, ExponentSize) end; try_generate_key([], ModulusSize, ExponentSize) -> erlang:error({not_supported, [{rsa, ModulusSize, ExponentSize}]}). erlang-jose-1.10.1/src/jwk/jose_jwk_kty_okp_ed25519.erl0000644000232200023220000002100613605433351023067 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 15 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_okp_ed25519). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_use_sig). -include_lib("jose_public_key.hrl"). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_sig callbacks -export([sign/3]). -export([signer/2]). -export([verifier/2]). -export([verify/4]). %% API -export([from_der/1]). -export([from_der/2]). -export([from_key/1]). -export([from_okp/1]). -export([from_openssh_key/1]). -export([from_pem/1]). -export([from_pem/2]). -export([to_der/1]). -export([to_der/2]). -export([to_okp/1]). -export([to_openssh_key/2]). -export([to_pem/1]). -export([to_pem/2]). %% Macros -define(crv, <<"Ed25519">>). -define(secretbytes, 32). -define(publickeybytes, 32). -define(secretkeybytes, 64). %% Types -type publickey() :: << _:256 >>. -type secretkey() :: << _:512 >>. -type key() :: publickey() | secretkey(). -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"d">> := D, <<"x">> := X }) -> << Secret:?secretbytes/binary >> = jose_jwa_base64url:decode(D), << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), SK = << Secret/binary, PK/binary >>, {SK, maps:without([<<"crv">>, <<"d">>, <<"kty">>, <<"x">>], F)}; from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"x">> := X }) -> << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), {PK, maps:without([<<"crv">>, <<"kty">>, <<"x">>], F)}. to_key(<< PublicKey:?publickeybytes/binary >>) -> #'jose_EdDSA25519PublicKey'{ publicKey = PublicKey }; to_key(<< PrivateKey:?secretbytes/binary, PublicKey:?publickeybytes/binary >>) -> #'jose_EdDSA25519PrivateKey'{ publicKey = #'jose_EdDSA25519PublicKey'{ publicKey = PublicKey }, privateKey = PrivateKey }. to_map(PK = << _:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }; to_map(<< Secret:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"d">> => jose_jwa_base64url:encode(Secret), <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }. to_public_map(PK = << _:?publickeybytes/binary >>, F) -> to_map(PK, F); to_public_map(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> to_public_map(PK, F). to_thumbprint_map(K, F) -> maps:with([<<"crv">>, <<"kty">>, <<"x">>], to_public_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(Seed = << _:?secretbytes/binary >>) -> {_PK, SK} = jose_curve25519:eddsa_keypair(Seed), {SK, #{}}; generate_key({okp, 'Ed25519', Seed = << _:?secretbytes/binary >>}) -> generate_key(Seed); generate_key({okp, 'Ed25519'}) -> {_PK, SK} = jose_curve25519:eddsa_keypair(), {SK, #{}}. generate_key(KTY, Fields) when is_binary(KTY) andalso (byte_size(KTY) =:= ?publickeybytes orelse byte_size(KTY) =:= ?secretkeybytes) -> {NewKTY, OtherFields} = generate_key({okp, 'Ed25519'}), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_sig callbacks %%==================================================================== sign(Message, ALG, SK = << _:?secretkeybytes/binary >>) when ALG =:= 'Ed25519' orelse ALG =:= 'EdDSA' -> jose_curve25519:ed25519_sign(Message, SK). signer(<< _:?secretkeybytes/binary >>, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> #{ <<"alg">> => ALG }; signer(<< _:?secretkeybytes/binary >>, _Fields) -> #{ <<"alg">> => <<"EdDSA">> }. verifier(<< _:?publickeybytes/binary >>, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> [ALG]; verifier(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, Fields) -> verifier(PK, Fields); verifier(<< _:?publickeybytes/binary >>, _Fields) -> [?crv, <<"EdDSA">>]. verify(Message, ALG, Signature, << _:?secretbytes/binary, PK:?publickeybytes/binary >>) when ALG =:= 'Ed25519' orelse ALG =:= 'EdDSA' -> verify(Message, ALG, Signature, PK); verify(Message, ALG, Signature, PK = << _:?publickeybytes/binary >>) when ALG =:= 'Ed25519' orelse ALG =:= 'EdDSA' -> jose_curve25519:ed25519_verify(Signature, Message, PK). %%==================================================================== %% API functions %%==================================================================== from_der(DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_der(Password, DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(Password, DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_key(#'jose_EdDSA25519PrivateKey'{publicKey=#'jose_EdDSA25519PublicKey'{publicKey=Public}, privateKey=Secret}) -> {<< Secret/binary, Public/binary >>, #{}}; from_key(#'jose_EdDSA25519PublicKey'{publicKey=Public}) -> {Public, #{}}. from_okp({'Ed25519', SK = << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>}) -> case jose_curve25519:eddsa_secret_to_public(Secret) of PK -> {SK, #{}}; _ -> erlang:error(badarg) end; from_okp({'Ed25519', PK = << _:?publickeybytes/binary >>}) -> {PK, #{}}. from_openssh_key({<<"ssh-ed25519">>, _PK, SK, Comment}) -> {KTY, OtherFields} = from_okp({'Ed25519', SK}), case Comment of <<>> -> {KTY, OtherFields}; _ -> {KTY, maps:merge(#{ <<"kid">> => Comment }, OtherFields)} end. from_pem(PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. from_pem(Password, PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(Password, PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. to_der(SK = << _:?secretkeybytes/binary >>) -> EdDSA25519PrivateKey = to_key(SK), jose_public_key:der_encode('EdDSA25519PrivateKey', EdDSA25519PrivateKey); to_der(PK = << _:?publickeybytes/binary >>) -> EdDSA25519PublicKey = to_key(PK), jose_public_key:der_encode('EdDSA25519PublicKey', EdDSA25519PublicKey). to_der(Password, SK = << _:?secretkeybytes/binary >>) -> EdDSA25519PrivateKey = to_key(SK), jose_jwk_der:to_binary(Password, 'EdDSA25519PrivateKey', EdDSA25519PrivateKey); to_der(Password, PK = << _:?publickeybytes/binary >>) -> EdDSA25519PublicKey = to_key(PK), jose_jwk_der:to_binary(Password, 'EdDSA25519PublicKey', EdDSA25519PublicKey). to_okp(SK = << _:?secretkeybytes/binary >>) -> {'Ed25519', SK}; to_okp(PK = << _:?publickeybytes/binary >>) -> {'Ed25519', PK}. to_openssh_key(SK = << _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> Comment = maps:get(<<"kid">>, F, <<>>), jose_jwk_openssh_key:to_binary([[{{<<"ssh-ed25519">>, PK}, {<<"ssh-ed25519">>, PK, SK, Comment}}]]). to_pem(SK = << _:?secretkeybytes/binary >>) -> EdDSA25519PrivateKey = to_key(SK), PEMEntry = jose_public_key:pem_entry_encode('EdDSA25519PrivateKey', EdDSA25519PrivateKey), jose_public_key:pem_encode([PEMEntry]); to_pem(PK = << _:?publickeybytes/binary >>) -> EdDSA25519PublicKey = to_key(PK), PEMEntry = jose_public_key:pem_entry_encode('EdDSA25519PublicKey', EdDSA25519PublicKey), jose_public_key:pem_encode([PEMEntry]). to_pem(Password, SK = << _:?secretkeybytes/binary >>) -> EdDSA25519PrivateKey = to_key(SK), jose_jwk_pem:to_binary(Password, 'PrivateKeyInfo', EdDSA25519PrivateKey); to_pem(Password, PK = << _:?publickeybytes/binary >>) -> EdDSA25519PublicKey = to_key(PK), jose_jwk_pem:to_binary(Password, 'EdDSA25519PublicKey', EdDSA25519PublicKey). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_der.erl0000644000232200023220000000501513605433351021105 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2020, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 02 Jan 2020 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_der). -include_lib("jose_public_key.hrl"). %% API -export([from_binary/1]). -export([from_binary/2]). -export([to_binary/3]). %%==================================================================== %% API functions %%==================================================================== from_binary(DERBinary) when is_binary(DERBinary) -> case jose_public_key:der_decode(DERBinary) of Key -> jose_jwk_kty:from_key(Key) end. from_binary(Password, DERBinary) when is_binary(DERBinary) -> case jose_public_key:der_decode(DERBinary) of #'EncryptedPrivateKeyInfo'{ encryptionAlgorithm = AlgorithmInfo, encryptedData = EncryptedDER } -> CipherInfo = jose_public_key:decrypt_parameters(AlgorithmInfo), DecryptedDER = jose_public_key:decipher({'PrivateKeyInfo', EncryptedDER, CipherInfo}, Password), from_binary(DecryptedDER); Key -> jose_jwk_kty:from_key(Key) end. to_binary(Password, _KeyType, Key) -> CipherInfo = {"AES-256-CBC", #'PBES2-params'{ keyDerivationFunc = #'PBES2-params_keyDerivationFunc'{ algorithm = ?'id-PBKDF2', parameters = #'PBKDF2-params'{ salt = {specified, crypto:strong_rand_bytes(8)}, iterationCount = 2048, keyLength = asn1_NOVALUE, prf = #'PBKDF2-params_prf'{ algorithm = ?'id-hmacWithSHA256', parameters = {asn1_OPENTYPE, <<5, 0>>} } } }, encryptionScheme = #'PBES2-params_encryptionScheme'{ algorithm = ?'id-aes256-CBC', parameters = {asn1_OPENTYPE, <<4, 16, (crypto:strong_rand_bytes(16))/binary>>} } }}, PasswordString = binary_to_list(iolist_to_binary(Password)), DecryptedDER = jose_public_key:der_encode('PrivateKeyInfo', Key), EncryptedDER = jose_public_key:cipher(DecryptedDER, CipherInfo, PasswordString), AlgorithmInfo = jose_public_key:encrypt_parameters(CipherInfo), jose_public_key:der_encode('EncryptedPrivateKeyInfo', #'EncryptedPrivateKeyInfo'{ encryptionAlgorithm = AlgorithmInfo, encryptedData = EncryptedDER }). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_use_enc.erl0000644000232200023220000000312513605433351021754 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 16 Mar 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_use_enc). -callback block_encryptor(KTY, Fields) -> JWEMap when KTY :: any(), Fields :: map(), JWEMap :: map(). -callback decrypt_private(CipherText, Options, KTY) -> PlainText when CipherText :: iodata(), Options :: any(), KTY :: any(), PlainText :: iodata(). -callback derive_key(KTY) -> DerivedKey when KTY :: any(), DerivedKey :: iodata(). -callback derive_key(OtherKTY, KTY) -> DerivedKey when OtherKTY :: any(), KTY :: any(), DerivedKey :: iodata(). -callback encrypt_public(PlainText, Options, KTY) -> CipherText when PlainText :: iodata(), Options :: any(), KTY :: any(), CipherText :: iodata(). -optional_callbacks([decrypt_private/3]). -optional_callbacks([derive_key/1]). -optional_callbacks([derive_key/2]). -optional_callbacks([encrypt_public/3]). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_kty_okp_ed25519ph.erl0000644000232200023220000001346713605433351023433 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 15 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_okp_ed25519ph). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_use_sig). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_sig callbacks -export([sign/3]). -export([signer/2]). -export([verifier/2]). -export([verify/4]). %% API -export([from_okp/1]). -export([from_openssh_key/1]). -export([to_okp/1]). -export([to_openssh_key/2]). %% Macros -define(crv, <<"Ed25519ph">>). -define(secretbytes, 32). -define(publickeybytes, 32). -define(secretkeybytes, 64). %% Types -type publickey() :: << _:256 >>. -type secretkey() :: << _:512 >>. -type key() :: publickey() | secretkey(). -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"d">> := D, <<"x">> := X }) -> << Secret:?secretbytes/binary >> = jose_jwa_base64url:decode(D), << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), SK = << Secret/binary, PK/binary >>, {SK, maps:without([<<"crv">>, <<"d">>, <<"kty">>, <<"x">>], F)}; from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"x">> := X }) -> << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), {PK, maps:without([<<"crv">>, <<"kty">>, <<"x">>], F)}. to_key(PK = << _:?publickeybytes/binary >>) -> PK; to_key(SK = << _:?secretkeybytes/binary >>) -> SK. to_map(PK = << _:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }; to_map(<< Secret:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"d">> => jose_jwa_base64url:encode(Secret), <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }. to_public_map(PK = << _:?publickeybytes/binary >>, F) -> to_map(PK, F); to_public_map(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> to_public_map(PK, F). to_thumbprint_map(K, F) -> maps:with([<<"crv">>, <<"kty">>, <<"x">>], to_public_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(Seed = << _:?secretbytes/binary >>) -> {_PK, SK} = jose_curve25519:eddsa_keypair(Seed), {SK, #{}}; generate_key({okp, 'Ed25519ph', Seed = << _:?secretbytes/binary >>}) -> generate_key(Seed); generate_key({okp, 'Ed25519ph'}) -> {_PK, SK} = jose_curve25519:eddsa_keypair(), {SK, #{}}. generate_key(KTY, Fields) when is_binary(KTY) andalso (byte_size(KTY) =:= ?publickeybytes orelse byte_size(KTY) =:= ?secretkeybytes) -> {NewKTY, OtherFields} = generate_key({okp, 'Ed25519ph'}), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_sig callbacks %%==================================================================== sign(Message, ALG, SK = << _:?secretkeybytes/binary >>) when ALG =:= 'Ed25519ph' orelse ALG =:= 'EdDSA' -> jose_curve25519:ed25519ph_sign(Message, SK). signer(<< _:?secretkeybytes/binary >>, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> #{ <<"alg">> => ALG }; signer(<< _:?secretkeybytes/binary >>, _Fields) -> #{ <<"alg">> => <<"EdDSA">> }. verifier(<< _:?publickeybytes/binary >>, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> [ALG]; verifier(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, Fields) -> verifier(PK, Fields); verifier(<< _:?publickeybytes/binary >>, _Fields) -> [?crv, <<"EdDSA">>]. verify(Message, ALG, Signature, << _:?secretbytes/binary, PK:?publickeybytes/binary >>) when ALG =:= 'Ed25519ph' orelse ALG =:= 'EdDSA' -> verify(Message, ALG, Signature, PK); verify(Message, ALG, Signature, PK = << _:?publickeybytes/binary >>) when ALG =:= 'Ed25519ph' orelse ALG =:= 'EdDSA' -> jose_curve25519:ed25519ph_verify(Signature, Message, PK). %%==================================================================== %% API functions %%==================================================================== from_okp({'Ed25519ph', SK = << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>}) -> case jose_curve25519:eddsa_secret_to_public(Secret) of PK -> {SK, #{}}; _ -> erlang:error(badarg) end; from_okp({'Ed25519ph', PK = << _:?publickeybytes/binary >>}) -> {PK, #{}}. from_openssh_key({<<"ssh-ed25519ph">>, _PK, SK, Comment}) -> {KTY, OtherFields} = from_okp({'Ed25519ph', SK}), case Comment of <<>> -> {KTY, OtherFields}; _ -> {KTY, maps:merge(#{ <<"kid">> => Comment }, OtherFields)} end. to_okp(SK = << _:?secretkeybytes/binary >>) -> {'Ed25519ph', SK}; to_okp(PK = << _:?publickeybytes/binary >>) -> {'Ed25519ph', PK}. to_openssh_key(SK = << _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> Comment = maps:get(<<"kid">>, F, <<>>), jose_jwk_openssh_key:to_binary([[{{<<"ssh-ed25519ph">>, PK}, {<<"ssh-ed25519ph">>, PK, SK, Comment}}]]). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_pem.erl0000644000232200023220000000754513605433351021126 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 24 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_pem). -include_lib("jose_public_key.hrl"). %% API -export([from_binary/1]). -export([from_binary/2]). -export([from_certificate/1]). -export([from_public_key_info/1]). -export([to_binary/3]). %%==================================================================== %% API functions %%==================================================================== from_binary(PEMBinary) when is_binary(PEMBinary) -> case jose_public_key:pem_decode(PEMBinary) of [CertificatePEMEntry={'Certificate', _, not_encrypted}] -> from_certificate(CertificatePEMEntry); [PEMEntry] -> jose_jwk_kty:from_key(jose_public_key:pem_entry_decode(PEMEntry)); PEMDecodeError -> PEMDecodeError end. from_binary(Password, EncryptedPEMBinary) when is_binary(EncryptedPEMBinary) -> case jose_public_key:pem_decode(EncryptedPEMBinary) of [EncryptedPEMEntry] -> PasswordString = unicode:characters_to_list(Password), jose_jwk_kty:from_key(jose_public_key:pem_entry_decode(EncryptedPEMEntry, PasswordString)); PEMDecodeError -> PEMDecodeError end. from_certificate(CertificateBinary) when is_binary(CertificateBinary) -> case jose_public_key:pem_decode(CertificateBinary) of [CertificatePEMEntry={'Certificate', _, not_encrypted}] -> from_certificate(CertificatePEMEntry); PEMDecodeError -> {error, {pem_decode, PEMDecodeError}} end; from_certificate(CertificatePEMEntry={'Certificate', _, not_encrypted}) -> case jose_public_key:pem_entry_decode(CertificatePEMEntry) of Certificate=#'Certificate'{} -> from_certificate(Certificate); PEMEntryDecodeError -> {error, {pem_entry_decode, PEMEntryDecodeError}} end; from_certificate(#'Certificate'{tbsCertificate=#'TBSCertificate'{subjectPublicKeyInfo=#'SubjectPublicKeyInfo'{}=SubjectPublicKeyInfo}}) -> from_public_key_info(SubjectPublicKeyInfo). from_public_key_info(#'SubjectPublicKeyInfo'{algorithm=#'AlgorithmIdentifier'{}}=SubjectPublicKeyInfo) -> from_public_key_info(jose_public_key:pem_entry_encode('SubjectPublicKeyInfo', SubjectPublicKeyInfo)); from_public_key_info(PEMEntry={'SubjectPublicKeyInfo', DER, not_encrypted}) when is_binary(DER) -> jose_jwk_kty:from_key(jose_public_key:pem_entry_decode(PEMEntry)). to_binary(Password, 'PrivateKeyInfo', Key) -> CipherInfo = {"AES-256-CBC", #'PBES2-params'{ keyDerivationFunc = #'PBES2-params_keyDerivationFunc'{ algorithm = ?'id-PBKDF2', parameters = #'PBKDF2-params'{ salt = {specified, crypto:strong_rand_bytes(8)}, iterationCount = 2048, keyLength = asn1_NOVALUE, prf = #'PBKDF2-params_prf'{ algorithm = ?'id-hmacWithSHA256', parameters = {asn1_OPENTYPE, <<5, 0>>} } } }, encryptionScheme = #'PBES2-params_encryptionScheme'{ algorithm = ?'id-aes256-CBC', parameters = {asn1_OPENTYPE, <<4, 16, (crypto:strong_rand_bytes(16))/binary>>} } }}, PasswordString = binary_to_list(iolist_to_binary(Password)), PEMEntry = jose_public_key:pem_entry_encode('PrivateKeyInfo', Key, {CipherInfo, PasswordString}), jose_public_key:pem_encode([PEMEntry]); to_binary(Password, KeyType, Key) -> CipherInfo = {"AES-256-CBC", crypto:strong_rand_bytes(16)}, PasswordString = binary_to_list(iolist_to_binary(Password)), PEMEntry = jose_public_key:pem_entry_encode(KeyType, Key, {CipherInfo, PasswordString}), jose_public_key:pem_encode([PEMEntry]). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_oct.erl0000644000232200023220000000213613605433351021121 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 18 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_oct). -callback from_oct(OCTBinary) -> {KTY, Fields} when OCTBinary :: binary(), KTY :: any(), Fields :: map(). -callback to_oct(KTY) -> OCTBinary when KTY :: any(), OCTBinary :: binary(). %% API -export([from_binary/1]). %%==================================================================== %% API functions %%==================================================================== from_binary(OCTBinary) when is_binary(OCTBinary) -> jose_jwk_kty:from_oct(OCTBinary). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_openssh_key.erl0000644000232200023220000001651613605433351022672 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc Private key format for OpenSSH %%% See https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key %%% @end %%% Created : 16 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_openssh_key). %% API -export([from_binary/1]). -export([to_binary/1]). %% Macros -define(AUTH_MAGIC, "openssh-key-v1"). -define(OPENSSH_HEAD, "-----BEGIN OPENSSH PRIVATE KEY-----"). -define(OPENSSH_TAIL, "-----END OPENSSH PRIVATE KEY-----"). %%==================================================================== %% API %%==================================================================== from_binary(Binary) when is_binary(Binary) -> parse_keys(Binary, []). to_binary(List) when is_list(List) -> to_binary(List, []). %%%------------------------------------------------------------------- %%% Internal encode functions %%%------------------------------------------------------------------- to_binary([KeyList | List], Acc) when is_list(KeyList) -> to_binary(List, [write_keylist(lists:unzip(KeyList)) | Acc]); to_binary([], Acc) -> iolist_to_binary([[?OPENSSH_HEAD, $\n, chunk(jose_base64:encode(Keys), 70, []), ?OPENSSH_TAIL, $\n] || Keys <- lists:reverse(Acc)]). chunk(Bin, Size, Chunks) when byte_size(Bin) > Size -> << Chunk:Size/binary, Rest/binary >> = Bin, chunk(Rest, Size, [[Chunk, $\n] | Chunks]); chunk(Bin, _Size, Chunks) -> lists:reverse([[Bin, $\n] | Chunks]). write_keylist({PKs, SKs}) when length(PKs) =:= length(SKs) -> N = length(PKs), PKBin = write_publickeys(PKs, []), SKBin = write_secretkeys(SKs, []), Check = crypto:strong_rand_bytes(4), Unpadded = << Check:4/binary, Check:4/binary, SKBin/binary >>, Padded = add_padding(Unpadded, 0), CipherName = <<"none">>, CipherNameLen = byte_size(CipherName), KDFName = <<"none">>, KDFNameLen = byte_size(KDFName), KDFOptions = <<>>, KDFOptionsLen = byte_size(KDFOptions), PaddedLen = byte_size(Padded), << ?AUTH_MAGIC, 16#00, CipherNameLen:32/unsigned-big-integer-unit:1, CipherName:CipherNameLen/binary, KDFNameLen:32/unsigned-big-integer-unit:1, KDFName:KDFNameLen/binary, KDFOptionsLen:32/unsigned-big-integer-unit:1, KDFOptions:KDFOptionsLen/binary, N:32/unsigned-big-integer-unit:1, PKBin/binary, PaddedLen:32/unsigned-big-integer-unit:1, Padded:PaddedLen/binary >>. write_publickeys([PK | PKs], Acc) when is_binary(PK) -> PKSize = byte_size(PK), write_publickeys(PKs, [<< PKSize:32/unsigned-big-integer-unit:1, PK:PKSize/binary >> | Acc]); write_publickeys([{Type, Key} | PKs], Acc) -> TypeLen = byte_size(Type), KeyLen = byte_size(Key), PK = << TypeLen:32/unsigned-big-integer-unit:1, Type:TypeLen/binary, KeyLen:32/unsigned-big-integer-unit:1, Key:KeyLen/binary >>, write_publickeys([PK | PKs], Acc); write_publickeys([], Acc) -> iolist_to_binary(lists:reverse(Acc)). write_secretkeys([{Type, PK, SK, Comment} | SKs], Acc) -> TypeLen = byte_size(Type), PKLen = byte_size(PK), SKLen = byte_size(SK), CommentLen = byte_size(Comment), SecretKey = << TypeLen:32/unsigned-big-integer-unit:1, Type:TypeLen/binary, PKLen:32/unsigned-big-integer-unit:1, PK:PKLen/binary, SKLen:32/unsigned-big-integer-unit:1, SK:SKLen/binary, CommentLen:32/unsigned-big-integer-unit:1, Comment:CommentLen/binary >>, write_secretkeys(SKs, [SecretKey | Acc]); write_secretkeys([], Acc) -> iolist_to_binary(lists:reverse(Acc)). add_padding(U, P) when (byte_size(U) + P) rem 8 =/= 0 -> add_padding(U, P + 1); add_padding(U, P) -> << U/binary, (binary:list_to_bin(lists:seq(1, P)))/binary >>. %%%------------------------------------------------------------------- %%% Internal decode functions %%%------------------------------------------------------------------- %% @private parse_keys(<< ?OPENSSH_HEAD, SoFar/binary >>, Acc) -> case parse_key(SoFar, <<>>) of {Key, Rest} -> parse_keys(Rest, [Key | Acc]); Rest -> parse_keys(Rest, Acc) end; parse_keys(<< _, Rest/binary >>, Acc) -> parse_keys(Rest, Acc); parse_keys(<<>>, Acc) -> lists:reverse(Acc). %% @private parse_key(<< W, Rest/binary >>, Body) when W =:= $\r orelse W =:= $\n orelse W =:= $\s orelse W =:= $\t -> parse_key(Rest, Body); parse_key(<< ?OPENSSH_TAIL, Rest/binary >>, Body) -> case parse_key(jose_base64:decode(Body)) of {true, Key} -> {Key, Rest}; false -> Rest end; parse_key(<< C, Rest/binary >>, Body) -> parse_key(Rest, << Body/binary, C >>); parse_key(<<>>, _Body) -> <<>>. %% @private parse_key(<< ?AUTH_MAGIC, 16#00, CipherNameLen:32/unsigned-big-integer-unit:1, CipherName:CipherNameLen/binary, KDFNameLen:32/unsigned-big-integer-unit:1, KDFName:KDFNameLen/binary, KDFOptionsLen:32/unsigned-big-integer-unit:1, KDFOptions:KDFOptionsLen/binary, N:32/unsigned-big-integer-unit:1, SoFar/binary >>) -> case parse_publickeys(SoFar, N, []) of {true, PKs, << EncryptedLen:32/unsigned-big-integer-unit:1, Encrypted:EncryptedLen/binary >>} -> Header = {CipherName, KDFName, KDFOptions, N}, case maybe_parse_secretkeys(Header, PKs, Encrypted) of {true, Key} -> {true, Key}; false -> {true, {Header, PKs, Encrypted}} end; {true, _PKs, _BadEncrypted} -> false; false -> false end; parse_key(<< _, Rest/binary >>) -> parse_key(Rest); parse_key(<<>>) -> false. %% @private parse_publickeys(Rest, 0, PKs) -> {true, lists:reverse(PKs), Rest}; parse_publickeys(<< PKLen:32/unsigned-big-integer-unit:1, PK:PKLen/binary, Rest/binary >>, N, PKs) -> case parse_publickey(PK) of {true, Type, Key} -> parse_publickeys(Rest, N - 1, [{Type, Key} | PKs]); false -> parse_publickeys(Rest, N - 1, [PK | PKs]) end; parse_publickeys(_Binary, _N, _PKs) -> false. %% @private parse_publickey(<< TypeLen:32/unsigned-big-integer-unit:1, Type:TypeLen/binary, KeyLen:32/unsigned-big-integer-unit:1, Key:KeyLen/binary >>) -> {true, Type, Key}; parse_publickey(_Binary) -> false. %% @private maybe_parse_secretkeys({<<"none">>, <<"none">>, <<>>, N}, PKs, << Check:4/binary, Check:4/binary, SoFar/binary >>) -> case parse_secretkeys(del_padding(SoFar), N, []) of {true, SKs} -> {true, lists:zip(PKs, SKs)}; false -> false end; maybe_parse_secretkeys(_Header, _PKs, _Binary) -> false. %% @private parse_secretkeys(<<>>, 0, SKs) -> {true, lists:reverse(SKs)}; parse_secretkeys(<< TypeLen:32/unsigned-big-integer-unit:1, Type:TypeLen/binary, PKLen:32/unsigned-big-integer-unit:1, PK:PKLen/binary, SKLen:32/unsigned-big-integer-unit:1, SK:SKLen/binary, CommentLen:32/unsigned-big-integer-unit:1, Comment:CommentLen/binary, Rest/binary >>, N, SKs) -> parse_secretkeys(Rest, N - 1, [{Type, PK, SK, Comment} | SKs]); parse_secretkeys(_Binary, _N, _SKs) -> false. %% @private del_padding(<<>>) -> <<>>; del_padding(Padded) when is_binary(Padded) -> Padding = binary:last(Padded), case Padding > byte_size(Padded) of true -> <<>>; false -> del_padding(Padded, Padding) end. %% @private del_padding(Padded, 0) -> Padded; del_padding(Padded, Padding) -> case binary:last(Padded) of Padding -> del_padding(binary:part(Padded, 0, byte_size(Padded) - 1), Padding - 1); _ -> <<>> end. erlang-jose-1.10.1/src/jwk/jose_jwk_use_sig.erl0000644000232200023220000000244613605433351021776 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 16 Mar 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_use_sig). -callback sign(Message, Options, KTY) -> Signature when Message :: iodata(), Options :: any(), KTY :: any(), Signature :: iodata(). -callback signer(KTY, Fields) -> JWSMap when KTY :: any(), Fields :: map(), JWSMap :: map(). -callback verifier(KTY, Fields) -> [JWSALG] when KTY :: any(), Fields :: map(), JWSALG :: iodata(). -callback verify(Message, Options, Signature, KTY) -> boolean() when Message :: iodata(), Options :: any(), Signature :: iodata(), KTY :: any(). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_kty_ec.erl0000644000232200023220000003531213605433351021614 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_ec). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_use_enc). -behaviour(jose_jwk_use_sig). -include_lib("public_key/include/public_key.hrl"). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_enc callbacks -export([block_encryptor/2]). -export([derive_key/2]). %% jose_jwk_use_sig callbacks -export([sign/3]). -export([signer/2]). -export([verifier/2]). -export([verify/4]). %% API -export([from_der/1]). -export([from_der/2]). -export([from_key/1]). -export([from_pem/1]). -export([from_pem/2]). -export([to_der/1]). -export([to_der/2]). -export([to_pem/1]). -export([to_pem/2]). %% Types -type key() :: #'ECPrivateKey'{} | {#'ECPoint'{}, {namedCurve, Oid::tuple()} | #'ECParameters'{}}. -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"EC">>, <<"d">> := _ }) -> from_map_ec_private_key(jose_jwa:ec_key_mode(), maps:remove(<<"kty">>, F), #'ECPrivateKey'{ version = 1 }); from_map(F = #{ <<"kty">> := <<"EC">> }) -> from_map_ec_public_key(maps:remove(<<"kty">>, F), {#'ECPoint'{}, undefined}). to_key(ECPrivateKey=#'ECPrivateKey'{}) -> ECPrivateKey; to_key(ECPublicKey={#'ECPoint'{}, _}) -> ECPublicKey. to_map(#'ECPrivateKey'{ version = 1, privateKey = D, parameters = {namedCurve, Parameters}, publicKey = PublicKey}, Fields) when is_binary(D) andalso is_binary(PublicKey) -> {X, Y} = public_key_to_x_y(PublicKey), Fields#{ <<"d">> => jose_jwa_base64url:encode(D), <<"crv">> => parameters_to_crv(Parameters), <<"kty">> => <<"EC">>, <<"x">> => jose_jwa_base64url:encode(X), <<"y">> => jose_jwa_base64url:encode(Y) }; to_map({#'ECPoint'{ point = PublicKey }, {namedCurve, Parameters}}, Fields) -> {X, Y} = public_key_to_x_y(PublicKey), Fields#{ <<"crv">> => parameters_to_crv(Parameters), <<"kty">> => <<"EC">>, <<"x">> => jose_jwa_base64url:encode(X), <<"y">> => jose_jwa_base64url:encode(Y) }; to_map(ECPrivateKey0=#'ECPrivateKey'{ version = 1, privateKey = D, parameters = {namedCurve, _Parameters}, publicKey = {_, PublicKey}}, Fields) when is_list(D) andalso is_binary(PublicKey) -> ECPrivateKey = ECPrivateKey0#'ECPrivateKey'{ privateKey = list_to_binary(D), publicKey = PublicKey}, to_map(ECPrivateKey, Fields). to_public_map(K=#'ECPrivateKey'{}, F) -> maps:without([<<"d">>], to_map(K, F)); to_public_map(K={#'ECPoint'{}, _}, F) -> to_map(K, F). to_thumbprint_map(K, F) -> maps:with([<<"crv">>, <<"kty">>, <<"x">>, <<"y">>], to_public_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(P=#'ECParameters'{}) -> {public_key:generate_key(P), #{}}; generate_key({namedCurve, P}) when is_atom(P) -> generate_key({namedCurve, pubkey_cert_records:namedCurves(P)}); generate_key(P={namedCurve, _}) -> {public_key:generate_key(P), #{}}; generate_key(#'ECPrivateKey'{ parameters = P }) -> generate_key(P); generate_key({#'ECPoint'{}, P}) -> generate_key(P); generate_key(P) when is_atom(P) -> generate_key({namedCurve, P}); generate_key(<<"P-256">>) -> generate_key(secp256r1); generate_key(<<"P-384">>) -> generate_key(secp384r1); generate_key(<<"P-521">>) -> generate_key(secp521r1); generate_key({ec, P=#'ECParameters'{}}) -> generate_key(P); generate_key({ec, P=#'ECPrivateKey'{}}) -> generate_key(P); generate_key({ec, P={#'ECPoint'{}, _}}) -> generate_key(P); generate_key({ec, P={namedCurve, _}}) -> generate_key(P); generate_key({ec, P}) when is_atom(P) -> generate_key(P); generate_key({ec, P}) when is_binary(P) -> generate_key(P). generate_key(KTY, Fields) -> {NewKTY, OtherFields} = generate_key(KTY), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_enc callbacks %%==================================================================== block_encryptor(_KTY, Fields=#{ <<"alg">> := ALG, <<"enc">> := ENC, <<"use">> := <<"enc">> }) -> Folder = fun (K, V, F) when K =:= <<"apu">> orelse K =:= <<"apv">> orelse K =:= <<"epk">> orelse K =:= <<"skid">> -> maps:put(K, V, F); (_K, _V, F) -> F end, maps:fold(Folder, #{ <<"alg">> => ALG, <<"enc">> => ENC }, Fields); block_encryptor(KTY, Fields=#{ <<"alg">> := <<"ECDH-1PU", _/binary>> }) -> block_encryptor(KTY, maps:merge(Fields, #{ <<"enc">> => case jose_jwa:is_block_cipher_supported({aes_gcm, 128}) of false -> <<"A128CBC-HS256">>; true -> <<"A128GCM">> end, <<"use">> => <<"enc">> })); block_encryptor(KTY, Fields) -> block_encryptor(KTY, maps:merge(Fields, #{ <<"alg">> => <<"ECDH-ES">>, <<"enc">> => case jose_jwa:is_block_cipher_supported({aes_gcm, 128}) of false -> <<"A128CBC-HS256">>; true -> <<"A128GCM">> end, <<"use">> => <<"enc">> })). derive_key({ECPoint=#'ECPoint'{}, _}, ECPrivateKey=#'ECPrivateKey'{}) -> public_key:compute_key(ECPoint, ECPrivateKey); derive_key(#'ECPrivateKey'{parameters=ECParameters, publicKey=Octets}, ECPrivateKey=#'ECPrivateKey'{}) -> ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, derive_key(ECPublicKey, ECPrivateKey). %%==================================================================== %% jose_jwk_use_sig callbacks %%==================================================================== sign(Message, JWSALG, ECPrivateKey=#'ECPrivateKey'{}) -> DigestType = jws_alg_to_digest_type(ECPrivateKey, JWSALG), DERSignature = public_key:sign(Message, DigestType, ECPrivateKey), #'ECDSA-Sig-Value'{ r = R, s = S } = public_key:der_decode('ECDSA-Sig-Value', DERSignature), RBin = int_to_bin(R), SBin = int_to_bin(S), Size = jws_alg_to_r_s_size(JWSALG), RPad = pad(RBin, Size), SPad = pad(SBin, Size), Signature = << RPad/binary, SPad/binary >>, Signature; sign(_Message, _JWSALG, {#'ECPoint'{}, _}) -> erlang:error(not_supported). signer(#'ECPrivateKey'{}, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> #{ <<"alg">> => ALG }; signer(#'ECPrivateKey'{parameters={namedCurve, Parameters}}, _Fields) -> #{ <<"alg">> => case parameters_to_crv(Parameters) of <<"P-256">> -> <<"ES256">>; <<"P-384">> -> <<"ES384">>; <<"P-521">> -> <<"ES512">> end }. verifier(_KTY, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> [ALG]; verifier(#'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0}, Fields) -> Octets = case Octets0 of {_, Octets1} -> Octets1; _ -> Octets0 end, ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, verifier(ECPublicKey, Fields); verifier({#'ECPoint'{}, {namedCurve, Parameters}}, _Fields) -> [ case parameters_to_crv(Parameters) of <<"P-256">> -> <<"ES256">>; <<"P-384">> -> <<"ES384">>; <<"P-521">> -> <<"ES512">> end ]. verify(Message, JWSALG, Signature, ECPublicKey={#'ECPoint'{}, _}) -> try jws_alg_to_digest_type(ECPublicKey, JWSALG) of DigestType -> SignatureLen = byte_size(Signature), {RBin, SBin} = split_binary(Signature, (SignatureLen div 2)), R = crypto:bytes_to_integer(RBin), S = crypto:bytes_to_integer(SBin), DERSignature = public_key:der_encode('ECDSA-Sig-Value', #'ECDSA-Sig-Value'{ r = R, s = S }), public_key:verify(Message, DigestType, DERSignature, ECPublicKey) catch error:{not_supported, _} -> false end; verify(Message, JWSALG, Signature, #'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0}) -> Octets = case Octets0 of {_, Octets1} -> Octets1; _ -> Octets0 end, ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, verify(Message, JWSALG, Signature, ECPublicKey). %%==================================================================== %% API functions %%==================================================================== from_der(DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_der(Password, PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_der:from_binary(Password, PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. from_key(ECPrivateKey=#'ECPrivateKey'{}) -> {ECPrivateKey, #{}}; from_key(ECPublicKey={#'ECPoint'{}, _}) -> {ECPublicKey, #{}}. from_pem(PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. from_pem(Password, PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(Password, PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. to_der(ECPrivateKey=#'ECPrivateKey'{}) -> jose_public_key:der_encode('PrivateKeyInfo', ECPrivateKey); to_der(ECPublicKey={#'ECPoint'{}, _ECParameters}) -> jose_public_key:der_encode('SubjectPublicKeyInfo', ECPublicKey). to_der(Password, ECPrivateKey=#'ECPrivateKey'{}) -> jose_jwk_der:to_binary(Password, 'PrivateKeyInfo', ECPrivateKey); to_der(Password, ECPublicKey={#'ECPoint'{}, _ECParameters}) -> erlang:error({badarg, [Password, ECPublicKey]}). to_pem(ECPrivateKey=#'ECPrivateKey'{}) -> PEMEntry = jose_public_key:pem_entry_encode('PrivateKeyInfo', ECPrivateKey), jose_public_key:pem_encode([PEMEntry]); to_pem(ECPublicKey={#'ECPoint'{}, _ECParameters}) -> PEMEntry = jose_public_key:pem_entry_encode('SubjectPublicKeyInfo', ECPublicKey), jose_public_key:pem_encode([PEMEntry]). to_pem(Password, ECPrivateKey=#'ECPrivateKey'{}) -> jose_jwk_pem:to_binary(Password, 'PrivateKeyInfo', ECPrivateKey); to_pem(Password, ECPublicKey={#'ECPoint'{}, _ECParameters}) -> erlang:error({badarg, [Password, ECPublicKey]}). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private from_map_ec_private_key(binary, F = #{ <<"d">> := D }, Key) -> from_map_ec_private_key(binary, maps:remove(<<"d">>, F), Key#'ECPrivateKey'{ privateKey = jose_jwa_base64url:decode(D) }); from_map_ec_private_key(list, F = #{ <<"d">> := D }, Key) -> from_map_ec_private_key(list, maps:remove(<<"d">>, F), Key#'ECPrivateKey'{ privateKey = binary_to_list(jose_jwa_base64url:decode(D)) }); from_map_ec_private_key(ECMode, F = #{ <<"crv">> := <<"P-256">> }, Key) -> from_map_ec_private_key(ECMode, maps:remove(<<"crv">>, F), Key#'ECPrivateKey'{ parameters = {namedCurve, pubkey_cert_records:namedCurves(secp256r1)} }); from_map_ec_private_key(ECMode, F = #{ <<"crv">> := <<"P-384">> }, Key) -> from_map_ec_private_key(ECMode, maps:remove(<<"crv">>, F), Key#'ECPrivateKey'{ parameters = {namedCurve, pubkey_cert_records:namedCurves(secp384r1)} }); from_map_ec_private_key(ECMode, F = #{ <<"crv">> := <<"P-521">> }, Key) -> from_map_ec_private_key(ECMode, maps:remove(<<"crv">>, F), Key#'ECPrivateKey'{ parameters = {namedCurve, pubkey_cert_records:namedCurves(secp521r1)} }); from_map_ec_private_key(binary, F = #{ <<"x">> := X, <<"y">> := Y }, Key) -> from_map_ec_private_key(binary, maps:without([<<"x">>, <<"y">>], F), Key#'ECPrivateKey'{ publicKey = << 16#04, (jose_jwa_base64url:decode(X))/binary, (jose_jwa_base64url:decode(Y))/binary >> }); from_map_ec_private_key(list, F = #{ <<"x">> := X, <<"y">> := Y }, Key) -> from_map_ec_private_key(list, maps:without([<<"x">>, <<"y">>], F), Key#'ECPrivateKey'{ publicKey = {0, << 16#04, (jose_jwa_base64url:decode(X))/binary, (jose_jwa_base64url:decode(Y))/binary >>} }); from_map_ec_private_key(_ECMode, F, Key) -> {Key, F}. %% @private from_map_ec_public_key(F = #{ <<"crv">> := <<"P-256">> }, {Point, _Params}) -> from_map_ec_public_key(maps:remove(<<"crv">>, F), {Point, {namedCurve, pubkey_cert_records:namedCurves(secp256r1)}}); from_map_ec_public_key(F = #{ <<"crv">> := <<"P-384">> }, {Point, _Params}) -> from_map_ec_public_key(maps:remove(<<"crv">>, F), {Point, {namedCurve, pubkey_cert_records:namedCurves(secp384r1)}}); from_map_ec_public_key(F = #{ <<"crv">> := <<"P-521">> }, {Point, _Params}) -> from_map_ec_public_key(maps:remove(<<"crv">>, F), {Point, {namedCurve, pubkey_cert_records:namedCurves(secp521r1)}}); from_map_ec_public_key(F = #{ <<"x">> := X, <<"y">> := Y }, {Point, Params}) -> from_map_ec_public_key(maps:without([<<"x">>, <<"y">>], F), {Point#'ECPoint'{ point = << 16#04, (jose_jwa_base64url:decode(X))/binary, (jose_jwa_base64url:decode(Y))/binary >> }, Params}); from_map_ec_public_key(F, Key) -> {Key, F}. %% @private int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); int_to_bin(X) -> int_to_bin_pos(X, []). %% @private int_to_bin_pos(0,Ds=[_|_]) -> list_to_binary(Ds); int_to_bin_pos(X,Ds) -> int_to_bin_pos(X bsr 8, [(X band 255)|Ds]). %% @private int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 -> list_to_binary(Ds); int_to_bin_neg(X,Ds) -> int_to_bin_neg(X bsr 8, [(X band 255)|Ds]). %% @private jws_alg_to_digest_type(<<"P-256">>, 'ES256') -> sha256; jws_alg_to_digest_type(<<"P-384">>, 'ES384') -> sha384; jws_alg_to_digest_type(<<"P-521">>, 'ES512') -> sha512; jws_alg_to_digest_type(#'ECPrivateKey'{parameters={namedCurve, Parameters}}, ALG) -> jws_alg_to_digest_type(parameters_to_crv(Parameters), ALG); jws_alg_to_digest_type({#'ECPoint'{}, {namedCurve, Parameters}}, ALG) -> jws_alg_to_digest_type(parameters_to_crv(Parameters), ALG); jws_alg_to_digest_type(KeyOrCurve, ALG) -> erlang:error({not_supported, [KeyOrCurve, ALG]}). %% @private jws_alg_to_r_s_size('ES256') -> 32; jws_alg_to_r_s_size('ES384') -> 48; jws_alg_to_r_s_size('ES512') -> 66. %% @private pad(Bin, Size) when byte_size(Bin) =:= Size -> Bin; pad(Bin, Size) -> pad(<< 0, Bin/binary >>, Size). %% @private parameters_to_crv(secp256r1) -> <<"P-256">>; parameters_to_crv(secp384r1) -> <<"P-384">>; parameters_to_crv(secp521r1) -> <<"P-521">>; parameters_to_crv(Parameters) when is_tuple(Parameters) -> parameters_to_crv(pubkey_cert_records:namedCurves(Parameters)). %% @private public_key_to_x_y(<< 16#04, X:32/binary, Y:32/binary >>) -> {X, Y}; public_key_to_x_y(<< 16#04, X:48/binary, Y:48/binary >>) -> {X, Y}; public_key_to_x_y(<< 16#04, X:66/binary, Y:66/binary >>) -> {X, Y}. erlang-jose-1.10.1/src/jwk/jose_jwk_kty_oct.erl0000644000232200023220000001226013605433351022007 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 21 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_oct). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_oct). -behaviour(jose_jwk_use_enc). -behaviour(jose_jwk_use_sig). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_enc callbacks -export([block_encryptor/2]). -export([derive_key/1]). %% jose_jwk_use_sig callbacks -export([sign/3]). -export([signer/2]). -export([verifier/2]). -export([verify/4]). %% jose_jwk_oct callbacks -export([from_oct/1]). -export([to_oct/1]). %% Types -type key() :: binary(). -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"oct">>, <<"k">> := K }) -> {jose_jwa_base64url:decode(K), maps:without([<<"k">>, <<"kty">>], F)}. to_key(Key) -> Key. to_map(K, F) -> F#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) }. to_public_map(_K, _F) -> erlang:error({not_supported, [to_public_map]}). to_thumbprint_map(K, F) -> maps:with([<<"k">>, <<"kty">>], to_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(Size) when is_integer(Size) -> {crypto:strong_rand_bytes(Size), #{}}; generate_key({oct, Size}) when is_integer(Size) -> generate_key(Size). generate_key(KTY, Fields) -> {NewKTY, OtherFields} = generate_key(byte_size(KTY)), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_enc callbacks %%==================================================================== block_encryptor(_KTY, #{ <<"alg">> := ALG, <<"enc">> := ENC, <<"use">> := <<"enc">> }) -> #{ <<"alg">> => ALG, <<"enc">> => ENC }; block_encryptor(KTY, Fields) -> ENC = case bit_size(KTY) of 128 -> <<"A128GCM">>; 192 -> <<"A192GCM">>; 256 -> case jose_jwa:is_block_cipher_supported({aes_gcm, 256}) of false -> <<"A128CBC-HS256">>; true -> <<"A256GCM">> end; 384 -> <<"A192CBC-HS384">>; 512 -> <<"A256CBC-HS512">>; _ -> erlang:error({badarg, [KTY, Fields]}) end, #{ <<"alg">> => <<"dir">>, <<"enc">> => ENC }. derive_key(Key) -> Key. %%==================================================================== %% jose_jwk_use_sig callbacks %%==================================================================== sign(Message, JWSALG, Key) when is_atom(JWSALG) -> DigestType = jws_alg_to_digest_type(JWSALG), crypto:hmac(DigestType, Key, Message); sign(Message, {'Poly1305', Nonce}, Key) -> jose_chacha20_poly1305:authenticate(Message, Key, Nonce); sign(_Message, JWSALG, _Key) -> erlang:error({not_supported, [JWSALG]}). signer(_KTY, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> #{ <<"alg">> => ALG }; signer(Key, _Fields) -> #{ <<"alg">> => case bit_size(Key) of KeySize when KeySize < 384 -> <<"HS256">>; KeySize when KeySize < 512 -> <<"HS384">>; _ -> <<"HS512">> end }. verifier(_KTY, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> [ALG]; verifier(Key, _Fields) -> case bit_size(Key) of 256 -> case jose_jwa:is_chacha20_poly1305_supported() of true -> [<<"HS256">>, <<"Poly1305">>]; false -> [<<"HS256">>] end; KeySize when KeySize < 384 -> [<<"HS256">>]; KeySize when KeySize < 512 -> [<<"HS256">>, <<"HS384">>]; _ -> [<<"HS256">>, <<"HS384">>, <<"HS512">>] end. verify(Message, JWSALG, Signature, Key) when is_atom(JWSALG) -> try sign(Message, JWSALG, Key) of Challenge -> jose_jwa:constant_time_compare(Signature, Challenge) catch error:{not_supported, _} -> false end; verify(Message, {'Poly1305', Nonce}, Signature, Key) -> jose_chacha20_poly1305:verify(Signature, Message, Key, Nonce). %%==================================================================== %% jose_jwk_oct callbacks %%==================================================================== from_oct(OCTBinary) when is_binary(OCTBinary) -> {OCTBinary, #{}}. to_oct(OCTBinary) when is_binary(OCTBinary) -> OCTBinary. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private jws_alg_to_digest_type('HS256') -> sha256; jws_alg_to_digest_type('HS384') -> sha384; jws_alg_to_digest_type('HS512') -> sha512; jws_alg_to_digest_type(ALG) -> erlang:error({not_supported, [ALG]}). erlang-jose-1.10.1/src/jwk/jose_jwk.erl0000644000232200023220000011636613605433351020267 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 21 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk). -include("jose_jwe.hrl"). -include("jose_jwk.hrl"). -include("jose_jws.hrl"). -callback from_map(Fields) -> KTY when Fields :: map(), KTY :: any(). -callback to_key(KTY) -> Key when KTY :: any(), Key :: any(). -callback to_map(KTY, Fields) -> Map when KTY :: any(), Fields :: map(), Map :: map(). -callback to_public_map(KTY, Fields) -> Map when KTY :: any(), Fields :: map(), Map :: map(). -callback to_thumbprint_map(KTY, Fields) -> Map when KTY :: any(), Fields :: map(), Map :: map(). %% Decode API -export([from/1]). -export([from/2]). -export([from_binary/1]). -export([from_binary/2]). -export([from_der/1]). -export([from_der/2]). -export([from_der_file/1]). -export([from_der_file/2]). -export([from_file/1]). -export([from_file/2]). -export([from_firebase/1]). -export([from_key/1]). -export([from_map/1]). -export([from_map/2]). -export([from_oct/1]). -export([from_oct/2]). -export([from_oct_file/1]). -export([from_oct_file/2]). -export([from_okp/1]). -export([from_openssh_key/1]). -export([from_openssh_key_file/1]). -export([from_pem/1]). -export([from_pem/2]). -export([from_pem_file/1]). -export([from_pem_file/2]). %% Encode API -export([to_binary/1]). -export([to_binary/2]). -export([to_binary/3]). -export([to_der/1]). -export([to_der/2]). -export([to_der_file/2]). -export([to_der_file/3]). -export([to_file/2]). -export([to_file/3]). -export([to_file/4]). -export([to_key/1]). -export([to_map/1]). -export([to_map/2]). -export([to_map/3]). -export([to_oct/1]). -export([to_oct/2]). -export([to_oct/3]). -export([to_oct_file/2]). -export([to_oct_file/3]). -export([to_oct_file/4]). -export([to_okp/1]). -export([to_openssh_key/1]). -export([to_openssh_key_file/2]). -export([to_pem/1]). -export([to_pem/2]). -export([to_pem_file/2]). -export([to_pem_file/3]). -export([to_public/1]). -export([to_public_file/2]). -export([to_public_key/1]). -export([to_public_map/1]). -export([to_thumbprint_map/1]). %% API -export([block_decrypt/2]). -export([block_encrypt/2]). -export([block_encrypt/3]). -export([block_encryptor/1]). -export([box_decrypt/2]). -export([box_encrypt/2]). -export([box_encrypt/3]). -export([box_encrypt/4]). -deprecated([{box_decrypt, 2, next_major_release}]). -deprecated([{box_encrypt, 2, next_major_release}]). -deprecated([{box_encrypt, 3, next_major_release}]). -deprecated([{box_encrypt, 4, next_major_release}]). -export([box_decrypt_ecdh_1pu/3]). -export([box_encrypt_ecdh_1pu/3]). -export([box_encrypt_ecdh_1pu/4]). -export([box_encrypt_ecdh_1pu/5]). -export([box_decrypt_ecdh_es/2]). -export([box_encrypt_ecdh_es/2]). -export([box_encrypt_ecdh_es/3]). -export([box_encrypt_ecdh_es/4]). -export([generate_key/1]). -export([merge/2]). -export([shared_secret/2]). -export([sign/2]). -export([sign/3]). -export([signer/1]). -export([thumbprint/1]). -export([thumbprint/2]). -export([thumbprint_concat/1]). -export([thumbprint_concat/2]). -export([verifier/1]). -export([verify/2]). -export([verify_strict/3]). %% Types -type key() :: #jose_jwk{}. -export_type([key/0]). -define(KEYS_MODULE, jose_jwk_set). -define(KTY_EC_MODULE, jose_jwk_kty_ec). -define(KTY_OCT_MODULE, jose_jwk_kty_oct). -define(KTY_RSA_MODULE, jose_jwk_kty_rsa). -define(KTY_OKP_Ed25519_MODULE, jose_jwk_kty_okp_ed25519). -define(KTY_OKP_Ed25519ph_MODULE, jose_jwk_kty_okp_ed25519ph). -define(KTY_OKP_X25519_MODULE, jose_jwk_kty_okp_x25519). -define(KTY_OKP_Ed448_MODULE, jose_jwk_kty_okp_ed448). -define(KTY_OKP_Ed448ph_MODULE, jose_jwk_kty_okp_ed448ph). -define(KTY_OKP_X448_MODULE, jose_jwk_kty_okp_x448). %%==================================================================== %% Decode API functions %%==================================================================== from(List) when is_list(List) -> [from(Element) || Element <- List]; from({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> from_map({Modules, Map}); from({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> from_binary({Modules, Binary}); from(JWK=#jose_jwk{}) -> JWK; from(Other) when is_map(Other) orelse is_binary(Other) -> from({#{}, Other}). from(Key, List) when is_list(List) -> [from(Key, Element) || Element <- List]; from(Key, {Modules, EncryptedMap}) when is_map(Modules) andalso is_map(EncryptedMap) -> from_map(Key, {Modules, EncryptedMap}); from(Key, {Modules, EncryptedBinary}) when is_map(Modules) andalso is_binary(EncryptedBinary) -> from_binary(Key, {Modules, EncryptedBinary}); from(_Key, JWK=#jose_jwk{}) -> JWK; from(Key, Other) when is_map(Other) orelse is_binary(Other) -> from(Key, {#{}, Other}). from_binary(List) when is_list(List) -> [from_binary(Element) || Element <- List]; from_binary({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> from_map({Modules, jose:decode(Binary)}); from_binary(Binary) when is_binary(Binary) -> from_binary({#{}, Binary}). from_binary(Key, List) when is_list(List) -> [from_binary(Key, Element) || Element <- List]; from_binary(Key, {Modules, Encrypted = << ${, _/binary >>}) when is_map(Modules) andalso is_binary(Encrypted) -> EncrypedMap = jose:decode(Encrypted), from_map(Key, {Modules, EncrypedMap}); from_binary(Key, {Modules, Encrypted}) when is_map(Modules) andalso is_binary(Encrypted) -> {JWKBinary, JWE=#jose_jwe{}} = jose_jwe:block_decrypt(Key, {Modules, Encrypted}), {JWE, from_binary({Modules, JWKBinary})}; from_binary(Key, Encrypted) when is_binary(Encrypted) -> from_binary(Key, {#{}, Encrypted}). from_der(List) when is_list(List) -> [from_der(Element) || Element <- List]; from_der({#{ kty := Module }, Binary}) when is_binary(Binary) -> {KTY, Fields} = Module:from_der(Binary), #jose_jwk{ kty = {Module, KTY}, fields = Fields }; from_der({#{}, Binary}) when is_binary(Binary) -> case jose_jwk_der:from_binary(Binary) of {Module, {KTY, Fields}} when Module =/= error -> #jose_jwk{ kty = {Module, KTY}, fields = Fields }; PEMError -> PEMError end; from_der(Binary) when is_binary(Binary) -> from_der({#{}, Binary}). from_der(Key, List) when is_list(List) -> [from_der(Key, Element) || Element <- List]; from_der(Key, {#{ kty := Module }, Binary}) when is_binary(Binary) -> {KTY, Fields} = Module:from_der(Key, Binary), #jose_jwk{ kty = {Module, KTY}, fields = Fields }; from_der(Key, {#{}, Binary}) when is_binary(Binary) -> case jose_jwk_der:from_binary(Key, Binary) of {Module, {KTY, Fields}} when Module =/= error -> #jose_jwk{ kty = {Module, KTY}, fields = Fields }; PEMError -> PEMError end; from_der(Key, Binary) when is_binary(Binary) -> from_der(Key, {#{}, Binary}). from_der_file({Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_der({Modules, Binary}); ReadError -> ReadError end; from_der_file(File) when is_binary(File) orelse is_list(File) -> from_der_file({#{}, File}). from_der_file(Key, {Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_der(Key, {Modules, Binary}); ReadError -> ReadError end; from_der_file(Key, File) when is_binary(File) orelse is_list(File) -> from_der_file(Key, {#{}, File}). from_file({Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_binary({Modules, Binary}); ReadError -> ReadError end; from_file(File) when is_binary(File) orelse is_list(File) -> from_file({#{}, File}). from_file(Key, {Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_binary(Key, {Modules, Binary}); ReadError -> ReadError end; from_file(Key, File) when is_binary(File) orelse is_list(File) -> from_file(Key, {#{}, File}). from_firebase(Binary) when is_binary(Binary) -> from_firebase({#{}, Binary}); from_firebase({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> Map = jose:decode(Binary), from_firebase({Modules, Map}); from_firebase(Map) when is_map(Map) -> from_firebase({#{}, Map}); from_firebase({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> Folder = fun (Key, Val, Acc) -> JWK = jose_jwk:merge(jose_jwk:from_pem({Modules, Val}), #{ <<"kid">> => Key }), maps:put(Key, JWK, Acc) end, maps:fold(Folder, #{}, Map). from_key(List) when is_list(List) -> [from_key(Element) || Element <- List]; from_key(Key) -> case jose_jwk_kty:from_key(Key) of {KTYModule, {KTY, Fields}} when KTYModule =/= error -> #jose_jwk{ kty = {KTYModule, KTY}, fields = Fields }; FromKeyError -> FromKeyError end. from_map(List) when is_list(List) -> [from_map(Element) || Element <- List]; from_map(Map) when is_map(Map) -> from_map({#{}, Map}); from_map({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> from_map({#jose_jwk{}, Modules, Map}); from_map({JWK, Modules=#{ keys := Module }, Map=#{ <<"keys">> := _ }}) -> {KEYS, Fields} = Module:from_map(Map), from_map({JWK#jose_jwk{ keys = {Module, KEYS} }, maps:remove(keys, Modules), Fields}); from_map({JWK, Modules=#{ kty := Module }, Map=#{ <<"kty">> := _ }}) -> {KTY, Fields} = Module:from_map(Map), from_map({JWK#jose_jwk{ kty = {Module, KTY} }, maps:remove(kty, Modules), Fields}); from_map({JWK, Modules, Map=#{ <<"keys">> := _ }}) -> from_map({JWK, Modules#{ keys => ?KEYS_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"EC">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_EC_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"oct">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_OCT_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"OKP">>, <<"crv">> := <<"Ed25519">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_OKP_Ed25519_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"OKP">>, <<"crv">> := <<"Ed25519ph">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_OKP_Ed25519ph_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"OKP">>, <<"crv">> := <<"X25519">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_OKP_X25519_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"OKP">>, <<"crv">> := <<"Ed448">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_OKP_Ed448_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"OKP">>, <<"crv">> := <<"Ed448ph">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_OKP_Ed448ph_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"OKP">>, <<"crv">> := <<"X448">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_OKP_X448_MODULE }, Map}); from_map({JWK, Modules, Map=#{ <<"kty">> := <<"RSA">> }}) -> from_map({JWK, Modules#{ kty => ?KTY_RSA_MODULE }, Map}); from_map({#jose_jwk{ keys = undefined, kty = undefined }, _Modules, _Map}) -> {error, {missing_required_keys, [<<"keys">>, <<"kty">>]}}; from_map({JWK, _Modules, Fields}) -> JWK#jose_jwk{ fields = Fields }. from_map(Key, List) when is_list(List) -> [from_map(Key, Element) || Element <- List]; from_map(Key, {Modules, Encrypted}) when is_map(Modules) andalso is_map(Encrypted) -> {JWKBinary, JWE=#jose_jwe{}} = jose_jwe:block_decrypt(Key, {Modules, Encrypted}), {JWE, from_binary({Modules, JWKBinary})}; from_map(Key, Encrypted) when is_map(Encrypted) -> from_map(Key, {#{}, Encrypted}). from_oct(List) when is_list(List) -> [from_oct(Element) || Element <- List]; from_oct({#{ kty := Module }, Binary}) when is_binary(Binary) -> {KTY, Fields} = Module:from_oct(Binary), #jose_jwk{ kty = {Module, KTY}, fields = Fields }; from_oct({#{}, Binary}) when is_binary(Binary) -> case jose_jwk_oct:from_binary(Binary) of {Module, {KTY, Fields}} when Module =/= error -> #jose_jwk{ kty = {Module, KTY}, fields = Fields }; OCTError -> OCTError end; from_oct(Binary) when is_binary(Binary) -> from_oct({#{}, Binary}). from_oct(Key, List) when is_list(List) -> [from_oct(Key, Element) || Element <- List]; from_oct(Key, {Modules, Encrypted}) when is_map(Modules) andalso is_binary(Encrypted) -> {OCTBinary, JWE=#jose_jwe{}} = jose_jwe:block_decrypt(Key, {Modules, Encrypted}), {JWE, from_oct({Modules, OCTBinary})}; from_oct(Key, Encrypted) when is_binary(Encrypted) -> from_oct(Key, {#{}, Encrypted}). from_oct_file({Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_oct({Modules, Binary}); ReadError -> ReadError end; from_oct_file(File) when is_binary(File) orelse is_list(File) -> from_oct_file({#{}, File}). from_oct_file(Key, {Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_oct(Key, {Modules, Binary}); ReadError -> ReadError end; from_oct_file(Key, File) when is_binary(File) orelse is_list(File) -> from_oct_file(Key, {#{}, File}). from_okp(List) when is_list(List) -> [from_okp(Element) || Element <- List]; from_okp({#{ kty := Module }, OKP}) -> {KTY, Fields} = Module:from_okp(OKP), #jose_jwk{ kty = {Module, KTY}, fields = Fields }; from_okp(P={'Ed25519', Binary}) when is_binary(Binary) -> from_okp({#{ kty => ?KTY_OKP_Ed25519_MODULE }, P}); from_okp(P={'Ed25519ph', Binary}) when is_binary(Binary) -> from_okp({#{ kty => ?KTY_OKP_Ed25519ph_MODULE }, P}); from_okp(P={'X25519', Binary}) when is_binary(Binary) -> from_okp({#{ kty => ?KTY_OKP_X25519_MODULE }, P}); from_okp(P={'Ed448', Binary}) when is_binary(Binary) -> from_okp({#{ kty => ?KTY_OKP_Ed448_MODULE }, P}); from_okp(P={'Ed448ph', Binary}) when is_binary(Binary) -> from_okp({#{ kty => ?KTY_OKP_Ed448ph_MODULE }, P}); from_okp(P={'X448', Binary}) when is_binary(Binary) -> from_okp({#{ kty => ?KTY_OKP_X448_MODULE }, P}). from_openssh_key(List) when is_list(List) -> [from_openssh_key(Element) || Element <- List]; from_openssh_key({#{ kty := Module }, Binary}) when is_binary(Binary) -> {KTY, Fields} = Module:from_openssh_key(Binary), #jose_jwk{ kty = {Module, KTY}, fields = Fields }; from_openssh_key({#{}, Binary}) when is_binary(Binary) -> case jose_jwk_openssh_key:from_binary(Binary) of CurrentKey = [[{{Type, PK}, Key = {Type, PK, _SK, _Comment}} | _] | _] -> Module = case Type of <<"ssh-ed25519">> -> ?KTY_OKP_Ed25519_MODULE; <<"ssh-ed25519ph">> -> ?KTY_OKP_Ed25519ph_MODULE; <<"ssh-x25519">> -> ?KTY_OKP_X25519_MODULE; <<"ssh-ed448">> -> ?KTY_OKP_Ed448_MODULE; <<"ssh-ed448ph">> -> ?KTY_OKP_Ed448ph_MODULE; <<"ssh-x448">> -> ?KTY_OKP_X448_MODULE; _ -> {error, {unknown_key, CurrentKey}} end, case is_atom(Module) of true -> {KTY, Fields} = Module:from_openssh_key(Key), #jose_jwk{ kty = {Module, KTY}, fields = Fields }; false -> Module end; UnknownKey -> {error, {unknown_key, UnknownKey}} end; from_openssh_key(Binary) when is_binary(Binary) -> from_openssh_key({#{}, Binary}). from_openssh_key_file({Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_openssh_key({Modules, Binary}); ReadError -> ReadError end; from_openssh_key_file(File) when is_binary(File) orelse is_list(File) -> from_openssh_key_file({#{}, File}). from_pem(List) when is_list(List) -> [from_pem(Element) || Element <- List]; from_pem({#{ kty := Module }, Binary}) when is_binary(Binary) -> {KTY, Fields} = Module:from_pem(Binary), #jose_jwk{ kty = {Module, KTY}, fields = Fields }; from_pem({#{}, Binary}) when is_binary(Binary) -> case jose_jwk_pem:from_binary(Binary) of {Module, {KTY, Fields}} when Module =/= error -> #jose_jwk{ kty = {Module, KTY}, fields = Fields }; PEMError -> PEMError end; from_pem(Binary) when is_binary(Binary) -> from_pem({#{}, Binary}). from_pem(Key, List) when is_list(List) -> [from_pem(Key, Element) || Element <- List]; from_pem(Key, {#{ kty := Module }, Binary}) when is_binary(Binary) -> {KTY, Fields} = Module:from_pem(Key, Binary), #jose_jwk{ kty = {Module, KTY}, fields = Fields }; from_pem(Key, {#{}, Binary}) when is_binary(Binary) -> case jose_jwk_pem:from_binary(Key, Binary) of {Module, {KTY, Fields}} when Module =/= error -> #jose_jwk{ kty = {Module, KTY}, fields = Fields }; PEMError -> PEMError end; from_pem(Key, Binary) when is_binary(Binary) -> from_pem(Key, {#{}, Binary}). from_pem_file({Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_pem({Modules, Binary}); ReadError -> ReadError end; from_pem_file(File) when is_binary(File) orelse is_list(File) -> from_pem_file({#{}, File}). from_pem_file(Key, {Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_pem(Key, {Modules, Binary}); ReadError -> ReadError end; from_pem_file(Key, File) when is_binary(File) orelse is_list(File) -> from_pem_file(Key, {#{}, File}). %%==================================================================== %% Encode API functions %%==================================================================== to_binary(List) when is_list(List) -> [to_binary(Element) || Element <- List]; to_binary(JWK=#jose_jwk{}) -> {Modules, Map} = to_map(JWK), {Modules, jose:encode(Map)}; to_binary(Other) -> to_binary(from(Other)). to_binary(Key, List) when is_list(List) -> [to_binary(Key, Element) || Element <- List]; to_binary(Key, JWK=#jose_jwk{kty={Module, KTY}, fields=Fields}) -> to_binary(Key, Module:key_encryptor(KTY, Fields, Key), JWK); to_binary(Key, Other) -> to_binary(Key, from(Other)). to_binary(Key, JWE=#jose_jwe{}, JWK=#jose_jwk{}) -> {Modules, EncryptedMap} = to_map(Key, JWE, JWK), {Modules, jose:encode(EncryptedMap)}; to_binary(Key, JWEOther, JWKOther) -> to_binary(Key, jose_jwe:from(JWEOther), from(JWKOther)). to_der(List) when is_list(List) -> [to_der(Element) || Element <- List]; to_der(#jose_jwk{kty={Module, KTY}}) -> {#{ kty => Module }, Module:to_der(KTY)}; to_der(Other) -> to_der(from(Other)). to_der(Key, #jose_jwk{kty={Module, KTY}}) -> {#{ kty => Module }, Module:to_der(Key, KTY)}; to_der(Key, Other) -> to_der(Key, from(Other)). to_der_file(File, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_der(JWK), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_der_file(File, Other) when is_binary(File) orelse is_list(File) -> to_der_file(File, from(Other)). to_der_file(Key, File, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_der(Key, JWK), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_der_file(Key, File, Other) when is_binary(File) orelse is_list(File) -> to_der_file(Key, File, from(Other)). to_file(File, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_binary(JWK), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_file(File, Other) when is_binary(File) orelse is_list(File) -> to_file(File, from(Other)). to_file(Key, File, JWK=#jose_jwk{kty={Module, KTY}, fields=Fields}) when is_binary(File) orelse is_list(File) -> to_file(Key, File, Module:key_encryptor(KTY, Fields, Key), JWK); to_file(Key, File, Other) when is_binary(File) orelse is_list(File) -> to_file(Key, File, from(Other)). to_file(Key, File, JWE=#jose_jwe{}, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, EncryptedBinary} = to_binary(Key, JWE, JWK), case file:write_file(File, EncryptedBinary) of ok -> {Modules, File}; WriteError -> WriteError end; to_file(Key, File, JWEOther, JWKOther) when is_binary(File) orelse is_list(File) -> to_file(Key, File, jose_jwe:from(JWEOther), from(JWKOther)). to_key(List) when is_list(List) -> [to_key(Element) || Element <- List]; to_key(#jose_jwk{kty={Module, KTY}}) -> {#{ kty => Module }, Module:to_key(KTY)}; to_key(Other) -> to_key(from(Other)). to_map(List) when is_list(List) -> [to_map(Element) || Element <- List]; to_map(JWK=#jose_jwk{fields=Fields}) -> record_to_map(JWK, #{}, Fields); to_map(Other) -> to_map(from(Other)). to_map(Key, JWK=#jose_jwk{kty={Module, KTY}, fields=Fields}) -> to_map(Key, Module:key_encryptor(KTY, Fields, Key), JWK); to_map(Key, Other) -> to_map(Key, from(Other)). to_map(Key, JWE=#jose_jwe{}, JWK=#jose_jwk{}) -> {Modules0, JWKBinary} = to_binary(JWK), {Modules1, Encrypted} = jose_jwe:block_encrypt(Key, JWKBinary, JWE), {maps:merge(Modules0, Modules1), Encrypted}; to_map(Key, JWEOther, JWKOther) -> to_map(Key, jose_jwe:from(JWEOther), from(JWKOther)). to_oct(List) when is_list(List) -> [to_oct(Element) || Element <- List]; to_oct(#jose_jwk{kty={Module, KTY}}) -> {#{ kty => Module }, Module:to_oct(KTY)}; to_oct(Other) -> to_oct(from(Other)). to_oct(Key, JWK=#jose_jwk{kty={Module, KTY}, fields=Fields}) -> to_oct(Key, Module:key_encryptor(KTY, Fields, Key), JWK); to_oct(Key, Other) -> to_oct(Key, from(Other)). to_oct(Key, JWE=#jose_jwe{}, JWK=#jose_jwk{}) -> {Modules0, OCTBinary} = to_oct(JWK), {Modules1, EncryptedMap} = jose_jwe:block_encrypt(Key, OCTBinary, JWE), jose_jwe:compact({maps:merge(Modules0, Modules1), EncryptedMap}); to_oct(Key, JWEOther, JWKOther) -> to_oct(Key, jose_jwe:from(JWEOther), from(JWKOther)). to_oct_file(File, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_oct(JWK), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_oct_file(File, Other) when is_binary(File) orelse is_list(File) -> to_oct_file(File, from(Other)). to_oct_file(Key, File, JWK=#jose_jwk{kty={Module, KTY}, fields=Fields}) when is_binary(File) orelse is_list(File) -> to_oct_file(Key, File, Module:key_encryptor(KTY, Fields, Key), JWK); to_oct_file(Key, File, Other) when is_binary(File) orelse is_list(File) -> to_oct_file(Key, File, from(Other)). to_oct_file(Key, File, JWE=#jose_jwe{}, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, EncryptedBinary} = to_oct(Key, JWE, JWK), case file:write_file(File, EncryptedBinary) of ok -> {Modules, File}; WriteError -> WriteError end; to_oct_file(Key, File, JWEOther, JWKOther) when is_binary(File) orelse is_list(File) -> to_oct_file(Key, File, jose_jwe:from(JWEOther), from(JWKOther)). to_okp(List) when is_list(List) -> [to_okp(Element) || Element <- List]; to_okp(#jose_jwk{kty={Module, KTY}}) -> {#{ kty => Module }, Module:to_okp(KTY)}; to_okp(Other) -> to_okp(from(Other)). to_openssh_key(List) when is_list(List) -> [to_openssh_key(Element) || Element <- List]; to_openssh_key(#jose_jwk{kty={Module, KTY}, fields=Fields}) -> {#{ kty => Module }, Module:to_openssh_key(KTY, Fields)}; to_openssh_key(Other) -> to_openssh_key(from(Other)). to_openssh_key_file(File, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_openssh_key(JWK), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_openssh_key_file(File, Other) when is_binary(File) orelse is_list(File) -> to_openssh_key_file(File, from(Other)). to_pem(List) when is_list(List) -> [to_pem(Element) || Element <- List]; to_pem(#jose_jwk{kty={Module, KTY}}) -> {#{ kty => Module }, Module:to_pem(KTY)}; to_pem(Other) -> to_pem(from(Other)). to_pem(Key, #jose_jwk{kty={Module, KTY}}) -> {#{ kty => Module }, Module:to_pem(Key, KTY)}; to_pem(Key, Other) -> to_pem(Key, from(Other)). to_pem_file(File, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_pem(JWK), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_pem_file(File, Other) when is_binary(File) orelse is_list(File) -> to_pem_file(File, from(Other)). to_pem_file(Key, File, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_pem(Key, JWK), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_pem_file(Key, File, Other) when is_binary(File) orelse is_list(File) -> to_pem_file(Key, File, from(Other)). to_public(List) when is_list(List) -> [to_public(Element) || Element <- List]; to_public(JWK=#jose_jwk{}) -> from_map(to_public_map(JWK)); to_public(Other) -> to_public(from(Other)). to_public_file(File, JWK=#jose_jwk{}) when is_binary(File) orelse is_list(File) -> to_file(File, to_public(JWK)); to_public_file(File, Other) when is_binary(File) orelse is_list(File) -> to_public_file(File, from(Other)). to_public_key(List) when is_list(List) -> [to_public_key(Element) || Element <- List]; to_public_key(JWT=#jose_jwk{}) -> to_key(to_public(JWT)); to_public_key(Other) -> to_public_key(from(Other)). to_public_map(List) when is_list(List) -> [to_public_map(Element) || Element <- List]; to_public_map(#jose_jwk{kty={Module, KTY}, fields=Fields}) -> {#{ kty => Module }, Module:to_public_map(KTY, Fields)}; to_public_map(Other) -> to_public_map(from(Other)). to_thumbprint_map(List) when is_list(List) -> [to_thumbprint_map(Element) || Element <- List]; to_thumbprint_map(#jose_jwk{kty={Module, KTY}, fields=Fields}) -> {#{ kty => Module }, Module:to_thumbprint_map(KTY, Fields)}; to_thumbprint_map(Other) -> to_thumbprint_map(from(Other)). %%==================================================================== %% API functions %%==================================================================== block_decrypt(Encrypted, JWK=#jose_jwk{}) -> jose_jwe:block_decrypt(JWK, Encrypted); block_decrypt(Encrypted, Other) -> block_decrypt(Encrypted, from(Other)). block_encrypt(PlainText, JWK=#jose_jwk{}) -> block_encrypt(PlainText, block_encryptor(JWK), JWK); block_encrypt(PlainText, Other) -> block_encrypt(PlainText, from(Other)). block_encrypt(PlainText, JWE=#jose_jwe{}, JWK=#jose_jwk{}) -> jose_jwe:block_encrypt(JWK, PlainText, JWE); block_encrypt(PlainText, JWEOther, JWKOther) -> block_encrypt(PlainText, jose_jwe:from(JWEOther), from(JWKOther)). block_encryptor(List) when is_list(List) -> [block_encryptor(Element) || Element <- List]; block_encryptor(#jose_jwk{kty={Module, KTY}, fields=Fields}) -> Module:block_encryptor(KTY, Fields); block_encryptor(Other) -> block_encryptor(from(Other)). box_decrypt(Encrypted, VStaticSecretKey) -> box_decrypt_ecdh_es(Encrypted, VStaticSecretKey). %% @doc Generates an ephemeral private key based on receiver public key curve. box_encrypt(PlainText, VStaticPublicKey=#jose_jwk{}) -> box_encrypt_ecdh_es(PlainText, VStaticPublicKey). box_encrypt(PlainText, VStaticPublicKey, UEphemeralSecretKey) -> box_encrypt_ecdh_es(PlainText, VStaticPublicKey, UEphemeralSecretKey). box_encrypt(PlainText, JWE, VStaticPublicKey, UEphemeralSecretKey) -> box_encrypt_ecdh_es(PlainText, JWE, VStaticPublicKey, UEphemeralSecretKey). box_decrypt_ecdh_1pu(Encrypted, UStaticPublicKey=#jose_jwk{}, VStaticSecretKey=#jose_jwk{}) -> jose_jwe:block_decrypt({UStaticPublicKey, VStaticSecretKey}, Encrypted); box_decrypt_ecdh_1pu(Encrypted, UStaticPublicKey, VStaticSecretKey) -> box_decrypt_ecdh_1pu(Encrypted, from(UStaticPublicKey), from(VStaticSecretKey)). %% @doc Generates an ephemeral private key based on receiver public key curve. box_encrypt_ecdh_1pu(PlainText, VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}) -> UEphemeralSecretKey = generate_key(VStaticPublicKey), {box_encrypt_ecdh_1pu(PlainText, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey), UEphemeralSecretKey}; box_encrypt_ecdh_1pu(PlainText, VStaticPublicKey, UStaticSecretKey) -> box_encrypt_ecdh_1pu(PlainText, from(VStaticPublicKey), from(UStaticSecretKey)). box_encrypt_ecdh_1pu(PlainText, VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}) -> UEphemeralPublicKey0 = #jose_jwk{fields=Fields0} = to_public(UEphemeralSecretKey), Fields1 = maps:put(<<"epk">>, element(2, to_map(UEphemeralPublicKey0)), Fields0), Fields2 = case Fields1 of #{ <<"alg">> := _ } -> Fields1; _ -> maps:put(<<"alg">>, <<"ECDH-1PU">>, Fields1) end, UEphemeralPublicKey = UEphemeralPublicKey0#jose_jwk{fields=Fields2}, JWEFields = block_encryptor(UEphemeralPublicKey), box_encrypt_ecdh_1pu(PlainText, JWEFields, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey); box_encrypt_ecdh_1pu(PlainText, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey) -> box_encrypt_ecdh_1pu(PlainText, from(VStaticPublicKey), from(UStaticSecretKey), from(UEphemeralSecretKey)). box_encrypt_ecdh_1pu(PlainText, JWE=#jose_jwe{}, VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}) -> jose_jwe:block_encrypt({VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey}, PlainText, JWE); box_encrypt_ecdh_1pu(PlainText, {JWEModules, JWEMap=#{ <<"apu">> := _, <<"apv">> := _, <<"epk">> := _, <<"skid">> := _ }}, VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}) -> box_encrypt_ecdh_1pu(PlainText, jose_jwe:from({JWEModules, JWEMap}), VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey); box_encrypt_ecdh_1pu(PlainText, {JWEModules, JWEMap0}, VStaticPublicKey=#jose_jwk{}, UStaticSecretKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}) -> Keys = [<<"apu">>, <<"apv">>, <<"epk">>, <<"skid">>] -- maps:keys(JWEMap0), JWEMap1 = normalize_ecdh_1pu(Keys, JWEMap0, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey), box_encrypt_ecdh_1pu(PlainText, {JWEModules, JWEMap1}, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey); box_encrypt_ecdh_1pu(PlainText, JWEMap, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey) when is_map(JWEMap) -> box_encrypt_ecdh_1pu(PlainText, {#{}, JWEMap}, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey); box_encrypt_ecdh_1pu(PlainText, JWE, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey) -> box_encrypt_ecdh_1pu(PlainText, JWE, from(VStaticPublicKey), from(UStaticSecretKey), from(UEphemeralSecretKey)). box_decrypt_ecdh_es(Encrypted, VStaticSecretKey=#jose_jwk{}) -> jose_jwe:block_decrypt(VStaticSecretKey, Encrypted); box_decrypt_ecdh_es(Encrypted, VStaticSecretKey) -> box_decrypt_ecdh_es(Encrypted, from(VStaticSecretKey)). %% @doc Generates an ephemeral private key based on receiver public key curve. box_encrypt_ecdh_es(PlainText, VStaticPublicKey=#jose_jwk{}) -> UEphemeralSecretKey = generate_key(VStaticPublicKey), {box_encrypt_ecdh_es(PlainText, VStaticPublicKey, UEphemeralSecretKey), UEphemeralSecretKey}; box_encrypt_ecdh_es(PlainText, VStaticPublicKey) -> box_encrypt_ecdh_es(PlainText, from(VStaticPublicKey)). box_encrypt_ecdh_es(PlainText, VStaticPublicKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}) -> UEphemeralPublicKey0 = #jose_jwk{fields=Fields0} = to_public(UEphemeralSecretKey), Fields1 = maps:put(<<"epk">>, element(2, to_map(UEphemeralPublicKey0)), Fields0), UEphemeralPublicKey = UEphemeralPublicKey0#jose_jwk{fields=Fields1}, JWEFields = block_encryptor(UEphemeralPublicKey), box_encrypt_ecdh_es(PlainText, JWEFields, VStaticPublicKey, UEphemeralSecretKey); box_encrypt_ecdh_es(PlainText, VStaticPublicKey, UEphemeralSecretKey) -> box_encrypt_ecdh_es(PlainText, from(VStaticPublicKey), from(UEphemeralSecretKey)). box_encrypt_ecdh_es(PlainText, JWE=#jose_jwe{}, VStaticPublicKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}) -> jose_jwe:block_encrypt({VStaticPublicKey, UEphemeralSecretKey}, PlainText, JWE); box_encrypt_ecdh_es(PlainText, {JWEModules, JWEMap=#{ <<"apu">> := _, <<"apv">> := _, <<"epk">> := _ }}, VStaticPublicKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}) -> box_encrypt_ecdh_es(PlainText, jose_jwe:from({JWEModules, JWEMap}), VStaticPublicKey, UEphemeralSecretKey); box_encrypt_ecdh_es(PlainText, {JWEModules, JWEMap0}, VStaticPublicKey=#jose_jwk{}, UEphemeralSecretKey=#jose_jwk{}) -> Keys = [<<"apu">>, <<"apv">>, <<"epk">>] -- maps:keys(JWEMap0), JWEMap1 = normalize_ecdh_es(Keys, JWEMap0, VStaticPublicKey, UEphemeralSecretKey), box_encrypt_ecdh_es(PlainText, {JWEModules, JWEMap1}, VStaticPublicKey, UEphemeralSecretKey); box_encrypt_ecdh_es(PlainText, JWEMap, VStaticPublicKey, UEphemeralSecretKey) when is_map(JWEMap) -> box_encrypt_ecdh_es(PlainText, {#{}, JWEMap}, VStaticPublicKey, UEphemeralSecretKey); box_encrypt_ecdh_es(PlainText, JWE, VStaticPublicKey, UEphemeralSecretKey) -> box_encrypt_ecdh_es(PlainText, JWE, from(VStaticPublicKey), from(UEphemeralSecretKey)). generate_key(#jose_jwk{kty={Module, KTY}, fields=Fields}) -> {NewKTY, NewFields} = Module:generate_key(KTY, Fields), #jose_jwk{kty={Module, NewKTY}, fields=NewFields}; generate_key({#{ kty := Module }, Parameters}) -> {KTY, Fields} = Module:generate_key(Parameters), #jose_jwk{kty={Module, KTY}, fields=Fields}; generate_key(Parameters) -> jose_jwk_kty:generate_key(Parameters). merge(LeftJWK=#jose_jwk{}, RightMap) when is_map(RightMap) -> {Modules, LeftMap} = to_map(LeftJWK), from_map({Modules, maps:merge(LeftMap, RightMap)}); merge(LeftOther, RightJWK=#jose_jwk{}) -> merge(LeftOther, element(2, to_map(RightJWK))); merge(LeftOther, RightMap) when is_map(RightMap) -> merge(from(LeftOther), RightMap). shared_secret(#jose_jwk{kty={Module, YourKTY}}, #jose_jwk{kty={Module, MyKTY}}) -> Module:derive_key(YourKTY, MyKTY); shared_secret(YourJWK, MyJWK) -> shared_secret(from(YourJWK), from(MyJWK)). sign(PlainText, JWK=#jose_jwk{}) -> sign(PlainText, signer(JWK), JWK); sign(PlainText, KeyList) when is_list(KeyList) -> Folder = fun Folder(Key=#jose_jwk{}, {Signers, Keys}) -> Signer = signer(Key), {[Signer | Signers], [Key | Keys]}; Folder(Other, Acc) -> Folder(from(Other), Acc) end, {Signers, Keys} = lists:foldr(Folder, {[], []}, KeyList), sign(PlainText, Signers, Keys); sign(PlainText, Other) -> sign(PlainText, from(Other)). sign(PlainText, JWS=#jose_jws{}, JWK=#jose_jwk{}) -> jose_jws:sign(JWK, PlainText, JWS); sign(PlainText, SignerList, KeyList) when is_list(SignerList) andalso is_list(KeyList) andalso length(SignerList) =:= length(KeyList) -> Signers = jose_jws:from(SignerList), Keys = from(KeyList), jose_jws:sign(Keys, PlainText, Signers); sign(PlainText, JWS=#jose_jws{}, KeyList) when is_list(KeyList) -> jose_jws:sign(from(KeyList), PlainText, JWS); sign(PlainText, SignerList, KeyList) when is_list(SignerList) andalso is_list(KeyList) andalso length(SignerList) =/= length(KeyList) -> erlang:error({badarg, [PlainText, SignerList, KeyList]}); sign(PlainText, JWSOther, KeyList) when is_list(KeyList) -> sign(PlainText, jose_jws:from(JWSOther), KeyList); sign(PlainText, JWSOther, JWKOther) -> sign(PlainText, jose_jws:from(JWSOther), from(JWKOther)). signer(List) when is_list(List) -> [signer(Element) || Element <- List]; signer(#jose_jwk{kty={Module, KTY}, fields=Fields}) -> Module:signer(KTY, Fields); signer(Other) -> signer(from(Other)). %% See https://tools.ietf.org/html/rfc7638 thumbprint(List) when is_list(List) -> [thumbprint(Element) || Element <- List]; thumbprint(JWK=#jose_jwk{}) -> thumbprint(sha256, JWK); thumbprint(Other) -> thumbprint(from(Other)). thumbprint(DigestType, List) when is_list(List) -> [thumbprint(DigestType, Element) || Element <- List]; thumbprint(DigestType, JWK=#jose_jwk{}) -> {_, ThumbprintMap} = to_thumbprint_map(JWK), ThumbprintBinary = jose:encode(ThumbprintMap), jose_jwa_base64url:encode(crypto:hash(DigestType, ThumbprintBinary)); thumbprint(DigestType, Other) -> thumbprint(DigestType, from(Other)). thumbprint_concat(List) when is_list(List) -> thumbprint_concat(sha256, List). thumbprint_concat(DigestType, List) when is_list(List) -> jose_jwa_base64url:encode(crypto:hash(DigestType, do_thumbprint_concat(List))). verifier(List) when is_list(List) -> [verifier(Element) || Element <- List]; verifier(#jose_jwk{kty={Module, KTY}, fields=Fields}) -> Module:verifier(KTY, Fields); verifier(Other) -> verifier(from(Other)). verify(Signed, JWK=#jose_jwk{}) -> jose_jws:verify(JWK, Signed); verify(Signed, Other) -> verify(Signed, from(Other)). verify_strict(Signed, Allow, JWK=#jose_jwk{}) -> jose_jws:verify_strict(JWK, Allow, Signed); verify_strict(Signed, Allow, Other) -> verify_strict(Signed, Allow, from(Other)). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private do_thumbprint_concat([]) -> []; do_thumbprint_concat([H | T]) -> {_, ThumbprintMap} = to_thumbprint_map(H), ThumbprintBinary = jose:encode(ThumbprintMap), [ThumbprintBinary | do_thumbprint_concat(T)]. %% @private normalize_ecdh_1pu([<<"apu">> | Keys], Map, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey) -> APU = thumbprint_concat([UStaticSecretKey, UEphemeralSecretKey]), normalize_ecdh_1pu(Keys, Map#{ <<"apu">> => APU }, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey); normalize_ecdh_1pu([<<"apv">> | Keys], Map, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey) -> APV = thumbprint(VStaticPublicKey), normalize_ecdh_1pu(Keys, Map#{ <<"apv">> => APV }, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey); normalize_ecdh_1pu([<<"epk">> | Keys], Map, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey) -> {_, UEphemeralPublicKeyMap} = to_public_map(UEphemeralSecretKey), normalize_ecdh_1pu(Keys, Map#{ <<"epk">> => UEphemeralPublicKeyMap }, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey); normalize_ecdh_1pu([<<"skid">> | Keys], Map, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey) -> SenderKeyId = case UStaticSecretKey of #jose_jwk{fields=#{ <<"kid">> := KID }} -> KID; _ -> thumbprint(UStaticSecretKey) end, normalize_ecdh_1pu(Keys, Map#{ <<"skid">> => SenderKeyId }, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey); normalize_ecdh_1pu([], Map, _, _, _) -> Map. %% @private normalize_ecdh_es([<<"apu">> | Keys], Map, VStaticPublicKey, UEphemeralSecretKey=#jose_jwk{fields=#{ <<"kid">> := KID }}) -> normalize_ecdh_es(Keys, Map#{ <<"apu">> => KID }, VStaticPublicKey, UEphemeralSecretKey); normalize_ecdh_es([<<"apu">> | Keys], Map, VStaticPublicKey, UEphemeralSecretKey) -> normalize_ecdh_es(Keys, Map#{ <<"apu">> => thumbprint(UEphemeralSecretKey) }, VStaticPublicKey, UEphemeralSecretKey); normalize_ecdh_es([<<"apv">> | Keys], Map, VStaticPublicKey=#jose_jwk{fields=#{ <<"kid">> := KID }}, UEphemeralSecretKey) -> normalize_ecdh_es(Keys, Map#{ <<"apv">> => KID }, VStaticPublicKey, UEphemeralSecretKey); normalize_ecdh_es([<<"apv">> | Keys], Map, VStaticPublicKey, UEphemeralSecretKey) -> normalize_ecdh_es(Keys, Map#{ <<"apv">> => thumbprint(VStaticPublicKey) }, VStaticPublicKey, UEphemeralSecretKey); normalize_ecdh_es([<<"epk">> | Keys], Map, VStaticPublicKey, UEphemeralSecretKey) -> {_, UEphemeralPublicKeyMap} = to_public_map(UEphemeralSecretKey), normalize_ecdh_es(Keys, Map#{ <<"epk">> => UEphemeralPublicKeyMap }, VStaticPublicKey, UEphemeralSecretKey); normalize_ecdh_es([], Map, _, _) -> Map. %% @private record_to_map(JWK=#jose_jwk{keys={Module, KEYS}}, Modules, Fields0) -> Fields1 = Module:to_map(KEYS, Fields0), record_to_map(JWK#jose_jwk{keys=undefined}, Modules#{ keys => Module }, Fields1); record_to_map(JWK=#jose_jwk{kty={Module, KTY}}, Modules, Fields0) -> Fields1 = Module:to_map(KTY, Fields0), record_to_map(JWK#jose_jwk{kty=undefined}, Modules#{ kty => Module }, Fields1); record_to_map(_JWK, Modules, Fields) -> {Modules, Fields}. erlang-jose-1.10.1/src/jwk/jose_jwk_kty_okp_ed448.erl0000644000232200023220000002063713605433351022732 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 15 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_okp_ed448). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_use_sig). -include_lib("jose_public_key.hrl"). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_sig callbacks -export([sign/3]). -export([signer/2]). -export([verifier/2]). -export([verify/4]). %% API -export([from_der/1]). -export([from_der/2]). -export([from_key/1]). -export([from_okp/1]). -export([from_openssh_key/1]). -export([from_pem/1]). -export([from_pem/2]). -export([to_der/1]). -export([to_der/2]). -export([to_okp/1]). -export([to_openssh_key/2]). -export([to_pem/1]). -export([to_pem/2]). %% Macros -define(crv, <<"Ed448">>). -define(secretbytes, 57). -define(publickeybytes, 57). -define(secretkeybytes, 114). %% Types -type publickey() :: << _:456 >>. -type secretkey() :: << _:912 >>. -type key() :: publickey() | secretkey(). -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"d">> := D, <<"x">> := X }) -> << Secret:?secretbytes/binary >> = jose_jwa_base64url:decode(D), << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), SK = << Secret/binary, PK/binary >>, {SK, maps:without([<<"crv">>, <<"d">>, <<"kty">>, <<"x">>], F)}; from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"x">> := X }) -> << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), {PK, maps:without([<<"crv">>, <<"kty">>, <<"x">>], F)}. to_key(<< PublicKey:?publickeybytes/binary >>) -> #'jose_EdDSA448PublicKey'{ publicKey = PublicKey }; to_key(<< PrivateKey:?secretbytes/binary, PublicKey:?publickeybytes/binary >>) -> #'jose_EdDSA448PrivateKey'{ publicKey = #'jose_EdDSA448PublicKey'{ publicKey = PublicKey }, privateKey = PrivateKey }. to_map(PK = << _:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }; to_map(<< Secret:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"d">> => jose_jwa_base64url:encode(Secret), <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }. to_public_map(PK = << _:?publickeybytes/binary >>, F) -> to_map(PK, F); to_public_map(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> to_public_map(PK, F). to_thumbprint_map(K, F) -> maps:with([<<"crv">>, <<"kty">>, <<"x">>], to_public_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(Seed = << _:?secretbytes/binary >>) -> {_PK, SK} = jose_curve448:eddsa_keypair(Seed), {SK, #{}}; generate_key({okp, 'Ed448', Seed = << _:?secretbytes/binary >>}) -> generate_key(Seed); generate_key({okp, 'Ed448'}) -> {_PK, SK} = jose_curve448:eddsa_keypair(), {SK, #{}}. generate_key(KTY, Fields) when is_binary(KTY) andalso (byte_size(KTY) =:= ?publickeybytes orelse byte_size(KTY) =:= ?secretkeybytes) -> {NewKTY, OtherFields} = generate_key({okp, 'Ed448'}), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_sig callbacks %%==================================================================== sign(Message, ALG, SK = << _:?secretkeybytes/binary >>) when ALG =:= 'Ed448' orelse ALG =:= 'EdDSA' -> jose_curve448:ed448_sign(Message, SK). signer(<< _:?secretkeybytes/binary >>, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> #{ <<"alg">> => ALG }; signer(<< _:?secretkeybytes/binary >>, _Fields) -> #{ <<"alg">> => <<"EdDSA">> }. verifier(<< _:?publickeybytes/binary >>, #{ <<"alg">> := ALG, <<"use">> := <<"sig">> }) -> [ALG]; verifier(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, Fields) -> verifier(PK, Fields); verifier(<< _:?publickeybytes/binary >>, _Fields) -> [?crv, <<"EdDSA">>]. verify(Message, ALG, Signature, << _:?secretbytes/binary, PK:?publickeybytes/binary >>) when ALG =:= 'Ed448' orelse ALG =:= 'EdDSA' -> verify(Message, ALG, Signature, PK); verify(Message, ALG, Signature, PK = << _:?publickeybytes/binary >>) when ALG =:= 'Ed448' orelse ALG =:= 'EdDSA' -> jose_curve448:ed448_verify(Signature, Message, PK). %%==================================================================== %% API functions %%==================================================================== from_der(DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_der(Password, DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(Password, DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_key(#'jose_EdDSA448PrivateKey'{publicKey=#'jose_EdDSA448PublicKey'{publicKey=Public}, privateKey=Secret}) -> {<< Secret/binary, Public/binary >>, #{}}; from_key(#'jose_EdDSA448PublicKey'{publicKey=Public}) -> {Public, #{}}. from_okp({'Ed448', SK = << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>}) -> case jose_curve448:eddsa_secret_to_public(Secret) of PK -> {SK, #{}}; _ -> erlang:error(badarg) end; from_okp({'Ed448', PK = << _:?publickeybytes/binary >>}) -> {PK, #{}}. from_openssh_key({<<"ssh-ed448">>, _PK, SK, Comment}) -> {KTY, OtherFields} = from_okp({'Ed448', SK}), case Comment of <<>> -> {KTY, OtherFields}; _ -> {KTY, maps:merge(#{ <<"kid">> => Comment }, OtherFields)} end. from_pem(PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. from_pem(Password, PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(Password, PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. to_der(SK = << _:?secretkeybytes/binary >>) -> EdDSA448PrivateKey = to_key(SK), jose_public_key:der_encode('EdDSA448PrivateKey', EdDSA448PrivateKey); to_der(PK = << _:?publickeybytes/binary >>) -> EdDSA448PublicKey = to_key(PK), jose_public_key:der_encode('EdDSA448PublicKey', EdDSA448PublicKey). to_der(Password, SK = << _:?secretkeybytes/binary >>) -> EdDSA448PrivateKey = to_key(SK), jose_jwk_der:to_binary(Password, 'EdDSA448PrivateKey', EdDSA448PrivateKey); to_der(Password, PK = << _:?publickeybytes/binary >>) -> EdDSA448PublicKey = to_key(PK), jose_jwk_der:to_binary(Password, 'EdDSA448PublicKey', EdDSA448PublicKey). to_okp(SK = << _:?secretkeybytes/binary >>) -> {'Ed448', SK}; to_okp(PK = << _:?publickeybytes/binary >>) -> {'Ed448', PK}. to_openssh_key(SK = << _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> Comment = maps:get(<<"kid">>, F, <<>>), jose_jwk_openssh_key:to_binary([[{{<<"ssh-ed448">>, PK}, {<<"ssh-ed448">>, PK, SK, Comment}}]]). to_pem(SK = << _:?secretkeybytes/binary >>) -> EdDSA448PrivateKey = to_key(SK), PEMEntry = jose_public_key:pem_entry_encode('EdDSA448PrivateKey', EdDSA448PrivateKey), jose_public_key:pem_encode([PEMEntry]); to_pem(PK = << _:?publickeybytes/binary >>) -> EdDSA448PublicKey = to_key(PK), PEMEntry = jose_public_key:pem_entry_encode('EdDSA448PublicKey', EdDSA448PublicKey), jose_public_key:pem_encode([PEMEntry]). to_pem(Password, SK = << _:?secretkeybytes/binary >>) -> EdDSA448PrivateKey = to_key(SK), jose_jwk_pem:to_binary(Password, 'PrivateKeyInfo', EdDSA448PrivateKey); to_pem(Password, PK = << _:?publickeybytes/binary >>) -> EdDSA448PublicKey = to_key(PK), jose_jwk_pem:to_binary(Password, 'EdDSA448PublicKey', EdDSA448PublicKey). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jwk/jose_jwk_kty_okp_x448.erl0000644000232200023220000002103613605433351022603 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 15 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwk_kty_okp_x448). -behaviour(jose_jwk). -behaviour(jose_jwk_kty). -behaviour(jose_jwk_use_enc). -include_lib("jose_public_key.hrl"). %% jose_jwk callbacks -export([from_map/1]). -export([to_key/1]). -export([to_map/2]). -export([to_public_map/2]). -export([to_thumbprint_map/2]). %% jose_jwk_kty callbacks -export([generate_key/1]). -export([generate_key/2]). -export([key_encryptor/3]). %% jose_jwk_use_enc callbacks -export([block_encryptor/2]). -export([derive_key/2]). %% API -export([from_der/1]). -export([from_der/2]). -export([from_key/1]). -export([from_okp/1]). -export([from_openssh_key/1]). -export([from_pem/1]). -export([from_pem/2]). -export([to_der/1]). -export([to_der/2]). -export([to_okp/1]). -export([to_openssh_key/2]). -export([to_pem/1]). -export([to_pem/2]). %% Macros -define(crv, <<"X448">>). -define(secretbytes, 56). -define(publickeybytes, 56). -define(secretkeybytes, 112). %% Types -type publickey() :: << _:448 >>. -type secretkey() :: << _:896 >>. -type key() :: publickey() | secretkey(). -export_type([key/0]). %%==================================================================== %% jose_jwk callbacks %%==================================================================== from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"d">> := D, <<"x">> := X }) -> << Secret:?secretbytes/binary >> = jose_jwa_base64url:decode(D), << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), SK = << Secret/binary, PK/binary >>, {SK, maps:without([<<"crv">>, <<"d">>, <<"kty">>, <<"x">>], F)}; from_map(F = #{ <<"kty">> := <<"OKP">>, <<"crv">> := ?crv, <<"x">> := X }) -> << PK:?publickeybytes/binary >> = jose_jwa_base64url:decode(X), {PK, maps:without([<<"crv">>, <<"kty">>, <<"x">>], F)}. to_key(<< PublicKey:?publickeybytes/binary >>) -> #'jose_X448PublicKey'{ publicKey = PublicKey }; to_key(<< PrivateKey:?secretbytes/binary, PublicKey:?publickeybytes/binary >>) -> #'jose_X448PrivateKey'{ publicKey = #'jose_X448PublicKey'{ publicKey = PublicKey }, privateKey = PrivateKey }. to_map(PK = << _:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }; to_map(<< Secret:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> F#{ <<"crv">> => ?crv, <<"d">> => jose_jwa_base64url:encode(Secret), <<"kty">> => <<"OKP">>, <<"x">> => jose_jwa_base64url:encode(PK) }. to_public_map(PK = << _:?publickeybytes/binary >>, F) -> to_map(PK, F); to_public_map(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> to_public_map(PK, F). to_thumbprint_map(K, F) -> maps:with([<<"crv">>, <<"kty">>, <<"x">>], to_public_map(K, F)). %%==================================================================== %% jose_jwk_kty callbacks %%==================================================================== generate_key(Seed = << _:?secretbytes/binary >>) -> {PK, SK} = jose_curve448:x448_keypair(Seed), {<< SK/binary, PK/binary >>, #{}}; generate_key({okp, 'X448', Seed = << _:?secretbytes/binary >>}) -> generate_key(Seed); generate_key({okp, 'X448'}) -> {PK, SK} = jose_curve448:x448_keypair(), {<< SK/binary, PK/binary >>, #{}}. generate_key(KTY, Fields) when is_binary(KTY) andalso (byte_size(KTY) =:= ?publickeybytes orelse byte_size(KTY) =:= ?secretkeybytes) -> {NewKTY, OtherFields} = generate_key({okp, 'X448'}), {NewKTY, maps:merge(maps:remove(<<"kid">>, Fields), OtherFields)}. key_encryptor(KTY, Fields, Key) -> jose_jwk_kty:key_encryptor(KTY, Fields, Key). %%==================================================================== %% jose_jwk_use_enc callbacks %%==================================================================== block_encryptor(_KTY, Fields=#{ <<"alg">> := ALG, <<"enc">> := ENC, <<"use">> := <<"enc">> }) -> Folder = fun (K, V, F) when K =:= <<"apu">> orelse K =:= <<"apv">> orelse K =:= <<"epk">> orelse K =:= <<"skid">> -> maps:put(K, V, F); (_K, _V, F) -> F end, maps:fold(Folder, #{ <<"alg">> => ALG, <<"enc">> => ENC }, Fields); block_encryptor(KTY, Fields=#{ <<"alg">> := <<"ECDH-1PU", _/binary>> }) -> block_encryptor(KTY, maps:merge(Fields, #{ <<"enc">> => case jose_jwa:is_block_cipher_supported({aes_gcm, 128}) of false -> <<"A128CBC-HS256">>; true -> <<"A128GCM">> end, <<"use">> => <<"enc">> })); block_encryptor(KTY, Fields) -> block_encryptor(KTY, maps:merge(Fields, #{ <<"alg">> => <<"ECDH-ES">>, <<"enc">> => case jose_jwa:is_block_cipher_supported({aes_gcm, 128}) of false -> <<"A128CBC-HS256">>; true -> <<"A128GCM">> end, <<"use">> => <<"enc">> })). derive_key(<< _:?secretbytes/binary, PK:?publickeybytes/binary >>, SK = << _:?secretkeybytes/binary >>) -> derive_key(PK, SK); derive_key(PK = << _:?publickeybytes/binary >>, << Secret:?secretbytes/binary, _:?publickeybytes/binary >>) -> jose_curve448:x448_shared_secret(Secret, PK). %%==================================================================== %% API functions %%==================================================================== from_der(DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_der(Password, DERBinary) when is_binary(DERBinary) -> case jose_jwk_der:from_binary(Password, DERBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields} end. from_key(#'jose_X448PrivateKey'{publicKey=#'jose_X448PublicKey'{publicKey=Public}, privateKey=Secret}) -> {<< Secret/binary, Public/binary >>, #{}}; from_key(#'jose_X448PublicKey'{publicKey=Public}) -> {Public, #{}}. from_okp({'X448', SK = << Secret:?secretbytes/binary, PK:?publickeybytes/binary >>}) -> case jose_curve448:x448_secret_to_public(Secret) of PK -> {SK, #{}}; _ -> erlang:error(badarg) end; from_okp({'X448', PK = << _:?publickeybytes/binary >>}) -> {PK, #{}}. from_openssh_key({<<"ssh-x448">>, _PK, SK, Comment}) -> {KTY, OtherFields} = from_okp({'X448', SK}), case Comment of <<>> -> {KTY, OtherFields}; _ -> {KTY, maps:merge(#{ <<"kid">> => Comment }, OtherFields)} end. from_pem(PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. from_pem(Password, PEMBinary) when is_binary(PEMBinary) -> case jose_jwk_pem:from_binary(Password, PEMBinary) of {?MODULE, {Key, Fields}} -> {Key, Fields}; PEMError -> PEMError end. to_der(SK = << _:?secretkeybytes/binary >>) -> X448PrivateKey = to_key(SK), jose_public_key:der_encode('X448PrivateKey', X448PrivateKey); to_der(PK = << _:?publickeybytes/binary >>) -> X448PublicKey = to_key(PK), jose_public_key:der_encode('X448PublicKey', X448PublicKey). to_der(Password, SK = << _:?secretkeybytes/binary >>) -> X448PrivateKey = to_key(SK), jose_jwk_der:to_binary(Password, 'X448PrivateKey', X448PrivateKey); to_der(Password, PK = << _:?publickeybytes/binary >>) -> X448PublicKey = to_key(PK), jose_jwk_der:to_binary(Password, 'X448PublicKey', X448PublicKey). to_okp(SK = << _:?secretkeybytes/binary >>) -> {'X448', SK}; to_okp(PK = << _:?publickeybytes/binary >>) -> {'X448', PK}. to_openssh_key(SK = << _:?secretbytes/binary, PK:?publickeybytes/binary >>, F) -> Comment = maps:get(<<"kid">>, F, <<>>), jose_jwk_openssh_key:to_binary([[{{<<"ssh-x448">>, PK}, {<<"ssh-x448">>, PK, SK, Comment}}]]). to_pem(SK = << _:?secretkeybytes/binary >>) -> X448PrivateKey = to_key(SK), PEMEntry = jose_public_key:pem_entry_encode('X448PrivateKey', X448PrivateKey), jose_public_key:pem_encode([PEMEntry]); to_pem(PK = << _:?publickeybytes/binary >>) -> X448PublicKey = to_key(PK), PEMEntry = jose_public_key:pem_entry_encode('X448PublicKey', X448PublicKey), jose_public_key:pem_encode([PEMEntry]). to_pem(Password, SK = << _:?secretkeybytes/binary >>) -> X448PrivateKey = to_key(SK), jose_jwk_pem:to_binary(Password, 'PrivateKeyInfo', X448PrivateKey); to_pem(Password, PK = << _:?publickeybytes/binary >>) -> X448PublicKey = to_key(PK), jose_jwk_pem:to_binary(Password, 'X448PublicKey', X448PublicKey). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jws/0000755000232200023220000000000013605433351015743 5ustar debalancedebalanceerlang-jose-1.10.1/src/jws/jose_jws_alg_ecdsa.erl0000644000232200023220000000447413605433351022265 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws_alg_ecdsa). -behaviour(jose_jws). -behaviour(jose_jws_alg). -include("jose_jwk.hrl"). %% jose_jws callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jws_alg callbacks -export([generate_key/2]). -export([sign/3]). -export([verify/4]). %% API %% Types -type alg() :: 'ES256' | 'ES384' | 'ES512'. -export_type([alg/0]). %%==================================================================== %% jose_jws callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"ES256">> }) -> {'ES256', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"ES384">> }) -> {'ES384', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"ES512">> }) -> {'ES512', maps:remove(<<"alg">>, F)}. to_map('ES256', F) -> F#{ <<"alg">> => <<"ES256">> }; to_map('ES384', F) -> F#{ <<"alg">> => <<"ES384">> }; to_map('ES512', F) -> F#{ <<"alg">> => <<"ES512">> }. %%==================================================================== %% jose_jws_alg callbacks %%==================================================================== generate_key('ES256', _Fields) -> jose_jws_alg:generate_key({ec, <<"P-256">>}, <<"ES256">>); generate_key('ES384', _Fields) -> jose_jws_alg:generate_key({ec, <<"P-384">>}, <<"ES384">>); generate_key('ES512', _Fields) -> jose_jws_alg:generate_key({ec, <<"P-521">>}, <<"ES512">>). sign(#jose_jwk{kty={KTYModule, KTY}}, Message, ALG) -> KTYModule:sign(Message, ALG, KTY). verify(#jose_jwk{kty={KTYModule, KTY}}, Message, Signature, ALG) -> KTYModule:verify(Message, ALG, Signature, KTY). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jws/jose_jws_alg_rsa_pkcs1_v1_5.erl0000644000232200023220000000446313605433351023724 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws_alg_rsa_pkcs1_v1_5). -behaviour(jose_jws). -behaviour(jose_jws_alg). -include("jose_jwk.hrl"). %% jose_jws callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jws_alg callbacks -export([generate_key/2]). -export([sign/3]). -export([verify/4]). %% API %% Types -type alg() :: 'RS256' | 'RS384' | 'RS512'. -export_type([alg/0]). %%==================================================================== %% jose_jws callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"RS256">> }) -> {'RS256', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"RS384">> }) -> {'RS384', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"RS512">> }) -> {'RS512', maps:remove(<<"alg">>, F)}. to_map('RS256', F) -> F#{ <<"alg">> => <<"RS256">> }; to_map('RS384', F) -> F#{ <<"alg">> => <<"RS384">> }; to_map('RS512', F) -> F#{ <<"alg">> => <<"RS512">> }. %%==================================================================== %% jose_jws_alg callbacks %%==================================================================== generate_key('RS256', _Fields) -> jose_jws_alg:generate_key({rsa, 2048}, <<"RS256">>); generate_key('RS384', _Fields) -> jose_jws_alg:generate_key({rsa, 3072}, <<"RS384">>); generate_key('RS512', _Fields) -> jose_jws_alg:generate_key({rsa, 4096}, <<"RS512">>). sign(#jose_jwk{kty={KTYModule, KTY}}, Message, ALG) -> KTYModule:sign(Message, ALG, KTY). verify(#jose_jwk{kty={KTYModule, KTY}}, Message, Signature, ALG) -> KTYModule:verify(Message, ALG, Signature, KTY). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jws/jose_jws_alg_hmac.erl0000644000232200023220000000444213605433351022111 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws_alg_hmac). -behaviour(jose_jws). -behaviour(jose_jws_alg). -include("jose_jwk.hrl"). %% jose_jws callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jws_alg callbacks -export([generate_key/2]). -export([sign/3]). -export([verify/4]). %% API %% Types -type alg() :: 'HS256' | 'HS384' | 'HS512'. -export_type([alg/0]). %%==================================================================== %% jose_jws callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"HS256">> }) -> {'HS256', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"HS384">> }) -> {'HS384', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"HS512">> }) -> {'HS512', maps:remove(<<"alg">>, F)}. to_map('HS256', F) -> F#{ <<"alg">> => <<"HS256">> }; to_map('HS384', F) -> F#{ <<"alg">> => <<"HS384">> }; to_map('HS512', F) -> F#{ <<"alg">> => <<"HS512">> }. %%==================================================================== %% jose_jws_alg callbacks %%==================================================================== generate_key('HS256', _Fields) -> jose_jws_alg:generate_key({oct, 32}, <<"HS256">>); generate_key('HS384', _Fields) -> jose_jws_alg:generate_key({oct, 48}, <<"HS384">>); generate_key('HS512', _Fields) -> jose_jws_alg:generate_key({oct, 64}, <<"HS512">>). sign(#jose_jwk{kty={KTYModule, KTY}}, Message, ALG) -> KTYModule:sign(Message, ALG, KTY). verify(#jose_jwk{kty={KTYModule, KTY}}, Message, Signature, ALG) -> KTYModule:verify(Message, ALG, Signature, KTY). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jws/jose_jws_alg_eddsa.erl0000644000232200023220000000523313605433351022260 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 31 Dec 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws_alg_eddsa). -behaviour(jose_jws). -behaviour(jose_jws_alg). -include("jose_jwk.hrl"). %% jose_jws callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jws_alg callbacks -export([generate_key/2]). -export([sign/3]). -export([verify/4]). %% Types -type alg() :: 'Ed25519' | 'Ed25519ph' | 'Ed448' | 'Ed448ph' | 'EdDSA'. -export_type([alg/0]). %%==================================================================== %% jose_jws callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"Ed25519">> }) -> {'Ed25519', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"Ed25519ph">> }) -> {'Ed25519ph', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"Ed448">> }) -> {'Ed448', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"Ed448ph">> }) -> {'Ed448ph', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"EdDSA">> }) -> {'EdDSA', maps:remove(<<"alg">>, F)}. to_map('Ed25519', F) -> F#{ <<"alg">> => <<"Ed25519">> }; to_map('Ed25519ph', F) -> F#{ <<"alg">> => <<"Ed25519ph">> }; to_map('Ed448', F) -> F#{ <<"alg">> => <<"Ed448">> }; to_map('Ed448ph', F) -> F#{ <<"alg">> => <<"Ed448ph">> }; to_map('EdDSA', F) -> F#{ <<"alg">> => <<"EdDSA">> }. %%==================================================================== %% jose_jws_alg callbacks %%==================================================================== generate_key(ALG, _Fields) when ALG =:= 'Ed25519' orelse ALG =:= 'Ed25519ph' orelse ALG =:= 'Ed448' orelse ALG =:= 'Ed448ph' -> jose_jws_alg:generate_key({okp, ALG}, atom_to_binary(ALG, unicode)); generate_key('EdDSA', _Fields) -> jose_jws_alg:generate_key({okp, 'Ed25519'}, <<"EdDSA">>). sign(#jose_jwk{kty={KTYModule, KTY}}, Message, ALG) -> KTYModule:sign(Message, ALG, KTY). verify(#jose_jwk{kty={KTYModule, KTY}}, Message, Signature, ALG) -> KTYModule:verify(Message, ALG, Signature, KTY). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jws/jose_jws.erl0000644000232200023220000004530213605433351020276 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc JSON Web Signature (JWS) %%% See RFC 7515: https://tools.ietf.org/html/rfc7515 %%% See RFC 7797: https://tools.ietf.org/html/rfc7797 %%% @end %%% Created : 21 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws). -include("jose_jwk.hrl"). -include("jose_jws.hrl"). -callback from_map(Fields) -> State when Fields :: map(), State :: any(). -callback to_map(State, Fields) -> Map when State :: any(), Fields :: map(), Map :: map(). %% Decode API -export([from/1]). -export([from_binary/1]). -export([from_file/1]). -export([from_map/1]). %% Encode API -export([to_binary/1]). -export([to_file/2]). -export([to_map/1]). %% API -export([compact/1]). -export([expand/1]). -export([generate_key/1]). -export([merge/2]). -export([peek/1]). -export([peek_payload/1]). -export([peek_protected/1]). -export([peek_signature/1]). -export([sign/3]). -export([sign/4]). -export([signing_input/2]). -export([signing_input/3]). -export([verify/2]). -export([verify_strict/3]). -define(ALG_ECDSA_MODULE, jose_jws_alg_ecdsa). -define(ALG_EDDSA_MODULE, jose_jws_alg_eddsa). -define(ALG_HMAC_MODULE, jose_jws_alg_hmac). -define(ALG_NONE_MODULE, jose_jws_alg_none). -define(ALG_POLY1305_MODULE, jose_jws_alg_poly1305). -define(ALG_RSA_PKCS1_V1_5_MODULE, jose_jws_alg_rsa_pkcs1_v1_5). -define(ALG_RSA_PSS_MODULE, jose_jws_alg_rsa_pss). %%==================================================================== %% Decode API functions %%==================================================================== from(List) when is_list(List) -> [from(Element) || Element <- List]; from({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> from_map({Modules, Map}); from({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> from_binary({Modules, Binary}); from(JWS=#jose_jws{}) -> JWS; from(Other) when is_map(Other) orelse is_binary(Other) -> from({#{}, Other}). from_binary(List) when is_list(List) -> [from_binary(Element) || Element <- List]; from_binary({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> from_map({Modules, jose:decode(Binary)}); from_binary(Binary) when is_binary(Binary) -> from_binary({#{}, Binary}). from_file({Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_binary({Modules, Binary}); ReadError -> ReadError end; from_file(File) when is_binary(File) orelse is_list(File) -> from_file({#{}, File}). from_map(List) when is_list(List) -> [from_map(Element) || Element <- List]; from_map(Map) when is_map(Map) -> from_map({#{}, Map}); from_map({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> from_map({#jose_jws{}, Modules, Map}); from_map({JWS, Modules = #{ alg := Module }, Map=#{ <<"alg">> := _ }}) -> {ALG, Fields} = Module:from_map(Map), from_map({JWS#jose_jws{ alg = {Module, ALG} }, maps:remove(alg, Modules), Fields}); from_map({JWS, Modules, Map=#{ <<"b64">> := B64 }}) -> from_map({JWS#jose_jws{ b64 = B64 }, Modules, maps:remove(<<"b64">>, Map)}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "Ed25519", _/binary >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_EDDSA_MODULE }, Map}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "Ed448", _/binary >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_EDDSA_MODULE }, Map}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "EdDSA", _/binary >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_EDDSA_MODULE }, Map}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "ES", _/binary >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_ECDSA_MODULE }, Map}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "HS", _/binary >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_HMAC_MODULE }, Map}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "Poly1305" >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_POLY1305_MODULE }, Map}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "PS", _/binary >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_RSA_PSS_MODULE }, Map}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "RS", _/binary >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_RSA_PKCS1_V1_5_MODULE }, Map}); from_map({JWS, Modules, Map=#{ <<"alg">> := << "none" >> }}) -> from_map({JWS, Modules#{ alg => ?ALG_NONE_MODULE }, Map}); from_map({#jose_jws{ alg = undefined }, _Modules, _Map}) -> {error, {missing_required_keys, [<<"alg">>]}}; from_map({JWS, _Modules, Fields}) -> JWS#jose_jws{ fields = Fields }. %%==================================================================== %% Encode API functions %%==================================================================== to_binary(List) when is_list(List) -> [to_binary(Element) || Element <- List]; to_binary(JWS=#jose_jws{}) -> {Modules, Map} = to_map(JWS), {Modules, jose:encode(Map)}; to_binary(Other) -> to_binary(from(Other)). to_file(File, JWS=#jose_jws{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_binary(JWS), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_file(File, Other) when is_binary(File) orelse is_list(File) -> to_file(File, from(Other)). to_map(List) when is_list(List) -> [to_map(Element) || Element <- List]; to_map(JWS=#jose_jws{fields=Fields}) -> record_to_map(JWS, #{}, Fields); to_map(Other) -> to_map(from(Other)). %%==================================================================== %% API functions %%==================================================================== compact({Modules, #{ <<"payload">> := Payload, <<"signatures">> := Signatures }}) when is_list(Signatures) -> {Modules, [do_compact(Map#{ <<"payload">> => Payload }) || Map <- Signatures]}; compact({Modules, Map}) when is_map(Map) -> {Modules, do_compact(Map)}; compact({Modules, List}) when is_list(List) -> {Modules, [do_compact(Map) || Map <- List]}; compact(Map) when is_map(Map) -> compact({#{}, Map}); compact(List) when is_list(List) -> compact({#{}, List}); compact(BadArg) -> erlang:error({badarg, [BadArg]}). expand({Modules, Binary}) when is_binary(Binary) -> {Modules, do_expand(Binary)}; expand({Modules, List}) when is_list(List) -> Expanded = [do_expand(Binary) || Binary <- List], Eligible = lists:foldl(fun (_, false) -> false; (#{ <<"payload">> := Payload }, undefined) when is_binary(Payload) -> Payload; (#{ <<"payload">> := Payload }, Payload) when is_binary(Payload) -> Payload; (_, _) -> false end, undefined, Expanded), case Eligible of _ when Eligible =:= false orelse Eligible =:= undefined -> {Modules, Expanded}; Payload -> Signatures = [maps:remove(<<"payload">>, Map) || Map <- Expanded], {Modules, #{ <<"payload">> => Payload, <<"signatures">> => Signatures }} end; expand(Binary) when is_binary(Binary) -> expand({#{}, Binary}); expand(List) when is_list(List) -> expand({#{}, List}). generate_key(List) when is_list(List) -> [generate_key(Element) || Element <- List]; generate_key(#jose_jws{alg={Module, ALG}, fields=Fields}) -> Module:generate_key(ALG, Fields); generate_key(Other) -> generate_key(from(Other)). merge(LeftJWS=#jose_jws{}, RightMap) when is_map(RightMap) -> {Modules, LeftMap} = to_map(LeftJWS), from_map({Modules, maps:merge(LeftMap, RightMap)}); merge(LeftOther, RightJWS=#jose_jws{}) -> merge(LeftOther, element(2, to_map(RightJWS))); merge(LeftOther, RightMap) when is_map(RightMap) -> merge(from(LeftOther), RightMap). peek(Signed) -> peek_payload(Signed). peek_payload({_Modules, Signed}) when is_binary(Signed) or is_map(Signed) -> peek_payload(Signed); peek_payload(SignedBinary) when is_binary(SignedBinary) -> peek_payload(expand(SignedBinary)); peek_payload(#{ <<"payload">> := Payload }) -> jose_jwa_base64url:decode(Payload). peek_protected({_Modules, Signed}) when is_binary(Signed) or is_map(Signed) -> peek_protected(Signed); peek_protected(SignedBinary) when is_binary(SignedBinary) -> peek_protected(expand(SignedBinary)); peek_protected(#{ <<"protected">> := Protected }) -> jose_jwa_base64url:decode(Protected). peek_signature({_Modules, Signed}) when is_binary(Signed) or is_map(Signed) -> peek_signature(Signed); peek_signature(SignedBinary) when is_binary(SignedBinary) -> peek_signature(expand(SignedBinary)); peek_signature(#{ <<"signature">> := Signature }) -> jose_jwa_base64url:decode(Signature). sign(KeyList, PlainText, SignerList) when is_list(KeyList) andalso is_list(SignerList) andalso length(KeyList) =:= length(SignerList) -> HeaderList = [#{} || _ <- SignerList], sign(KeyList, PlainText, HeaderList, SignerList); sign(KeyList, PlainText, SignerList) when is_list(KeyList) andalso is_list(SignerList) andalso length(KeyList) =/= length(SignerList) -> erlang:error({badarg, [KeyList, PlainText, SignerList]}); sign(KeyOrKeyList, PlainText, JWS=#jose_jws{}) -> sign(KeyOrKeyList, PlainText, #{}, JWS); sign(KeyOrKeyList, PlainText, Other) -> sign(KeyOrKeyList, PlainText, from(Other)). sign(KeyList, PlainText, Header, Signer=#jose_jws{}) when is_list(KeyList) andalso is_binary(PlainText) andalso is_map(Header) -> HeaderList = [Header || _ <- KeyList], SignerList = [Signer || _ <- KeyList], sign(KeyList, PlainText, HeaderList, SignerList); sign(KeyList, PlainText, Header, SignerList) when is_list(KeyList) andalso is_binary(PlainText) andalso is_map(Header) andalso is_list(SignerList) andalso length(KeyList) =:= length(SignerList) -> HeaderList = [Header || _ <- KeyList], sign(KeyList, PlainText, HeaderList, SignerList); sign(KeyList, PlainText, HeaderList, Signer=#jose_jws{}) when is_list(KeyList) andalso is_binary(PlainText) andalso is_list(HeaderList) andalso length(KeyList) =:= length(HeaderList) -> SignerList = [Signer || _ <- KeyList], sign(KeyList, PlainText, HeaderList, SignerList); sign(KeyList, PlainText, HeaderList, SignerList) when is_list(KeyList) andalso is_binary(PlainText) andalso is_list(HeaderList) andalso is_list(SignerList) andalso length(KeyList) =:= length(SignerList) andalso length(KeyList) =:= length(HeaderList) -> Keys = jose_jwk:from(KeyList), Signers = from(SignerList), Payload = jose_jwa_base64url:encode(PlainText), Signatures = map_signatures(Keys, PlainText, HeaderList, Signers, []), {#{}, #{ <<"payload">> => Payload, <<"signatures">> => Signatures }}; sign(Key=#jose_jwk{}, PlainText, Header, JWS=#jose_jws{alg={ALGModule, ALG}}) when is_binary(PlainText) andalso is_map(Header) -> _ = code:ensure_loaded(ALGModule), NewALG = case erlang:function_exported(ALGModule, presign, 2) of false -> ALG; true -> ALGModule:presign(Key, ALG) end, NewJWS = JWS#jose_jws{alg={ALGModule, NewALG}}, {Modules, ProtectedBinary} = to_binary(NewJWS), Protected = jose_jwa_base64url:encode(ProtectedBinary), Payload = jose_jwa_base64url:encode(PlainText), SigningInput = signing_input(PlainText, Protected, NewJWS), Signature = jose_jwa_base64url:encode(ALGModule:sign(Key, SigningInput, NewALG)), {Modules, maps:put(<<"payload">>, Payload, signature_to_map(Protected, Header, Key, Signature))}; sign(Key=none, PlainText, Header, JWS=#jose_jws{alg={ALGModule, ALG}}) when is_binary(PlainText) andalso is_map(Header) -> _ = code:ensure_loaded(ALGModule), NewALG = case erlang:function_exported(ALGModule, presign, 2) of false -> ALG; true -> ALGModule:presign(Key, ALG) end, NewJWS = JWS#jose_jws{alg={ALGModule, NewALG}}, {Modules, ProtectedBinary} = to_binary(NewJWS), Protected = jose_jwa_base64url:encode(ProtectedBinary), Payload = jose_jwa_base64url:encode(PlainText), SigningInput = signing_input(PlainText, Protected, NewJWS), Signature = jose_jwa_base64url:encode(ALGModule:sign(Key, SigningInput, NewALG)), {Modules, maps:put(<<"payload">>, Payload, signature_to_map(Protected, Header, Key, Signature))}; sign(KeyList, PlainText, HeaderList, SignerList) when (is_list(KeyList) andalso is_list(HeaderList) andalso length(KeyList) =/= length(HeaderList)) orelse (is_list(KeyList) andalso is_list(SignerList) andalso length(KeyList) =/= length(SignerList)) orelse (is_list(HeaderList) andalso is_list(SignerList) andalso length(HeaderList) =/= length(SignerList)) orelse (is_list(HeaderList) andalso not is_list(KeyList) andalso not is_list(SignerList)) -> erlang:error({badarg, [KeyList, PlainText, HeaderList, SignerList]}); sign(KeyOrKeyList, PlainText, Header, Other) when is_binary(PlainText) andalso is_map(Header) -> sign(jose_jwk:from(KeyOrKeyList), PlainText, Header, from(Other)). %% See https://tools.ietf.org/html/rfc7797 signing_input(Payload, JWS=#jose_jws{}) -> {_, ProtectedBinary} = to_binary(JWS), Protected = jose_jwa_base64url:encode(ProtectedBinary), signing_input(Payload, Protected, JWS); signing_input(Payload, Other) -> signing_input(Payload, from(Other)). signing_input(PlainText, Protected, #jose_jws{b64=B64}) when (B64 =:= true orelse B64 =:= undefined) -> Payload = jose_jwa_base64url:encode(PlainText), << Protected/binary, $., Payload/binary >>; signing_input(Payload, Protected, #jose_jws{b64=false}) -> << Protected/binary, $., Payload/binary >>. verify(Key, SignedMap) when is_map(SignedMap) -> verify(Key, {#{}, SignedMap}); verify(Key, SignedBinary) when is_binary(SignedBinary) -> verify(Key, expand(SignedBinary)); verify(Key, {Modules, SignedBinary}) when is_binary(SignedBinary) -> verify(Key, expand({Modules, SignedBinary})); verify(Key, {Modules, #{ <<"payload">> := Payload, <<"protected">> := Protected, <<"signature">> := EncodedSignature}}) -> JWS = #jose_jws{alg={ALGModule, ALG}} = from_binary({Modules, jose_jwa_base64url:decode(Protected)}), Signature = jose_jwa_base64url:decode(EncodedSignature), PlainText = jose_jwa_base64url:decode(Payload), SigningInput = signing_input(PlainText, Protected, JWS), {ALGModule:verify(Key, SigningInput, Signature, ALG), PlainText, JWS}; verify(Keys = [_ | _], {Modules, Signed=#{ <<"payload">> := _Payload, <<"signatures">> := EncodedSignatures}}) when is_list(EncodedSignatures) -> [begin {Key, verify(Key, {Modules, Signed})} end || Key <- Keys]; verify(Key, {Modules, #{ <<"payload">> := Payload, <<"signatures">> := EncodedSignatures}}) when is_list(EncodedSignatures) -> [begin verify(Key, {Modules, maps:put(<<"payload">>, Payload, EncodedSignature)}) end || EncodedSignature <- EncodedSignatures]. verify_strict(Key, Allow, SignedMap) when is_map(SignedMap) -> verify_strict(Key, Allow, {#{}, SignedMap}); verify_strict(Key, Allow, SignedBinary) when is_binary(SignedBinary) -> verify_strict(Key, Allow, expand(SignedBinary)); verify_strict(Key, Allow, {Modules, SignedBinary}) when is_binary(SignedBinary) -> verify_strict(Key, Allow, expand({Modules, SignedBinary})); verify_strict(Key, Allow, {Modules, #{ <<"payload">> := Payload, <<"protected">> := Protected, <<"signature">> := EncodedSignature}}) -> ProtectedMap = jose:decode(jose_jwa_base64url:decode(Protected)), Signature = jose_jwa_base64url:decode(EncodedSignature), PlainText = jose_jwa_base64url:decode(Payload), case ProtectedMap of #{ <<"alg">> := Algorithm } -> case lists:member(Algorithm, Allow) of false -> {false, PlainText, ProtectedMap}; true -> JWS = #jose_jws{alg={ALGModule, ALG}} = from_map({Modules, ProtectedMap}), SigningInput = signing_input(PlainText, Protected, JWS), {ALGModule:verify(Key, SigningInput, Signature, ALG), PlainText, JWS} end; _ -> {false, PlainText, ProtectedMap} end; verify_strict(Keys = [_ | _], Allow, {Modules, Signed=#{ <<"payload">> := _Payload, <<"signatures">> := EncodedSignatures}}) when is_list(EncodedSignatures) -> [begin {Key, verify_strict(Key, Allow, {Modules, Signed})} end || Key <- Keys]; verify_strict(Key, Allow, {Modules, #{ <<"payload">> := Payload, <<"signatures">> := EncodedSignatures}}) when is_list(EncodedSignatures) -> [begin verify_strict(Key, Allow, {Modules, maps:put(<<"payload">>, Payload, EncodedSignature)}) end || EncodedSignature <- EncodedSignatures]. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private do_compact(#{ <<"payload">> := Payload, <<"protected">> := Protected, <<"signature">> := Signature}) -> << Protected/binary, $., Payload/binary, $., Signature/binary >>; do_compact(BadArg) -> erlang:error({badarg, [BadArg]}). %% @private do_expand(Binary) when is_binary(Binary) -> case binary:split(Binary, <<".">>, [global]) of [Protected, Payload, Signature] -> #{ <<"payload">> => Payload, <<"protected">> => Protected, <<"signature">> => Signature }; _ -> erlang:error({badarg, [Binary]}) end; do_expand(BadArg) -> erlang:error({badarg, [BadArg]}). %% @private map_signatures([Key | Keys], PlainText, [Header | Headers], [Signer=#jose_jws{alg={ALGModule, ALG}} | Signers], Acc) -> _ = code:ensure_loaded(ALGModule), NewALG = case erlang:function_exported(ALGModule, presign, 2) of false -> ALG; true -> ALGModule:presign(Key, ALG) end, NewSigner = Signer#jose_jws{alg={ALGModule, NewALG}}, {_Modules, ProtectedBinary} = to_binary(NewSigner), Protected = jose_jwa_base64url:encode(ProtectedBinary), SigningInput = signing_input(PlainText, Protected, NewSigner), Signature = jose_jwa_base64url:encode(ALGModule:sign(Key, SigningInput, NewALG)), map_signatures(Keys, PlainText, Headers, Signers, [signature_to_map(Protected, Header, Key, Signature) | Acc]); map_signatures([], _PlainText, [], [], Acc) -> lists:reverse(Acc). %% @private record_to_map(JWS=#jose_jws{alg={Module, ALG}}, Modules, Fields0) -> Fields1 = Module:to_map(ALG, Fields0), record_to_map(JWS#jose_jws{alg=undefined}, Modules#{ alg => Module }, Fields1); record_to_map(JWS=#jose_jws{b64=B64}, Modules, Fields0) when is_boolean(B64) -> Fields1 = Fields0#{ <<"b64">> => B64 }, record_to_map(JWS#jose_jws{b64=undefined}, Modules, Fields1); record_to_map(_JWS, Modules, Fields) -> {Modules, Fields}. %% @private signature_to_map(Protected, Header, #jose_jwk{fields=Fields}, Signature) -> signature_to_map(Protected, Header, Fields, Signature); signature_to_map(Protected, Header, #{ <<"kid">> := KID }, Signature) -> #{ <<"protected">> => Protected, <<"header">> => maps:put(<<"kid">>, KID, Header), <<"signature">> => Signature }; signature_to_map(Protected, Header, _Fields, Signature) -> case maps:size(Header) of 0 -> #{ <<"protected">> => Protected, <<"signature">> => Signature }; _ -> #{ <<"protected">> => Protected, <<"header">> => Header, <<"signature">> => Signature } end. erlang-jose-1.10.1/src/jws/jose_jws_alg_none.erl0000644000232200023220000000354613605433351022144 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws_alg_none). -behaviour(jose_jws). -behaviour(jose_jws_alg). %% jose_jws callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jws_alg callbacks -export([generate_key/2]). -export([sign/3]). -export([verify/4]). %% API %% Types -type alg() :: none. -export_type([alg/0]). %%==================================================================== %% jose_jws callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"none">> }) -> {none, maps:remove(<<"alg">>, F)}. to_map(none, F) -> F#{ <<"alg">> => <<"none">> }. %%==================================================================== %% jose_jws_alg callbacks %%==================================================================== generate_key(none, _Fields) -> erlang:error(not_supported). sign(_Key, _Message, none) -> case jose_jwa:unsecured_signing() of true -> <<>>; _ -> erlang:error(not_supported) end. verify(_Key, _Message, <<>>, none) -> case jose_jwa:unsecured_signing() of true -> true; _ -> false end; verify(_Key, _Message, _Signature, none) -> false. %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jws/jose_jws_alg_poly1305.erl0000644000232200023220000000523113605433351022472 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 08 Aug 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws_alg_poly1305). -behaviour(jose_jws). -behaviour(jose_jws_alg). -include("jose_jwk.hrl"). %% jose_jws callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jws_alg callbacks -export([generate_key/2]). -export([presign/2]). -export([sign/3]). -export([verify/4]). %% API %% Types -record('Poly1305', { nonce = undefined :: undefined | << _:12 >> }). -type alg() :: #'Poly1305'{}. -export_type([alg/0]). %%==================================================================== %% jose_jws callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"Poly1305">> }) -> from_map(maps:remove(<<"alg">>, F), #'Poly1305'{}). to_map(#'Poly1305'{nonce=undefined}, F) -> F#{ <<"alg">> => <<"Poly1305">> }; to_map(#'Poly1305'{nonce=Nonce}, F) -> F#{ <<"alg">> => <<"Poly1305">>, <<"nonce">> => jose_jwa_base64url:encode(Nonce) }. %%==================================================================== %% jose_jws_alg callbacks %%==================================================================== generate_key(#'Poly1305'{}, _Fields) -> jose_jws_alg:generate_key({oct, 32}, <<"Poly1305">>). presign(_Key, ALG=#'Poly1305'{nonce=undefined}) -> Nonce = crypto:strong_rand_bytes(12), ALG#'Poly1305'{nonce=Nonce}; presign(_Key, ALG) -> ALG. sign(#jose_jwk{kty={KTYModule, KTY}}, Message, ALG=#'Poly1305'{nonce=Nonce}) when is_binary(Nonce) andalso bit_size(Nonce) == 96 -> KTYModule:sign(Message, ALG, KTY). verify(_Key, _Message, _Signature, #'Poly1305'{nonce=undefined}) -> false; verify(#jose_jwk{kty={KTYModule, KTY}}, Message, Signature, ALG=#'Poly1305'{nonce=Nonce}) when is_binary(Nonce) andalso bit_size(Nonce) == 96 -> KTYModule:verify(Message, ALG, Signature, KTY). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private from_map(F = #{ <<"nonce">> := Nonce }, ALG) -> from_map(maps:remove(<<"nonce">>, F), ALG#'Poly1305'{nonce=jose_jwa_base64url:decode(Nonce)}); from_map(F, ALG) -> {ALG, F}. erlang-jose-1.10.1/src/jws/jose_jws_alg.erl0000644000232200023220000000252413605433351021120 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 29 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws_alg). -callback generate_key(ALG, Fields) -> JWK when ALG :: any(), Fields :: map(), JWK :: jose_jwk:key(). -callback sign(Key, Message, ALG) -> Signature when Key :: any(), Message :: iodata(), ALG :: any(), Signature :: iodata(). -callback verify(Key, Message, Signature, ALG) -> boolean() when Key :: any(), Message :: iodata(), Signature :: iodata(), ALG :: any(). -callback presign(Key, ALG) -> NewALG when Key :: any(), ALG :: any(), NewALG :: any(). -optional_callbacks([presign/2]). %% API -export([generate_key/2]). %%==================================================================== %% API functions %%==================================================================== generate_key(Parameters, Algorithm) -> jose_jwk:merge(jose_jwk:generate_key(Parameters), #{ <<"alg">> => Algorithm, <<"use">> => <<"sig">> }). erlang-jose-1.10.1/src/jws/jose_jws_alg_rsa_pss.erl0000644000232200023220000000445413605433351022656 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jws_alg_rsa_pss). -behaviour(jose_jws). -behaviour(jose_jws_alg). -include("jose_jwk.hrl"). %% jose_jws callbacks -export([from_map/1]). -export([to_map/2]). %% jose_jws_alg callbacks -export([generate_key/2]). -export([sign/3]). -export([verify/4]). %% API %% Types -type alg() :: 'PS256' | 'PS384' | 'PS512'. -export_type([alg/0]). %%==================================================================== %% jose_jws callbacks %%==================================================================== from_map(F = #{ <<"alg">> := <<"PS256">> }) -> {'PS256', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"PS384">> }) -> {'PS384', maps:remove(<<"alg">>, F)}; from_map(F = #{ <<"alg">> := <<"PS512">> }) -> {'PS512', maps:remove(<<"alg">>, F)}. to_map('PS256', F) -> F#{ <<"alg">> => <<"PS256">> }; to_map('PS384', F) -> F#{ <<"alg">> => <<"PS384">> }; to_map('PS512', F) -> F#{ <<"alg">> => <<"PS512">> }. %%==================================================================== %% jose_jws_alg callbacks %%==================================================================== generate_key('PS256', _Fields) -> jose_jws_alg:generate_key({rsa, 2048}, <<"PS256">>); generate_key('PS384', _Fields) -> jose_jws_alg:generate_key({rsa, 3072}, <<"PS384">>); generate_key('PS512', _Fields) -> jose_jws_alg:generate_key({rsa, 4096}, <<"PS512">>). sign(#jose_jwk{kty={KTYModule, KTY}}, Message, ALG) -> KTYModule:sign(Message, ALG, KTY). verify(#jose_jwk{kty={KTYModule, KTY}}, Message, Signature, ALG) -> KTYModule:verify(Message, ALG, Signature, KTY). %%==================================================================== %% API functions %%==================================================================== %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jose_chacha20_poly1305_libsodium.erl0000644000232200023220000000326213605433351023663 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 31 May 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_chacha20_poly1305_libsodium). -behaviour(jose_chacha20_poly1305). %% jose_chacha20_poly1305 callbacks -export([decrypt/5]). -export([encrypt/4]). -export([authenticate/3]). -export([verify/4]). %%==================================================================== %% jose_chacha20_poly1305 callbacks %%==================================================================== decrypt(CipherText, CipherTag, AAD, IV, CEK) -> libsodium_crypto_aead_chacha20poly1305:ietf_decrypt_detached(CipherText, CipherTag, AAD, IV, CEK). encrypt(PlainText, AAD, IV, CEK) -> libsodium_crypto_aead_chacha20poly1305:ietf_encrypt_detached(PlainText, AAD, IV, CEK). authenticate(Message, Key, Nonce) -> OTK = one_time_key(Key, Nonce), libsodium_crypto_onetimeauth_poly1305:crypto_onetimeauth_poly1305(Message, OTK). verify(MAC, Message, Key, Nonce) -> OTK = one_time_key(Key, Nonce), case libsodium_crypto_onetimeauth_poly1305:verify(MAC, Message, OTK) of 0 -> true; _ -> false end. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private one_time_key(Key, Nonce) -> libsodium_crypto_stream_chacha20:ietf_xor_ic(<< 0:256 >>, Nonce, 0, Key). erlang-jose-1.10.1/src/base/0000755000232200023220000000000013605433351016052 5ustar debalancedebalanceerlang-jose-1.10.1/src/base/jose_base.erl0000644000232200023220000001005013605433351020504 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2017-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 24 Feb 2018 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_base). %% API -export([calculate_shift/1]). -export([calculate_pairs/2]). %% parse_transform callbacks -export([parse_transform/2]). %%%=================================================================== %%% API functions %%%=================================================================== calculate_shift(Table) when is_list(Table) -> erlang:round(math:log2(length(Table))). calculate_pairs(Table, Type) when Type == sensitive orelse Type == upper -> Shift = calculate_shift(Table), do_calculate_pairs(Table, Table, Shift, []). %% @private do_calculate_pairs([{V0, C0} | Rest], Table, Shift, Acc0) -> Acc1 = do_calculate_pairs_permutation(V0 bsl Shift, C0 bsl 8, Table, Acc0), do_calculate_pairs(Rest, Table, Shift, Acc1); do_calculate_pairs([], _Table, _Shift, Acc) -> lists:reverse(Acc). %% @private do_calculate_pairs_permutation(V0, C0, [{V1, C1} | Rest], Acc0) -> V = V0 + V1, C = C0 + C1, Acc1 = [{V, C} | Acc0], do_calculate_pairs_permutation(V0, C0, Rest, Acc1); do_calculate_pairs_permutation(_, _, [], Acc) -> Acc. %%%=================================================================== %%% parse_transform callbacks %%%=================================================================== parse_transform(Ast, _Options) -> walk_ast([], Ast). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private walk_ast(Acc, []) -> lists:reverse(Acc); walk_ast(Acc, [{function, Line, Name, Arity, Clauses} | Ast]) -> walk_ast([{function, Line, Name, Arity, walk_clauses([], Clauses)} | Acc], Ast); walk_ast(Acc, [Form | Ast]) -> walk_ast([Form | Acc], Ast). %% @private walk_clauses(Acc, []) -> lists:reverse(Acc); walk_clauses(Acc, [{clause, Line, Arguments, Guards, Body} | Ast]) -> walk_clauses([{clause, Line, Arguments, Guards, walk_body([], Body)} | Acc], Ast). %% @private walk_body(Acc, []) -> lists:reverse(Acc); walk_body(Acc, [Statement | Ast]) -> walk_body([transform_statement(Statement) | Acc], Ast). %% @private transform_statement(Statement = {call, Line, {remote, _Line1, {atom, _Line2, ?MODULE}, {atom, _Line3, Function}}, Arguments}) -> case transform_call(Function, Line, Arguments) of {ok, NewStatement} -> NewStatement; error -> Statement end; transform_statement({match, Line, Pattern, Expression}) -> {match, Line, Pattern, transform_expression(Expression)}; transform_statement(Statement) -> Statement. %% @private transform_expression({bc, Line1, {bin, Line2, Elements}, Qualifiers}) -> {bc, Line1, {bin, Line2, walk_elements([], Elements)}, Qualifiers}; transform_expression(Expression) -> Expression. %% @private walk_elements(Acc, []) -> lists:reverse(Acc); walk_elements(Acc, [{bin_element, Line, Statement, Size, Type} | Ast]) -> walk_elements([{bin_element, Line, transform_statement(Statement), Size, Type} | Acc], Ast); walk_elements(Acc, [Element | Ast]) -> walk_elements([Element | Acc], Ast). %% @private transform_call(encode_char, _Line, [Case = {'case', _Line1, _Var, [{clause, _Line2, [{integer, _Line3, 0}], [], [{char, _Line4, _}]} | _]}]) -> {ok, Case}; transform_call(encode_pair, Line, [{'case', _Line1, Var, Clauses0 = [{clause, _Line2, [{integer, _Line3, 0}], [], [{char, _Line4, _}]} | _]}, {atom, _Line5, Type}]) -> Table = calculate_pairs([{Index, Value} || {clause, _, [{integer, _, Index}], [], [{char, _, Value}]} <- Clauses0], Type), Clauses1 = [{clause, Line, [{integer, Line, Index}], [], [{integer, Line, Value}]} || {Index, Value} <- Table], Case = {'case', Line, Var, Clauses1}, {ok, Case}; transform_call(_Function, _Line, _Arguments) -> error. erlang-jose-1.10.1/src/base/jose_base64.erl0000644000232200023220000001753413605433351020674 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2017-2019, Andrew Bennett %%% @doc RFC 4648, Section 4: https://tools.ietf.org/html/rfc4648#section-4 %%% %%% @end %%% Created : 11 May 2017 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_base64). -compile({parse_transform, jose_base}). -include("jose_base.hrl"). %% API -export([decode/1]). -export([decode/2]). -export(['decode!'/1]). -export(['decode!'/2]). -export([encode/1]). -export([encode/2]). -export([random/1]). -export([random/2]). % Macros -define(B64_TO_INT(C), case C of $A -> 16#00; $B -> 16#01; $C -> 16#02; $D -> 16#03; $E -> 16#04; $F -> 16#05; $G -> 16#06; $H -> 16#07; $I -> 16#08; $J -> 16#09; $K -> 16#0A; $L -> 16#0B; $M -> 16#0C; $N -> 16#0D; $O -> 16#0E; $P -> 16#0F; $Q -> 16#10; $R -> 16#11; $S -> 16#12; $T -> 16#13; $U -> 16#14; $V -> 16#15; $W -> 16#16; $X -> 16#17; $Y -> 16#18; $Z -> 16#19; $a -> 16#1A; $b -> 16#1B; $c -> 16#1C; $d -> 16#1D; $e -> 16#1E; $f -> 16#1F; $g -> 16#20; $h -> 16#21; $i -> 16#22; $j -> 16#23; $k -> 16#24; $l -> 16#25; $m -> 16#26; $n -> 16#27; $o -> 16#28; $p -> 16#29; $q -> 16#2A; $r -> 16#2B; $s -> 16#2C; $t -> 16#2D; $u -> 16#2E; $v -> 16#2F; $w -> 16#30; $x -> 16#31; $y -> 16#32; $z -> 16#33; $0 -> 16#34; $1 -> 16#35; $2 -> 16#36; $3 -> 16#37; $4 -> 16#38; $5 -> 16#39; $6 -> 16#3A; $7 -> 16#3B; $8 -> 16#3C; $9 -> 16#3D; $+ -> 16#3E; $/ -> 16#3F end). -define(INT_TO_B64(C), case C of 16#00 -> $A; 16#01 -> $B; 16#02 -> $C; 16#03 -> $D; 16#04 -> $E; 16#05 -> $F; 16#06 -> $G; 16#07 -> $H; 16#08 -> $I; 16#09 -> $J; 16#0A -> $K; 16#0B -> $L; 16#0C -> $M; 16#0D -> $N; 16#0E -> $O; 16#0F -> $P; 16#10 -> $Q; 16#11 -> $R; 16#12 -> $S; 16#13 -> $T; 16#14 -> $U; 16#15 -> $V; 16#16 -> $W; 16#17 -> $X; 16#18 -> $Y; 16#19 -> $Z; 16#1A -> $a; 16#1B -> $b; 16#1C -> $c; 16#1D -> $d; 16#1E -> $e; 16#1F -> $f; 16#20 -> $g; 16#21 -> $h; 16#22 -> $i; 16#23 -> $j; 16#24 -> $k; 16#25 -> $l; 16#26 -> $m; 16#27 -> $n; 16#28 -> $o; 16#29 -> $p; 16#2A -> $q; 16#2B -> $r; 16#2C -> $s; 16#2D -> $t; 16#2E -> $u; 16#2F -> $v; 16#30 -> $w; 16#31 -> $x; 16#32 -> $y; 16#33 -> $z; 16#34 -> $0; 16#35 -> $1; 16#36 -> $2; 16#37 -> $3; 16#38 -> $4; 16#39 -> $5; 16#3A -> $6; 16#3B -> $7; 16#3C -> $8; 16#3D -> $9; 16#3E -> $+; 16#3F -> $/ end). %%%=================================================================== %%% API functions %%%=================================================================== decode(Input) when ?is_iodata(Input) -> decode(Input, #{}). decode(Input, Opts) when ?is_iodata(Input) andalso is_map(Opts) -> try 'decode!'(Input, Opts) of Output when is_binary(Output) -> {ok, Output} catch _:_ -> error end; decode(Input, Opts) when ?is_iodata(Input) andalso is_list(Opts) -> decode(Input, maps:from_list(Opts)). 'decode!'(Input) when ?is_iodata(Input) -> 'decode!'(Input, #{}). 'decode!'([], #{}) -> <<>>; 'decode!'(<<>>, #{}) -> <<>>; 'decode!'(Input, Opts) when ?is_iodata(Input) andalso is_map(Opts) -> Padding = maps:get('padding', Opts, nil), Size = erlang:iolist_size(Input), Offset = case Padding of _ when (Padding == false orelse Padding == nil) andalso Size =< 4 -> 0; _ when (Padding == false orelse Padding == nil) andalso (Size rem 4) =/= 0 -> Size - (Size rem 4); _ when (Padding == false orelse Padding == nil) -> Size - 4; _ when (Padding == true orelse Padding == nil) andalso Size >= 4 -> Size - 4; _ -> erlang:error({badarg, [Input, Opts]}) end, << Head0:Offset/binary, Tail0/binary >> = ?to_binary(Input), Head = << << (?B64_TO_INT(V)):6 >> || << V >> <= Head0 >>, Tail = case Padding of false -> case Tail0 of << T0:8, T1:8 >> -> << (?B64_TO_INT(T0)):6, (?B64_TO_INT(T1) bsr 4):2 >>; << T0:8, T1:8, T2:8 >> -> << (?B64_TO_INT(T0)):6, (?B64_TO_INT(T1)):6, (?B64_TO_INT(T2) bsr 2):4 >>; << T:4/binary >> -> << << (?B64_TO_INT(V)):6 >> || << V >> <= T >>; <<>> -> <<>>; _ -> erlang:error({badarg, [Input, Opts]}) end; nil -> case Tail0 of << T0:8, T1:8, $=, $= >> -> << (?B64_TO_INT(T0)):6, (?B64_TO_INT(T1) bsr 4):2 >>; << T0:8, T1:8, T2:8, $= >> -> << (?B64_TO_INT(T0)):6, (?B64_TO_INT(T1)):6, (?B64_TO_INT(T2) bsr 2):4 >>; << T0:8, T1:8 >> -> << (?B64_TO_INT(T0)):6, (?B64_TO_INT(T1) bsr 4):2 >>; << T0:8, T1:8, T2:8 >> -> << (?B64_TO_INT(T0)):6, (?B64_TO_INT(T1)):6, (?B64_TO_INT(T2) bsr 2):4 >>; << T:4/binary >> -> << << (?B64_TO_INT(V)):6 >> || << V >> <= T >>; <<>> -> <<>> end; true -> case Tail0 of << T0:8, T1:8, $=, $= >> -> << (?B64_TO_INT(T0)):6, (?B64_TO_INT(T1) bsr 4):2 >>; << T0:8, T1:8, T2:8, $= >> -> << (?B64_TO_INT(T0)):6, (?B64_TO_INT(T1)):6, (?B64_TO_INT(T2) bsr 2):4 >>; << T:4/binary >> -> << << (?B64_TO_INT(V)):6 >> || << V >> <= T >>; <<>> -> <<>>; _ -> erlang:error({badarg, [Input, Opts]}) end end, << Head/binary, Tail/binary >>; 'decode!'(Input, Opts) when ?is_iodata(Input) andalso is_list(Opts) -> 'decode!'(Input, maps:from_list(Opts)). encode(Input) when ?is_iodata(Input) -> encode(Input, #{}). encode(Input, Opts) when ?is_iodata(Input) andalso is_map(Opts) -> Padding = maps:get('padding', Opts, true), Offset = 6 * (erlang:iolist_size(Input) div 6), << Head:Offset/binary, Tail/binary >> = ?to_binary(Input), H = << << (encode_pair(V0)):16, (encode_pair(V1)):16, (encode_pair(V2)):16, (encode_pair(V3)):16 >> || << V0:12, V1:12, V2:12, V3:12 >> <= Head >>, {T, Pad} = case Tail of << T0:12, T1:12, T2:12, T3:4 >> -> {<< (encode_pair(T0)):16, (encode_pair(T1)):16, (encode_pair(T2)):16, (encode_char(T3 bsl 2)):8 >>, << $= >>}; << T0:12, T1:12, T2:8 >> -> {<< (encode_pair(T0)):16, (encode_pair(T1)):16, (encode_pair(T2 bsl 4)):16 >>, << $=, $= >>}; << T0:12, T1:12 >> -> {<< (encode_pair(T0)):16, (encode_pair(T1)):16 >>, <<>>}; << T0:12, T1:4 >> -> {<< (encode_pair(T0)):16, (encode_char(T1 bsl 2)):8 >>, <<>>}; << T0:8 >> -> {<< (encode_pair(T0 bsl 4)):16 >>, << $=, $= >>}; <<>> -> {<<>>, <<>>} end, case Padding of true -> << H/binary, T/binary, Pad/binary >>; false -> << H/binary, T/binary >>; _ -> erlang:error({badarg, [Input, Opts]}) end; encode(Input, Opts) when ?is_iodata(Input) andalso is_list(Opts) -> encode(Input, maps:from_list(Opts)). random(Bytes) when is_integer(Bytes) andalso Bytes >= 0 -> random(Bytes, #{}). random(0, Opts) when is_map(Opts) -> <<>>; random(Bytes, Opts) when (Bytes =:= 1) andalso is_map(Opts) -> erlang:error({badarg, [Bytes, Opts]}); random(Bytes, Opts) when is_integer(Bytes) andalso Bytes > 0 andalso is_map(Opts) -> Padding = maps:get('padding', Opts, true), R = (Bytes rem 4), Size = case Padding of true when R =:= 0 -> (Bytes * 3) div 4; false when R =:= 0 orelse R =:= 2 orelse R =:= 3 -> (Bytes * 3) div 4; _ -> erlang:error({badarg, [Bytes, Opts]}) end, Binary = crypto:strong_rand_bytes(Size), encode(Binary, Opts); random(Bytes, Opts) when is_integer(Bytes) andalso Bytes >= 0 andalso is_list(Opts) -> random(Bytes, maps:from_list(Opts)). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private encode_char(V) -> jose_base:encode_char(?INT_TO_B64(V)). %% @private encode_pair(V) -> jose_base:encode_pair(?INT_TO_B64(V), sensitive). erlang-jose-1.10.1/src/base/jose_base64url.erl0000644000232200023220000001766313605433351021422 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2017-2019, Andrew Bennett %%% @doc RFC 4648, Section 5: https://tools.ietf.org/html/rfc4648#section-5 %%% %%% @end %%% Created : 11 May 2017 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_base64url). -compile({parse_transform, jose_base}). -include("jose_base.hrl"). %% API -export([decode/1]). -export([decode/2]). -export(['decode!'/1]). -export(['decode!'/2]). -export([encode/1]). -export([encode/2]). -export([random/1]). -export([random/2]). % Macros -define(B64URL_TO_INT(C), case C of $A -> 16#00; $B -> 16#01; $C -> 16#02; $D -> 16#03; $E -> 16#04; $F -> 16#05; $G -> 16#06; $H -> 16#07; $I -> 16#08; $J -> 16#09; $K -> 16#0A; $L -> 16#0B; $M -> 16#0C; $N -> 16#0D; $O -> 16#0E; $P -> 16#0F; $Q -> 16#10; $R -> 16#11; $S -> 16#12; $T -> 16#13; $U -> 16#14; $V -> 16#15; $W -> 16#16; $X -> 16#17; $Y -> 16#18; $Z -> 16#19; $a -> 16#1A; $b -> 16#1B; $c -> 16#1C; $d -> 16#1D; $e -> 16#1E; $f -> 16#1F; $g -> 16#20; $h -> 16#21; $i -> 16#22; $j -> 16#23; $k -> 16#24; $l -> 16#25; $m -> 16#26; $n -> 16#27; $o -> 16#28; $p -> 16#29; $q -> 16#2A; $r -> 16#2B; $s -> 16#2C; $t -> 16#2D; $u -> 16#2E; $v -> 16#2F; $w -> 16#30; $x -> 16#31; $y -> 16#32; $z -> 16#33; $0 -> 16#34; $1 -> 16#35; $2 -> 16#36; $3 -> 16#37; $4 -> 16#38; $5 -> 16#39; $6 -> 16#3A; $7 -> 16#3B; $8 -> 16#3C; $9 -> 16#3D; $- -> 16#3E; $_ -> 16#3F end). -define(INT_TO_B64URL(C), case C of 16#00 -> $A; 16#01 -> $B; 16#02 -> $C; 16#03 -> $D; 16#04 -> $E; 16#05 -> $F; 16#06 -> $G; 16#07 -> $H; 16#08 -> $I; 16#09 -> $J; 16#0A -> $K; 16#0B -> $L; 16#0C -> $M; 16#0D -> $N; 16#0E -> $O; 16#0F -> $P; 16#10 -> $Q; 16#11 -> $R; 16#12 -> $S; 16#13 -> $T; 16#14 -> $U; 16#15 -> $V; 16#16 -> $W; 16#17 -> $X; 16#18 -> $Y; 16#19 -> $Z; 16#1A -> $a; 16#1B -> $b; 16#1C -> $c; 16#1D -> $d; 16#1E -> $e; 16#1F -> $f; 16#20 -> $g; 16#21 -> $h; 16#22 -> $i; 16#23 -> $j; 16#24 -> $k; 16#25 -> $l; 16#26 -> $m; 16#27 -> $n; 16#28 -> $o; 16#29 -> $p; 16#2A -> $q; 16#2B -> $r; 16#2C -> $s; 16#2D -> $t; 16#2E -> $u; 16#2F -> $v; 16#30 -> $w; 16#31 -> $x; 16#32 -> $y; 16#33 -> $z; 16#34 -> $0; 16#35 -> $1; 16#36 -> $2; 16#37 -> $3; 16#38 -> $4; 16#39 -> $5; 16#3A -> $6; 16#3B -> $7; 16#3C -> $8; 16#3D -> $9; 16#3E -> $-; 16#3F -> $_ end). %%%=================================================================== %%% API functions %%%=================================================================== decode(Input) when ?is_iodata(Input) -> decode(Input, #{}). decode(Input, Opts) when ?is_iodata(Input) andalso is_map(Opts) -> try 'decode!'(Input, Opts) of Output when is_binary(Output) -> {ok, Output} catch _:_ -> error end; decode(Input, Opts) when ?is_iodata(Input) andalso is_list(Opts) -> decode(Input, maps:from_list(Opts)). 'decode!'(Input) when ?is_iodata(Input) -> 'decode!'(Input, #{}). 'decode!'([], #{}) -> <<>>; 'decode!'(<<>>, #{}) -> <<>>; 'decode!'(Input, Opts) when ?is_iodata(Input) andalso is_map(Opts) -> Padding = maps:get('padding', Opts, nil), Size = erlang:iolist_size(Input), Offset = case Padding of _ when (Padding == false orelse Padding == nil) andalso Size =< 4 -> 0; _ when (Padding == false orelse Padding == nil) andalso (Size rem 4) =/= 0 -> Size - (Size rem 4); _ when (Padding == false orelse Padding == nil) -> Size - 4; _ when (Padding == true orelse Padding == nil) andalso Size >= 4 -> Size - 4; _ -> erlang:error({badarg, [Input, Opts]}) end, << Head0:Offset/binary, Tail0/binary >> = ?to_binary(Input), Head = << << (?B64URL_TO_INT(V)):6 >> || << V >> <= Head0 >>, Tail = case Padding of false -> case Tail0 of << T0:8, T1:8 >> -> << (?B64URL_TO_INT(T0)):6, (?B64URL_TO_INT(T1) bsr 4):2 >>; << T0:8, T1:8, T2:8 >> -> << (?B64URL_TO_INT(T0)):6, (?B64URL_TO_INT(T1)):6, (?B64URL_TO_INT(T2) bsr 2):4 >>; << T:4/binary >> -> << << (?B64URL_TO_INT(V)):6 >> || << V >> <= T >>; <<>> -> <<>>; _ -> erlang:error({badarg, [Input, Opts]}) end; nil -> case Tail0 of << T0:8, T1:8, $=, $= >> -> << (?B64URL_TO_INT(T0)):6, (?B64URL_TO_INT(T1) bsr 4):2 >>; << T0:8, T1:8, T2:8, $= >> -> << (?B64URL_TO_INT(T0)):6, (?B64URL_TO_INT(T1)):6, (?B64URL_TO_INT(T2) bsr 2):4 >>; << T0:8, T1:8 >> -> << (?B64URL_TO_INT(T0)):6, (?B64URL_TO_INT(T1) bsr 4):2 >>; << T0:8, T1:8, T2:8 >> -> << (?B64URL_TO_INT(T0)):6, (?B64URL_TO_INT(T1)):6, (?B64URL_TO_INT(T2) bsr 2):4 >>; << T:4/binary >> -> << << (?B64URL_TO_INT(V)):6 >> || << V >> <= T >>; <<>> -> <<>> end; true -> case Tail0 of << T0:8, T1:8, $=, $= >> -> << (?B64URL_TO_INT(T0)):6, (?B64URL_TO_INT(T1) bsr 4):2 >>; << T0:8, T1:8, T2:8, $= >> -> << (?B64URL_TO_INT(T0)):6, (?B64URL_TO_INT(T1)):6, (?B64URL_TO_INT(T2) bsr 2):4 >>; << T:4/binary >> -> << << (?B64URL_TO_INT(V)):6 >> || << V >> <= T >>; <<>> -> <<>>; _ -> erlang:error({badarg, [Input, Opts]}) end end, << Head/binary, Tail/binary >>; 'decode!'(Input, Opts) when ?is_iodata(Input) andalso is_list(Opts) -> 'decode!'(Input, maps:from_list(Opts)). encode(Input) when ?is_iodata(Input) -> encode(Input, #{}). encode(Input, Opts) when ?is_iodata(Input) andalso is_map(Opts) -> Padding = maps:get('padding', Opts, true), Offset = 6 * (erlang:iolist_size(Input) div 6), << Head:Offset/binary, Tail/binary >> = ?to_binary(Input), H = << << (encode_pair(V0)):16, (encode_pair(V1)):16, (encode_pair(V2)):16, (encode_pair(V3)):16 >> || << V0:12, V1:12, V2:12, V3:12 >> <= Head >>, {T, Pad} = case Tail of << T0:12, T1:12, T2:12, T3:4 >> -> {<< (encode_pair(T0)):16, (encode_pair(T1)):16, (encode_pair(T2)):16, (encode_char(T3 bsl 2)):8 >>, << $= >>}; << T0:12, T1:12, T2:8 >> -> {<< (encode_pair(T0)):16, (encode_pair(T1)):16, (encode_pair(T2 bsl 4)):16 >>, << $=, $= >>}; << T0:12, T1:12 >> -> {<< (encode_pair(T0)):16, (encode_pair(T1)):16 >>, <<>>}; << T0:12, T1:4 >> -> {<< (encode_pair(T0)):16, (encode_char(T1 bsl 2)):8 >>, <<>>}; << T0:8 >> -> {<< (encode_pair(T0 bsl 4)):16 >>, << $=, $= >>}; <<>> -> {<<>>, <<>>} end, case Padding of true -> << H/binary, T/binary, Pad/binary >>; false -> << H/binary, T/binary >>; _ -> erlang:error({badarg, [Input, Opts]}) end; encode(Input, Opts) when ?is_iodata(Input) andalso is_list(Opts) -> encode(Input, maps:from_list(Opts)). random(Bytes) when is_integer(Bytes) andalso Bytes >= 0 -> random(Bytes, #{}). random(0, Opts) when is_map(Opts) -> <<>>; random(Bytes, Opts) when (Bytes =:= 1) andalso is_map(Opts) -> erlang:error({badarg, [Bytes, Opts]}); random(Bytes, Opts) when is_integer(Bytes) andalso Bytes > 0 andalso is_map(Opts) -> Padding = maps:get('padding', Opts, true), R = (Bytes rem 4), Size = case Padding of true when R =:= 0 -> (Bytes * 3) div 4; false when R =:= 0 orelse R =:= 2 orelse R =:= 3 -> (Bytes * 3) div 4; _ -> erlang:error({badarg, [Bytes, Opts]}) end, Binary = crypto:strong_rand_bytes(Size), encode(Binary, Opts); random(Bytes, Opts) when is_integer(Bytes) andalso Bytes >= 0 andalso is_list(Opts) -> random(Bytes, maps:from_list(Opts)). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private encode_char(V) -> jose_base:encode_char(?INT_TO_B64URL(V)). %% @private encode_pair(V) -> jose_base:encode_pair(?INT_TO_B64URL(V), sensitive). erlang-jose-1.10.1/src/jose_curve25519.erl0000644000232200023220000000573113605433351020424 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 02 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_curve25519). -callback eddsa_keypair() -> {PublicKey::binary(), SecretKey::binary()}. -callback eddsa_keypair(Seed::binary()) -> {PublicKey::binary(), SecretKey::binary()}. -callback eddsa_secret_to_public(SecretKey::binary()) -> PublicKey::binary(). -callback ed25519_sign(Message::binary(), SecretKey::binary()) -> Signature::binary(). -callback ed25519_verify(Signature::binary(), Message::binary(), PublicKey::binary()) -> boolean(). -callback ed25519ph_sign(Message::binary(), SecretKey::binary()) -> Signature::binary(). -callback ed25519ph_verify(Signature::binary(), Message::binary(), PublicKey::binary()) -> boolean(). -callback x25519_keypair() -> {PublicKey::binary(), SecretKey::binary()}. -callback x25519_keypair(Seed::binary()) -> {PublicKey::binary(), SecretKey::binary()}. -callback x25519_secret_to_public(SecretKey::binary()) -> PublicKey::binary(). -callback x25519_shared_secret(MySecretKey::binary(), YourPublicKey::binary()) -> SharedSecret::binary(). %% jose_curve25519 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed25519_sign/2]). -export([ed25519_verify/3]). -export([ed25519ph_sign/2]). -export([ed25519ph_verify/3]). -export([x25519_keypair/0]). -export([x25519_keypair/1]). -export([x25519_secret_to_public/1]). -export([x25519_shared_secret/2]). %% Macros -define(JOSE_CURVE25519, (jose:curve25519_module())). %%==================================================================== %% jose_curve25519 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> ?JOSE_CURVE25519:eddsa_keypair(). eddsa_keypair(Seed) -> ?JOSE_CURVE25519:eddsa_keypair(Seed). eddsa_secret_to_public(SecretKey) -> ?JOSE_CURVE25519:eddsa_secret_to_public(SecretKey). % Ed25519 ed25519_sign(Message, SecretKey) -> ?JOSE_CURVE25519:ed25519_sign(Message, SecretKey). ed25519_verify(Signature, Message, PublicKey) -> ?JOSE_CURVE25519:ed25519_verify(Signature, Message, PublicKey). % Ed25519ph ed25519ph_sign(Message, SecretKey) -> ?JOSE_CURVE25519:ed25519ph_sign(Message, SecretKey). ed25519ph_verify(Signature, Message, PublicKey) -> ?JOSE_CURVE25519:ed25519ph_verify(Signature, Message, PublicKey). % X25519 x25519_keypair() -> ?JOSE_CURVE25519:x25519_keypair(). x25519_keypair(Seed) -> ?JOSE_CURVE25519:x25519_keypair(Seed). x25519_secret_to_public(SecretKey) -> ?JOSE_CURVE25519:x25519_secret_to_public(SecretKey). x25519_shared_secret(MySecretKey, YourPublicKey) -> ?JOSE_CURVE25519:x25519_shared_secret(MySecretKey, YourPublicKey). erlang-jose-1.10.1/src/jose_sha3_unsupported.erl0000644000232200023220000000221313605433351022170 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 11 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_sha3_unsupported). -behaviour(jose_sha3). %% jose_sha3 callbacks -export([sha3_224/1]). -export([sha3_256/1]). -export([sha3_384/1]). -export([sha3_512/1]). -export([shake128/2]). -export([shake256/2]). %% Macros -define(unsupported, erlang:error(sha3_unsupported)). %%==================================================================== %% jose_sha3 callbacks %%==================================================================== sha3_224(_InputBytes) -> ?unsupported. sha3_256(_InputBytes) -> ?unsupported. sha3_384(_InputBytes) -> ?unsupported. sha3_512(_InputBytes) -> ?unsupported. shake128(_InputBytes, _OutputByteLen) -> ?unsupported. shake256(_InputBytes, _OutputByteLen) -> ?unsupported. erlang-jose-1.10.1/src/jwt/0000755000232200023220000000000013605433351015744 5ustar debalancedebalanceerlang-jose-1.10.1/src/jwt/jose_jwt.erl0000644000232200023220000002060313605433351020275 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 21 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwt). -include("jose_jwe.hrl"). -include("jose_jwk.hrl"). -include("jose_jws.hrl"). -include("jose_jwt.hrl"). %% Decode API -export([from/1]). -export([from_binary/1]). -export([from_file/1]). -export([from_map/1]). %% Encode API -export([to_binary/1]). -export([to_file/2]). -export([to_map/1]). %% API -export([decrypt/2]). -export([encrypt/2]). -export([encrypt/3]). -export([merge/2]). -export([peek/1]). -export([peek_payload/1]). -export([peek_protected/1]). -export([sign/2]). -export([sign/3]). -export([verify/2]). -export([verify_strict/3]). %%==================================================================== %% Decode API functions %%==================================================================== from(List) when is_list(List) -> [from(Element) || Element <- List]; from({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> from_map({Modules, Map}); from({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> from_binary({Modules, Binary}); from(JWT=#jose_jwt{}) -> JWT; from(Other) when is_map(Other) orelse is_binary(Other) -> from({#{}, Other}). from_binary(List) when is_list(List) -> [from_binary(Element) || Element <- List]; from_binary({Modules, Binary}) when is_map(Modules) andalso is_binary(Binary) -> from_map({Modules, jose:decode(Binary)}); from_binary(Binary) when is_binary(Binary) -> from_binary({#{}, Binary}). from_file({Modules, File}) when is_map(Modules) andalso (is_binary(File) orelse is_list(File)) -> case file:read_file(File) of {ok, Binary} -> from_binary({Modules, Binary}); ReadError -> ReadError end; from_file(File) when is_binary(File) orelse is_list(File) -> from_file({#{}, File}). from_map(List) when is_list(List) -> [from_map(Element) || Element <- List]; from_map(Map) when is_map(Map) -> from_map({#{}, Map}); from_map({Modules, Map}) when is_map(Modules) andalso is_map(Map) -> from_map({#jose_jwt{}, Modules, Map}); from_map({JWT, _Modules, Fields}) -> JWT#jose_jwt{ fields = Fields }. %%==================================================================== %% Encode API functions %%==================================================================== to_binary(List) when is_list(List) -> [to_binary(Element) || Element <- List]; to_binary(JWT=#jose_jwt{}) -> {Modules, Map} = to_map(JWT), {Modules, jose:encode(Map)}; to_binary(Other) -> to_binary(from(Other)). to_file(File, JWT=#jose_jwt{}) when is_binary(File) orelse is_list(File) -> {Modules, Binary} = to_binary(JWT), case file:write_file(File, Binary) of ok -> {Modules, File}; WriteError -> WriteError end; to_file(File, Other) when is_binary(File) orelse is_list(File) -> to_file(File, from(Other)). to_map(List) when is_list(List) -> [to_map(Element) || Element <- List]; to_map(JWT=#jose_jwt{fields=Fields}) -> record_to_map(JWT, #{}, Fields); to_map(Other) -> to_map(from(Other)). %%==================================================================== %% API functions %%==================================================================== decrypt(Key, {Modules, Encrypted}) when is_map(Modules) andalso is_map(Encrypted) -> {JWTBinary, JWE=#jose_jwe{}} = jose_jwe:block_decrypt(Key, {Modules, Encrypted}), {JWE, from_binary({Modules, JWTBinary})}; decrypt(Key, {Modules, Encrypted = << ${, _/binary >>}) when is_map(Modules) -> EncryptedMap = jose:decode(Encrypted), decrypt(Key, {Modules, EncryptedMap}); decrypt(Key, {Modules, Encrypted}) when is_map(Modules) andalso is_binary(Encrypted) -> {JWTBinary, JWE=#jose_jwe{}} = jose_jwe:block_decrypt(Key, {Modules, Encrypted}), {JWE, from_binary({Modules, JWTBinary})}; decrypt(Key, Encrypted) when is_map(Encrypted) orelse is_binary(Encrypted) -> decrypt(Key, {#{}, Encrypted}). encrypt(JWK=#jose_jwk{}, JWT=#jose_jwt{}) -> encrypt(JWK, jose_jwk:block_encryptor(JWK), JWT); encrypt(JWKOther, JWTOther) -> encrypt(jose_jwk:from(JWKOther), from(JWTOther)). encrypt(JWK=#jose_jwk{}, JWE=#jose_jwe{}, JWT=#jose_jwt{}) -> {Modules0, JWTBinary} = to_binary(JWT), {Modules1, SignedMap} = jose_jwk:block_encrypt(JWTBinary, JWE, JWK), {maps:merge(Modules0, Modules1), SignedMap}; encrypt(JWKOther, {JWEModules, JWEMap=#{ <<"typ">> := _ }}, JWTOther) -> encrypt(JWKOther, jose_jwe:from({JWEModules, JWEMap}), JWTOther); encrypt(JWKOther, {JWEModules, JWEMap0}, JWTOther) when is_map(JWEMap0) -> Keys = [<<"typ">>] -- maps:keys(JWEMap0), JWEMap1 = normalize_block_encryptor(Keys, JWEMap0), encrypt(JWKOther, {JWEModules, JWEMap1}, JWTOther); encrypt(JWKOther, JWEMap, JWTOther) when is_map(JWEMap) -> encrypt(JWKOther, {#{}, JWEMap}, JWTOther); encrypt(JWKOther, JWEOther, JWTOther) -> encrypt(jose_jwk:from(JWKOther), jose_jwe:from(JWEOther), from(JWTOther)). merge(LeftJWT=#jose_jwt{}, RightMap) when is_map(RightMap) -> {Modules, LeftMap} = to_map(LeftJWT), from_map({Modules, maps:merge(LeftMap, RightMap)}); merge(LeftOther, RightJWT=#jose_jwt{}) -> merge(LeftOther, element(2, to_map(RightJWT))); merge(LeftOther, RightMap) when is_map(RightMap) -> merge(from(LeftOther), RightMap). peek(Signed) -> peek_payload(Signed). peek_payload(Signed) -> from(jose_jws:peek_payload(Signed)). peek_protected(Signed) -> jose_jws:from(jose_jws:peek_protected(Signed)). sign(JWK=#jose_jwk{}, JWT=#jose_jwt{}) -> sign(JWK, jose_jwk:signer(JWK), JWT); sign([], JWTOther) -> erlang:error({badarg, [[], JWTOther]}); sign(JWKOther, JWTOther) -> sign(jose_jwk:from(JWKOther), from(JWTOther)). sign(JWK=#jose_jwk{}, JWS=#jose_jws{}, JWT=#jose_jwt{}) -> {Modules0, JWTBinary} = to_binary(JWT), {Modules1, SignedMap} = jose_jwk:sign(JWTBinary, JWS, JWK), {maps:merge(Modules0, Modules1), SignedMap}; sign(JWKOther, {JWSModules, JWSMap=#{ <<"typ">> := _ }}, JWTOther) -> sign(JWKOther, jose_jws:from({JWSModules, JWSMap}), JWTOther); sign(JWKOther, {JWSModules, JWSMap0}, JWTOther) when is_map(JWSMap0) -> Keys = [<<"typ">>] -- maps:keys(JWSMap0), JWSMap1 = normalize_signer(Keys, JWSMap0), sign(JWKOther, {JWSModules, JWSMap1}, JWTOther); sign(JWKOther, JWSMap, JWTOther) when is_map(JWSMap) -> sign(JWKOther, {#{}, JWSMap}, JWTOther); sign([], JWSOther, JWTOther) -> erlang:error({badarg, [[], JWSOther, JWTOther]}); sign(JWKOther, JWSOther, JWTOther) -> sign(jose_jwk:from(JWKOther), jose_jws:from(JWSOther), from(JWTOther)). verify(JWK=#jose_jwk{}, {Modules, Signed}) -> {Verified, JWTBinary, JWS} = jose_jwk:verify({Modules, Signed}, JWK), {Verified, from_binary({Modules, JWTBinary}), JWS}; verify(Other, SignedBinary) when is_binary(SignedBinary) -> verify(Other, {#{}, SignedBinary}); verify(Other, SignedMap) when is_map(SignedMap) -> verify(Other, {#{}, SignedMap}); verify(JWK=#jose_jwk{}, Signed) -> erlang:error({badarg, [JWK, Signed]}); verify([], Signed) -> erlang:error({badarg, [[], Signed]}); verify(Other, Signed) -> verify(jose_jwk:from(Other), Signed). verify_strict(JWK=#jose_jwk{}, Allow, {Modules, Signed}) -> {Verified, JWTBinary, JWS} = jose_jwk:verify_strict({Modules, Signed}, Allow, JWK), {Verified, from_binary({Modules, JWTBinary}), JWS}; verify_strict(Other, Allow, SignedBinary) when is_binary(SignedBinary) -> verify_strict(Other, Allow, {#{}, SignedBinary}); verify_strict(Other, Allow, SignedMap) when is_map(SignedMap) -> verify_strict(Other, Allow, {#{}, SignedMap}); verify_strict(JWK=#jose_jwk{}, Allow, Signed) -> erlang:error({badarg, [JWK, Allow, Signed]}); verify_strict([], Allow, Signed) -> erlang:error({badarg, [[], Allow, Signed]}); verify_strict(Other, Allow, Signed) -> verify_strict(jose_jwk:from(Other), Allow, Signed). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private normalize_block_encryptor([<<"typ">> | Keys], Map) -> normalize_block_encryptor(Keys, Map#{ <<"typ">> => <<"JWT">> }); normalize_block_encryptor([], Map) -> Map. %% @private normalize_signer([<<"typ">> | Keys], Map) -> normalize_signer(Keys, Map#{ <<"typ">> => <<"JWT">> }); normalize_signer([], Map) -> Map. %% @private record_to_map(_JWT, Modules, Fields) -> {Modules, Fields}. erlang-jose-1.10.1/src/jose.app.src0000644000232200023220000000104513605433351017370 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet {application, jose, [ {description, "JSON Object Signing and Encryption (JOSE) for Erlang and Elixir."}, {vsn, "1.10.1"}, {id, "git"}, {mod, {'jose_app', []}}, {registered, []}, {applications, [ kernel, stdlib, crypto, asn1, public_key ]}, {modules, []}, {maintainers, ["Andrew Bennett"]}, {licenses, ["MIT"]}, {links, [{"Github", "https://github.com/potatosalad/erlang-jose"}]}, {env, [{crypto_fallback, true}]} ]}. erlang-jose-1.10.1/src/jose_xchacha20_poly1305_crypto.erl0000644000232200023220000000236113605433351023403 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 14 Sep 2019 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_xchacha20_poly1305_crypto). -behaviour(jose_xchacha20_poly1305). %% jose_xchacha20_poly1305 callbacks -export([decrypt/5]). -export([encrypt/4]). -export([authenticate/3]). -export([verify/4]). %%==================================================================== %% jose_xchacha20_poly1305 callbacks %%==================================================================== decrypt(CipherText, CipherTag, AAD, IV, CEK) -> crypto:block_decrypt(xchacha20_poly1305, CEK, IV, {AAD, CipherText, CipherTag}). encrypt(PlainText, AAD, IV, CEK) -> crypto:block_encrypt(xchacha20_poly1305, CEK, IV, {AAD, PlainText}). authenticate(Message, Key, Nonce) -> jose_jwa_xchacha20_poly1305:authenticate(Message, Key, Nonce). verify(MAC, Message, Key, Nonce) -> jose_jwa_xchacha20_poly1305:verify(MAC, Message, Key, Nonce). erlang-jose-1.10.1/src/jose_sup.erl0000644000232200023220000000261613605433351017500 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 06 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_sup). -behaviour(supervisor). -define(SERVER, ?MODULE). %% API -export([start_link/0]). %% Supervisor callbacks -export([init/1]). %% Helper macro for declaring children of supervisor -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). %%%=================================================================== %%% API functions %%%=================================================================== start_link() -> supervisor:start_link({local, ?SERVER}, ?MODULE, []). %%%=================================================================== %%% Supervisor callbacks %%%=================================================================== %% @private init([]) -> ChildSpecs = [ ?CHILD(jose_server, worker) ], Restart = {one_for_one, 10, 10}, {ok, {Restart, ChildSpecs}}. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/src/jose_app.erl0000644000232200023220000000156613605433351017454 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 06 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_app). -behaviour(application). %% Application callbacks -export([start/2]). -export([stop/1]). -export([config_change/3]). %%%=================================================================== %%% Application callbacks %%%=================================================================== start(_Type, _Args) -> jose_sup:start_link(). stop(_State) -> ok. config_change(_Changed, _New, _Removed) -> jose_server:config_change(). erlang-jose-1.10.1/src/jose_curve448.erl0000644000232200023220000000755513605433351020264 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 02 Jan 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_curve448). -callback eddsa_keypair() -> {PublicKey::binary(), SecretKey::binary()}. -callback eddsa_keypair(Seed::binary()) -> {PublicKey::binary(), SecretKey::binary()}. -callback eddsa_secret_to_public(SecretKey::binary()) -> PublicKey::binary(). -callback ed448_sign(Message::binary(), SecretKey::binary()) -> Signature::binary(). -callback ed448_sign(Message::binary(), SecretKey::binary(), Context::binary()) -> Signature::binary(). -callback ed448_verify(Signature::binary(), Message::binary(), PublicKey::binary()) -> boolean(). -callback ed448_verify(Signature::binary(), Message::binary(), PublicKey::binary(), Context::binary()) -> boolean(). -callback ed448ph_sign(Message::binary(), SecretKey::binary()) -> Signature::binary(). -callback ed448ph_sign(Message::binary(), SecretKey::binary(), Context::binary()) -> Signature::binary(). -callback ed448ph_verify(Signature::binary(), Message::binary(), PublicKey::binary()) -> boolean(). -callback ed448ph_verify(Signature::binary(), Message::binary(), PublicKey::binary(), Context::binary()) -> boolean(). -callback x448_keypair() -> {PublicKey::binary(), SecretKey::binary()}. -callback x448_keypair(Seed::binary()) -> {PublicKey::binary(), SecretKey::binary()}. -callback x448_secret_to_public(SecretKey::binary()) -> PublicKey::binary(). -callback x448_shared_secret(MySecretKey::binary(), YourPublicKey::binary()) -> SharedSecret::binary(). %% jose_curve448 callbacks -export([eddsa_keypair/0]). -export([eddsa_keypair/1]). -export([eddsa_secret_to_public/1]). -export([ed448_sign/2]). -export([ed448_sign/3]). -export([ed448_verify/3]). -export([ed448_verify/4]). -export([ed448ph_sign/2]). -export([ed448ph_sign/3]). -export([ed448ph_verify/3]). -export([ed448ph_verify/4]). -export([x448_keypair/0]). -export([x448_keypair/1]). -export([x448_secret_to_public/1]). -export([x448_shared_secret/2]). %% Macros -define(JOSE_CURVE448, (jose:curve448_module())). %%==================================================================== %% jose_curve448 callbacks %%==================================================================== % EdDSA eddsa_keypair() -> ?JOSE_CURVE448:eddsa_keypair(). eddsa_keypair(Seed) -> ?JOSE_CURVE448:eddsa_keypair(Seed). eddsa_secret_to_public(SecretKey) -> ?JOSE_CURVE448:eddsa_secret_to_public(SecretKey). % Ed448 ed448_sign(Message, SecretKey) -> ?JOSE_CURVE448:ed448_sign(Message, SecretKey). ed448_sign(Message, SecretKey, Context) -> ?JOSE_CURVE448:ed448_sign(Message, SecretKey, Context). ed448_verify(Signature, Message, PublicKey) -> ?JOSE_CURVE448:ed448_verify(Signature, Message, PublicKey). ed448_verify(Signature, Message, PublicKey, Context) -> ?JOSE_CURVE448:ed448_verify(Signature, Message, PublicKey, Context). % Ed448ph ed448ph_sign(Message, SecretKey) -> ?JOSE_CURVE448:ed448ph_sign(Message, SecretKey). ed448ph_sign(Message, SecretKey, Context) -> ?JOSE_CURVE448:ed448ph_sign(Message, SecretKey, Context). ed448ph_verify(Signature, Message, PublicKey) -> ?JOSE_CURVE448:ed448ph_verify(Signature, Message, PublicKey). ed448ph_verify(Signature, Message, PublicKey, Context) -> ?JOSE_CURVE448:ed448ph_verify(Signature, Message, PublicKey, Context). % X448 x448_keypair() -> ?JOSE_CURVE448:x448_keypair(). x448_keypair(Seed) -> ?JOSE_CURVE448:x448_keypair(Seed). x448_secret_to_public(SecretKey) -> ?JOSE_CURVE448:x448_secret_to_public(SecretKey). x448_shared_secret(MySecretKey, YourPublicKey) -> ?JOSE_CURVE448:x448_shared_secret(MySecretKey, YourPublicKey). erlang-jose-1.10.1/src/jose_server.erl0000644000232200023220000006522613605433351020205 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 13 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_server). -behaviour(gen_server). -include_lib("public_key/include/public_key.hrl"). -define(SERVER, ?MODULE). %% API -export([start_link/0]). -export([config_change/0]). -export([chacha20_poly1305_module/1]). -export([curve25519_module/1]). -export([curve448_module/1]). -export([json_module/1]). -export([sha3_module/1]). -export([xchacha20_poly1305_module/1]). %% gen_server callbacks -export([init/1]). -export([handle_call/3]). -export([handle_cast/2]). -export([handle_info/2]). -export([terminate/2]). -export([code_change/3]). -define(CRYPTO_FALLBACK, application:get_env(jose, crypto_fallback, false)). -define(TAB, jose_jwa). -define(POISON_MAP, #{ <<"a">> => 1, <<"b">> => 2, <<"c">> => #{ <<"d">> => 3, <<"e">> => 4 } }). -define(POISON_BIN, <<"{\"a\":1,\"b\":2,\"c\":{\"d\":3,\"e\":4}}">>). %% Types -record(state, {}). %%%=================================================================== %%% API functions %%%=================================================================== start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). config_change() -> gen_server:call(?SERVER, config_change). chacha20_poly1305_module(ChaCha20Poly1305Module) when is_atom(ChaCha20Poly1305Module) -> gen_server:call(?SERVER, {chacha20_poly1305_module, ChaCha20Poly1305Module}). curve25519_module(Curve25519Module) when is_atom(Curve25519Module) -> gen_server:call(?SERVER, {curve25519_module, Curve25519Module}). curve448_module(Curve448Module) when is_atom(Curve448Module) -> gen_server:call(?SERVER, {curve448_module, Curve448Module}). json_module(JSONModule) when is_atom(JSONModule) -> gen_server:call(?SERVER, {json_module, JSONModule}). sha3_module(SHA3Module) when is_atom(SHA3Module) -> gen_server:call(?SERVER, {sha3_module, SHA3Module}). xchacha20_poly1305_module(XChaCha20Poly1305Module) when is_atom(XChaCha20Poly1305Module) -> gen_server:call(?SERVER, {xchacha20_poly1305_module, XChaCha20Poly1305Module}). %%%=================================================================== %%% gen_server callbacks %%%=================================================================== %% @private init([]) -> ?TAB = ets:new(?TAB, [ named_table, public, ordered_set, {read_concurrency, true} ]), ok = support_check(), {ok, #state{}}. %% @private handle_call(config_change, _From, State) -> {reply, support_check(), State}; handle_call({chacha20_poly1305_module, M}, _From, State) -> ChaCha20Poly1305Module = check_chacha20_poly1305_module(M), Entries = lists:flatten(check_crypto(?CRYPTO_FALLBACK, [{chacha20_poly1305_module, ChaCha20Poly1305Module}])), _ = ets:select_delete(?TAB, [{{{cipher, '_'}, '_'}, [], [true]}]), true = ets:insert(?TAB, Entries), {reply, ok, State}; handle_call({curve25519_module, M}, _From, State) -> Curve25519Module = check_curve25519_module(M), true = ets:insert(?TAB, {curve25519_module, Curve25519Module}), {reply, ok, State}; handle_call({curve448_module, M}, _From, State) -> Curve448Module = check_curve448_module(M), true = ets:insert(?TAB, {curve448_module, Curve448Module}), {reply, ok, State}; handle_call({json_module, M}, _From, State) -> JSONModule = check_json_module(M), true = ets:insert(?TAB, {json_module, JSONModule}), {reply, ok, State}; handle_call({sha3_module, M}, _From, State) -> SHA3Module = check_sha3_module(M), true = ets:insert(?TAB, {sha3_module, SHA3Module}), {reply, ok, State}; handle_call({xchacha20_poly1305_module, M}, _From, State) -> XChaCha20Poly1305Module = check_xchacha20_poly1305_module(M), Entries = lists:flatten(check_crypto(?CRYPTO_FALLBACK, [{xchacha20_poly1305_module, XChaCha20Poly1305Module}])), _ = ets:select_delete(?TAB, [{{{cipher, '_'}, '_'}, [], [true]}]), true = ets:insert(?TAB, Entries), {reply, ok, State}; handle_call(_Request, _From, State) -> {reply, ignore, State}. %% @private handle_cast(_Request, State) -> {noreply, State}. %% @private handle_info(_Info, State) -> {noreply, State}. %% @private terminate(_Reason, _State) -> ok. %% @private code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private support_check() -> Fallback = ?CRYPTO_FALLBACK, Entries = lists:flatten(lists:foldl(fun(Check, Acc) -> Check(Fallback, Acc) end, [], [ fun check_ec_key_mode/2, fun check_chacha20_poly1305/2, fun check_xchacha20_poly1305/2, fun check_curve25519/2, fun check_curve448/2, fun check_json/2, fun check_sha3/2, fun check_crypto/2, fun check_public_key/2 ])), true = ets:delete_all_objects(?TAB), true = ets:insert(?TAB, Entries), ok. %%%------------------------------------------------------------------- %%% Internal check functions %%%------------------------------------------------------------------- %% @private check_ec_key_mode(_Fallback, Entries) -> ECPEMEntry = { 'ECPrivateKey', << 48,119,2,1,1,4,32,104,152,88,12,19,82,251,156,171,31,222,207, 0,76,115,88,210,229,36,106,137,192,81,153,154,254,226,38,247, 70,226,157,160,10,6,8,42,134,72,206,61,3,1,7,161,68,3,66,0,4, 46,75,29,46,150,77,222,40,220,159,244,193,125,18,190,254,216, 38,191,11,52,115,159,213,230,77,27,131,94,17,46,21,186,71,62, 36,225,0,90,21,186,235,132,152,229,13,189,196,121,64,84,64, 229,173,12,24,23,127,175,67,247,29,139,91 >>, not_encrypted }, case public_key:pem_entry_decode(ECPEMEntry) of #'ECPrivateKey'{ privateKey = PrivateKey, publicKey = PublicKey } when is_list(PrivateKey) andalso is_tuple(PublicKey) -> [{ec_key_mode, list} | Entries]; #'ECPrivateKey'{ privateKey = PrivateKey, publicKey = PublicKey } when is_binary(PrivateKey) andalso is_binary(PublicKey) -> [{ec_key_mode, binary} | Entries] end. %% @private check_chacha20_poly1305(false, Entries) -> check_chacha20_poly1305(jose_chacha20_poly1305_unsupported, Entries); check_chacha20_poly1305(true, Entries) -> check_chacha20_poly1305(jose_jwa_chacha20_poly1305, Entries); check_chacha20_poly1305(Fallback, Entries) -> true = ets:delete_object(?TAB, {chacha20_poly1305_module, jose_jwa_chacha20_poly1305}), true = ets:delete_object(?TAB, {chacha20_poly1305_module, jose_chacha20_poly1305_unsupported}), ChaCha20Poly1305Module = case ets:lookup(?TAB, chacha20_poly1305_module) of [{chacha20_poly1305_module, M}] when is_atom(M) -> M; [] -> case application:get_env(jose, chacha20_poly1305_module, undefined) of undefined -> check_chacha20_poly1305_modules(Fallback, [crypto, libsodium]); M when is_atom(M) -> check_chacha20_poly1305_module(M) end end, [{chacha20_poly1305_module, ChaCha20Poly1305Module} | Entries]. %% @private check_chacha20_poly1305_module(crypto) -> jose_chacha20_poly1305_crypto; check_chacha20_poly1305_module(libsodium) -> jose_chacha20_poly1305_libsodium; check_chacha20_poly1305_module(Module) when is_atom(Module) -> Module. %% @private check_chacha20_poly1305_modules(Fallback, [Module | Modules]) -> case code:ensure_loaded(Module) of {module, Module} -> _ = application:ensure_all_started(Module), M = check_chacha20_poly1305_module(Module), PT = crypto:strong_rand_bytes(8), CEK = crypto:strong_rand_bytes(32), IV = crypto:strong_rand_bytes(12), AAD = <<>>, try M:encrypt(PT, AAD, IV, CEK) of {CT, TAG} when is_binary(CT) andalso is_binary(TAG) -> try M:decrypt(CT, TAG, AAD, IV, CEK) of PT -> M; _ -> check_chacha20_poly1305_modules(Fallback, Modules) catch _:_ -> check_chacha20_poly1305_modules(Fallback, Modules) end; _ -> check_chacha20_poly1305_modules(Fallback, Modules) catch _:_ -> check_chacha20_poly1305_modules(Fallback, Modules) end; _ -> check_chacha20_poly1305_modules(Fallback, Modules) end; check_chacha20_poly1305_modules(Fallback, []) -> Fallback. %% @private check_curve25519(false, Entries) -> check_curve25519(jose_curve25519_unsupported, Entries); check_curve25519(true, Entries) -> check_curve25519(jose_jwa_curve25519, Entries); check_curve25519(Fallback, Entries) -> true = ets:delete_object(?TAB, {curve25519_module, jose_jwa_curve25519}), true = ets:delete_object(?TAB, {curve25519_module, jose_curve25519_unsupported}), Curve25519Module = case ets:lookup(?TAB, curve25519_module) of [{curve25519_module, M}] when is_atom(M) -> M; [] -> case application:get_env(jose, curve25519_module, undefined) of undefined -> check_curve25519_modules(Fallback, [libdecaf, libsodium]); M when is_atom(M) -> check_curve25519_module(M) end end, [{curve25519_module, Curve25519Module} | Entries]. %% @private check_curve25519_module(libdecaf) -> jose_curve25519_libdecaf; check_curve25519_module(libsodium) -> jose_curve25519_libsodium; check_curve25519_module(Module) when is_atom(Module) -> Module. %% @private check_curve25519_modules(Fallback, [Module | Modules]) -> case code:ensure_loaded(Module) of {module, Module} -> _ = application:ensure_all_started(Module), check_curve25519_module(Module); _ -> check_curve25519_modules(Fallback, Modules) end; check_curve25519_modules(Fallback, []) -> Fallback. %% @private check_curve448(false, Entries) -> check_curve448(jose_curve448_unsupported, Entries); check_curve448(true, Entries) -> check_curve448(jose_jwa_curve448, Entries); check_curve448(Fallback, Entries) -> true = ets:delete_object(?TAB, {curve448_module, jose_jwa_curve448}), true = ets:delete_object(?TAB, {curve448_module, jose_curve448_unsupported}), Curve448Module = case ets:lookup(?TAB, curve448_module) of [{curve448_module, M}] when is_atom(M) -> M; [] -> case application:get_env(jose, curve448_module, undefined) of undefined -> check_curve448_modules(Fallback, [libdecaf]); M when is_atom(M) -> check_curve448_module(M) end end, [{curve448_module, Curve448Module} | Entries]. %% @private check_curve448_module(libdecaf) -> jose_curve448_libdecaf; check_curve448_module(Module) when is_atom(Module) -> Module. %% @private check_curve448_modules(Fallback, [Module | Modules]) -> case code:ensure_loaded(Module) of {module, Module} -> _ = application:ensure_all_started(Module), check_curve448_module(Module); _ -> check_curve448_modules(Fallback, Modules) end; check_curve448_modules(Fallback, []) -> Fallback. %% @private check_json(_Fallback, Entries) -> JSONModule = case ets:lookup(?TAB, json_module) of [{json_module, M}] when is_atom(M) -> M; [] -> case application:get_env(jose, json_module, undefined) of undefined -> case code:ensure_loaded(elixir) of {module, elixir} -> check_json_modules([ojson, 'Elixir.Jason', 'Elixir.Poison', jiffy, jsone, jsx]); _ -> check_json_modules([ojson, jiffy, jsone, jsx]) end; M when is_atom(M) -> check_json_module(M) end end, [{json_module, JSONModule} | Entries]. %% @private check_json_module(jiffy) -> jose_json_jiffy; check_json_module(jsx) -> jose_json_jsx; check_json_module(jsone) -> jose_json_jsone; check_json_module(ojson) -> jose_json_ojson; check_json_module('Elixir.Jason') -> jose_json_jason; check_json_module('Elixir.Poison') -> Map = ?POISON_MAP, Bin = ?POISON_BIN, case jose_json_poison:encode(Map) of Bin -> jose_json_poison; _ -> check_json_module('Elixir.JOSE.Poison') end; check_json_module('Elixir.JOSE.Poison') -> Map = ?POISON_MAP, Bin = ?POISON_BIN, case code:ensure_loaded('Elixir.JOSE.Poison') of {module, 'Elixir.JOSE.Poison'} -> try jose_json_poison_lexical_encoder:encode(Map) of Bin -> jose_json_poison_lexical_encoder; _ -> check_json_module(jose_json_poison_compat_encoder) catch _:_ -> check_json_module(jose_json_poison_compat_encoder) end; _ -> check_json_module(jose_json_poison_compat_encoder) end; check_json_module(jose_json_poison_compat_encoder) -> Map = ?POISON_MAP, Bin = ?POISON_BIN, try jose_json_poison_compat_encoder:encode(Map) of Bin -> jose_json_poison_compat_encoder; _ -> jose_json_poison catch _:_ -> jose_json_poison end; check_json_module(Module) when is_atom(Module) -> Module. %% @private check_json_modules([Module | Modules]) -> case code:ensure_loaded(Module) of {module, Module} -> _ = application:ensure_all_started(Module), check_json_module(Module); _ -> check_json_modules(Modules) end; check_json_modules([]) -> jose_json_unsupported. %% @private check_sha3(false, Entries) -> check_sha3(jose_sha3_unsupported, Entries); check_sha3(true, Entries) -> check_sha3(jose_jwa_sha3, Entries); check_sha3(Fallback, Entries) -> true = ets:delete_object(?TAB, {sha3_module, jose_jwa_sha3}), true = ets:delete_object(?TAB, {sha3_module, jose_sha3_unsupported}), SHA3Module = case ets:lookup(?TAB, sha3_module) of [{sha3_module, M}] when is_atom(M) -> M; [] -> case application:get_env(jose, sha3_module, undefined) of undefined -> check_sha3_modules(Fallback, [keccakf1600, libdecaf]); M when is_atom(M) -> check_sha3_module(M) end end, [{sha3_module, SHA3Module} | Entries]. %% @private check_sha3_module(keccakf1600) -> check_sha3_module(jose_sha3_keccakf1600); check_sha3_module(libdecaf) -> check_sha3_module(jose_sha3_libdecaf); check_sha3_module(jose_sha3_keccakf1600) -> _ = code:ensure_loaded(keccakf1600), case erlang:function_exported(keccakf1600, hash, 3) of false -> % version < 2 check_sha3_module(jose_sha3_keccakf1600_driver); true -> % version >= 2 check_sha3_module(jose_sha3_keccakf1600_nif) end; check_sha3_module(Module) when is_atom(Module) -> Module. %% @private check_sha3_modules(Fallback, [Module | Modules]) -> case code:ensure_loaded(Module) of {module, Module} -> _ = application:ensure_all_started(Module), check_sha3_module(Module); _ -> check_sha3_modules(Fallback, Modules) end; check_sha3_modules(Fallback, []) -> Fallback. %% @private check_crypto(false, Entries) -> check_crypto(jose_jwa_unsupported, Entries); check_crypto(true, Entries) -> check_crypto(jose_jwa_aes, Entries); check_crypto(Fallback, Entries) -> Ciphers = [ aes_cbc, aes_ecb, aes_gcm ], KeySizes = [ 128, 192, 256 ], CipherEntries0 = [begin case has_cipher(Cipher, KeySize) of false -> {{cipher, {Cipher, KeySize}}, {Fallback, {Cipher, KeySize}}}; {true, CryptoCipher} -> {{cipher, {Cipher, KeySize}}, {crypto, CryptoCipher}} end end || Cipher <- Ciphers, KeySize <- KeySizes], CipherEntries1 = case lists:keyfind(chacha20_poly1305_module, 1, Entries) of {chacha20_poly1305_module, jose_chacha20_poly1305_unsupported} -> CipherEntries0 ++ [{{cipher, {chacha20_poly1305, 256}}, {Fallback, {chacha20_poly1305, 256}}}]; _ -> CipherEntries0 ++ [{{cipher, {chacha20_poly1305, 256}}, {jose_chacha20_poly1305, {chacha20_poly1305, 256}}}] end, CipherEntries2 = case lists:keyfind(xchacha20_poly1305_module, 1, Entries) of {xchacha20_poly1305_module, jose_xchacha20_poly1305_unsupported} -> CipherEntries1 ++ [{{cipher, {xchacha20_poly1305, 256}}, {Fallback, {xchacha20_poly1305, 256}}}]; _ -> CipherEntries1 ++ [{{cipher, {xchacha20_poly1305, 256}}, {jose_xchacha20_poly1305, {xchacha20_poly1305, 256}}}] end, [CipherEntries2 | Entries]. %% @private check_public_key(Fallback, Entries) -> RSACrypt = check_rsa_crypt(Fallback), RSASign = check_rsa_sign(Fallback), [RSACrypt, RSASign | Entries]. %% @private check_rsa_crypt(false) -> check_rsa_crypt(jose_jwa_unsupported); check_rsa_crypt(true) -> check_rsa_crypt(jose_jwa_pkcs1); check_rsa_crypt(Fallback) -> Algorithms = [ %% Algorithm, LegacyOptions, FutureOptions {rsa1_5, [{rsa_pad, rsa_pkcs1_padding}], [{rsa_padding, rsa_pkcs1_padding}]}, {rsa_oaep, [{rsa_pad, rsa_pkcs1_oaep_padding}], [{rsa_padding, rsa_pkcs1_oaep_padding}]}, {rsa_oaep_256, notsup, [{rsa_padding, rsa_pkcs1_oaep_padding}, {rsa_oaep_md, sha256}]} ], _ = code:ensure_loaded(public_key), _ = application:ensure_all_started(public_key), Legacy = case erlang:function_exported(public_key, sign, 4) of false -> legacy; true -> future end, CryptEntries = [begin case has_rsa_crypt(Algorithm, Legacy, LegacyOptions, FutureOptions) of false -> {{rsa_crypt, Algorithm}, {Fallback, FutureOptions}}; {true, Module, Options} -> {{rsa_crypt, Algorithm}, {Module, Options}} end end || {Algorithm, LegacyOptions, FutureOptions} <- Algorithms], CryptEntries. %% @private check_rsa_sign(false) -> check_rsa_sign(jose_jwa_unsupported); check_rsa_sign(true) -> check_rsa_sign(jose_jwa_pkcs1); check_rsa_sign(Fallback) -> Paddings = [ rsa_pkcs1_padding, rsa_pkcs1_pss_padding ], _ = code:ensure_loaded(public_key), _ = application:ensure_all_started(public_key), Legacy = case erlang:function_exported(public_key, sign, 4) of false -> legacy; true -> future end, SignEntries = [begin case has_rsa_sign(Padding, Legacy, sha) of false -> {{rsa_sign, Padding}, {Fallback, [{rsa_padding, Padding}]}}; {true, Module} -> {{rsa_sign, Padding}, {Module, undefined}}; {true, Module, Options} -> {{rsa_sign, Padding}, {Module, Options}} end end || Padding <- Paddings], SignEntries. %% @private check_xchacha20_poly1305(false, Entries) -> check_xchacha20_poly1305(jose_xchacha20_poly1305_unsupported, Entries); check_xchacha20_poly1305(true, Entries) -> check_xchacha20_poly1305(jose_jwa_xchacha20_poly1305, Entries); check_xchacha20_poly1305(Fallback, Entries) -> true = ets:delete_object(?TAB, {xchacha20_poly1305_module, jose_jwa_xchacha20_poly1305}), true = ets:delete_object(?TAB, {xchacha20_poly1305_module, jose_xchacha20_poly1305_unsupported}), ChaCha20Poly1305Module = case ets:lookup(?TAB, xchacha20_poly1305_module) of [{xchacha20_poly1305_module, M}] when is_atom(M) -> M; [] -> case application:get_env(jose, xchacha20_poly1305_module, undefined) of undefined -> check_xchacha20_poly1305_modules(Fallback, [crypto]); M when is_atom(M) -> check_xchacha20_poly1305_module(M) end end, [{xchacha20_poly1305_module, ChaCha20Poly1305Module} | Entries]. %% @private check_xchacha20_poly1305_module(crypto) -> jose_xchacha20_poly1305_crypto; check_xchacha20_poly1305_module(Module) when is_atom(Module) -> Module. %% @private check_xchacha20_poly1305_modules(Fallback, [Module | Modules]) -> case code:ensure_loaded(Module) of {module, Module} -> _ = application:ensure_all_started(Module), M = check_xchacha20_poly1305_module(Module), PT = crypto:strong_rand_bytes(8), CEK = crypto:strong_rand_bytes(32), IV = crypto:strong_rand_bytes(24), AAD = <<>>, try M:encrypt(PT, AAD, IV, CEK) of {CT, TAG} when is_binary(CT) andalso is_binary(TAG) -> try M:decrypt(CT, TAG, AAD, IV, CEK) of PT -> M; _ -> check_xchacha20_poly1305_modules(Fallback, Modules) catch _:_ -> check_xchacha20_poly1305_modules(Fallback, Modules) end; _ -> check_xchacha20_poly1305_modules(Fallback, Modules) catch _:_ -> check_xchacha20_poly1305_modules(Fallback, Modules) end; _ -> check_xchacha20_poly1305_modules(Fallback, Modules) end; check_xchacha20_poly1305_modules(Fallback, []) -> Fallback. %% @private has_cipher(aes_cbc, KeySize) -> Key = << 0:KeySize >>, IV = << 0:128 >>, PlainText = jose_jwa_pkcs7:pad(<<>>), case has_block_cipher(aes_cbc, {Key, IV, PlainText}) of false -> Cipher = list_to_atom("aes_cbc" ++ integer_to_list(KeySize)), has_block_cipher(Cipher, {Key, IV, PlainText}); Other -> Other end; has_cipher(aes_ecb, KeySize) -> Key = << 0:KeySize >>, PlainText = jose_jwa_pkcs7:pad(<<>>), has_block_cipher(aes_ecb, {Key, PlainText}); has_cipher(aes_gcm, KeySize) -> Key = << 0:KeySize >>, IV = << 0:96 >>, AAD = <<>>, PlainText = jose_jwa_pkcs7:pad(<<>>), has_block_cipher(aes_gcm, {Key, IV, AAD, PlainText}). %% @private has_block_cipher(Cipher, {Key, PlainText}) -> case catch crypto:block_encrypt(Cipher, Key, PlainText) of CipherText when is_binary(CipherText) -> case catch crypto:block_decrypt(Cipher, Key, CipherText) of PlainText -> {true, Cipher}; _ -> false end; _ -> false end; has_block_cipher(Cipher, {Key, IV, PlainText}) -> case catch crypto:block_encrypt(Cipher, Key, IV, PlainText) of CipherText when is_binary(CipherText) -> case catch crypto:block_decrypt(Cipher, Key, IV, CipherText) of PlainText -> {true, Cipher}; _ -> false end; _ -> false end; has_block_cipher(Cipher, {Key, IV, AAD, PlainText}) -> case catch crypto:block_encrypt(Cipher, Key, IV, {AAD, PlainText}) of {CipherText, CipherTag} when is_binary(CipherText) andalso is_binary(CipherTag) -> case catch crypto:block_decrypt(Cipher, Key, IV, {AAD, CipherText, CipherTag}) of PlainText -> {true, Cipher}; _ -> false end; _ -> false end. %% @private has_rsa_crypt(Algorithm, future, _LegacyOptions, FutureOptions) -> PlainText = << 0:8 >>, PublicKey = rsa_public_key(), case catch public_key:encrypt_public(PlainText, PublicKey, FutureOptions) of CipherText when is_binary(CipherText) -> PrivateKey = rsa_private_key(), case catch public_key:decrypt_private(CipherText, PrivateKey, FutureOptions) of PlainText -> case catch public_key:decrypt_private(rsa_ciphertext(Algorithm), PrivateKey, FutureOptions) of <<"ciphertext">> -> {true, public_key, FutureOptions}; _ -> false end; _ -> false end; _ -> false end; has_rsa_crypt(_Algorithm, legacy, notsup, _FutureOptions) -> false; has_rsa_crypt(Algorithm, legacy, LegacyOptions, _FutureOptions) -> PlainText = << 0:8 >>, PublicKey = rsa_public_key(), case catch public_key:encrypt_public(PlainText, PublicKey, LegacyOptions) of CipherText when is_binary(CipherText) -> PrivateKey = rsa_private_key(), case catch public_key:decrypt_private(CipherText, PrivateKey, LegacyOptions) of PlainText -> case catch public_key:decrypt_private(rsa_ciphertext(Algorithm), PrivateKey, LegacyOptions) of <<"ciphertext">> -> {true, public_key, LegacyOptions}; _ -> false end; _ -> false end; _ -> false end. %% @private has_rsa_sign(Padding, future, DigestType) -> Message = << 0:8 >>, PrivateKey = rsa_private_key(), Options = [{rsa_padding, Padding}], case catch public_key:sign(Message, DigestType, PrivateKey, Options) of Signature when is_binary(Signature) -> PublicKey = rsa_public_key(), case catch public_key:verify(Message, DigestType, Signature, PublicKey, Options) of true -> {true, public_key, Options}; _ -> false end; _ -> false end; has_rsa_sign(rsa_pkcs1_padding, legacy, DigestType) -> Message = << 0:8 >>, PrivateKey = rsa_private_key(), case catch public_key:sign(Message, DigestType, PrivateKey) of Signature when is_binary(Signature) -> PublicKey = rsa_public_key(), case catch public_key:verify(Message, DigestType, Signature, PublicKey) of true -> {true, public_key}; _ -> false end; _ -> false end; has_rsa_sign(_Padding, legacy, _DigestType) -> false. %% @private read_pem_key(PEM) -> public_key:pem_entry_decode(hd(public_key:pem_decode(PEM))). %% @private rsa_ciphertext(rsa1_5) -> << 16#67, 16#3F, 16#BF, 16#D4, 16#93, 16#1E, 16#6C, 16#54, 16#67, 16#DE, 16#29, 16#3C, 16#71, 16#5F, 16#95, 16#BE, 16#69, 16#99, 16#D3, 16#6C, 16#E4, 16#81, 16#1E, 16#49, 16#BE, 16#5D, 16#91, 16#85, 16#E7, 16#1D, 16#04, 16#C5, 16#38, 16#0A, 16#6F, 16#3F, 16#32, 16#2C, 16#3D, 16#67, 16#53, 16#B1, 16#EA, 16#D7, 16#2E, 16#ED, 16#6A, 16#7A, 16#EB, 16#49, 16#79, 16#71, 16#CA, 16#F5, 16#71, 16#67, 16#FA, 16#8B, 16#B8, 16#A8, 16#30, 16#59, 16#2E, 16#88, 16#98, 16#19, 16#AE, 16#B2, 16#94, 16#BA, 16#6E, 16#D2, 16#EF, 16#28, 16#BE, 16#04, 16#4F, 16#90, 16#77, 16#CA, 16#3D, 16#11, 16#2B, 16#E7, 16#17, 16#D8, 16#89, 16#7F, 16#EC, 16#7A, 16#2C, 16#70, 16#A5, 16#08, 16#FB, 16#5B >>; rsa_ciphertext(rsa_oaep) -> << 16#B8, 16#F7, 16#0C, 16#A8, 16#F8, 16#30, 16#2A, 16#E9, 16#68, 16#8A, 16#DB, 16#3E, 16#5D, 16#AE, 16#84, 16#A7, 16#16, 16#FA, 16#9D, 16#E2, 16#FC, 16#81, 16#F7, 16#DF, 16#A8, 16#DB, 16#8F, 16#4F, 16#92, 16#A1, 16#51, 16#9E, 16#6B, 16#C5, 16#36, 16#CE, 16#93, 16#10, 16#11, 16#D9, 16#D5, 16#C2, 16#C9, 16#85, 16#14, 16#EF, 16#D5, 16#C3, 16#AC, 16#63, 16#BE, 16#49, 16#FA, 16#02, 16#1A, 16#FC, 16#3D, 16#D0, 16#2C, 16#83, 16#C5, 16#76, 16#1D, 16#F5, 16#FA, 16#A0, 16#D7, 16#42, 16#ED, 16#3F, 16#A4, 16#12, 16#32, 16#14, 16#93, 16#51, 16#79, 16#2E, 16#40, 16#FB, 16#14, 16#18, 16#DF, 16#30, 16#62, 16#9F, 16#F3, 16#59, 16#5D, 16#83, 16#0F, 16#4A, 16#8F, 16#9B, 16#3F, 16#39 >>; rsa_ciphertext(rsa_oaep_256) -> << 16#09, 16#24, 16#EA, 16#EB, 16#D4, 16#EF, 16#00, 16#BE, 16#8E, 16#02, 16#BE, 16#25, 16#24, 16#24, 16#18, 16#81, 16#8D, 16#7A, 16#A2, 16#EB, 16#F1, 16#BE, 16#5C, 16#DC, 16#D0, 16#71, 16#43, 16#09, 16#53, 16#12, 16#44, 16#AD, 16#8A, 16#CD, 16#F8, 16#45, 16#7F, 16#1F, 16#30, 16#B6, 16#54, 16#8E, 16#AB, 16#D2, 16#10, 16#14, 16#BC, 16#CE, 16#7A, 16#99, 16#DC, 16#A6, 16#8D, 16#16, 16#5A, 16#A0, 16#50, 16#3A, 16#93, 16#0E, 16#53, 16#4A, 16#B5, 16#6B, 16#51, 16#E8, 16#43, 16#8F, 16#BD, 16#2D, 16#E0, 16#63, 16#36, 16#24, 16#5B, 16#8D, 16#DD, 16#98, 16#AC, 16#37, 16#7C, 16#16, 16#DB, 16#03, 16#C8, 16#BD, 16#22, 16#D2, 16#15, 16#98, 16#91, 16#B7, 16#3C, 16#01, 16#CF, 16#0E >>. %% @private rsa_public_key() -> read_pem_key(<< "-----BEGIN PUBLIC KEY-----\n" "MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhAL/f1xISwDSm4m6sYHm6WD4WK2egfyfZ\n" "hd0w4iVeZvHjUurZVRVQojs7hZC7DKBfjShl6M7BT9j7gkaYOXlJHLhK6/J+Zr0C\n" "g6PMkkbejQltgr4fUzbG8zUBo7BMs4Xm0wIDAQAB\n" "-----END PUBLIC KEY-----\n" >>). %% @private rsa_private_key() -> read_pem_key(<< "-----BEGIN RSA PRIVATE KEY-----\n" "MIIBzAIBAAJhAL/f1xISwDSm4m6sYHm6WD4WK2egfyfZhd0w4iVeZvHjUurZVRVQ\n" "ojs7hZC7DKBfjShl6M7BT9j7gkaYOXlJHLhK6/J+Zr0Cg6PMkkbejQltgr4fUzbG\n" "8zUBo7BMs4Xm0wIDAQABAmEAiisNO7WG9SNLoPi+TEn061iZjvjTOAX60Io3/0LY\n" "jMzu07EHBN9Yw6CcENmxQPcsdIRlSKLlt+UeUdBES6Zoccek5fJl+gnqExeX2Av1\n" "v0Y8vIP2yejV7Pw+SrNxpY5ZAjEA+WMEZEgFrK8cPJmZLR9Kj3jvN5P+AmIKzg00\n" "VMW93rS+sdHmYQUStqBuu2XRw5SlAjEAxPZlLCZ83GrqdStcmChCFpflzCRyU/wC\n" "qVVP8QYfct49Cca3TyC8lCywwXI5s5wXAjA1JQK0lByRdiegSmM4GGj9NhpUT7db\n" "rqT60BmMzy7tHLtejYp4tmoMfRfb25DeCvkCMQCO+usQ9NOZUsfmzNaH4lmvew8n\n" "daHFE+F+uV6x8ibsRSZ8LVQuze33hsW9eEUo/HsCMQDKkImE3DSqHgwfKPjtecFH\n" "oftdsGQ4u+MUGkST94Hh8479oNYaNveCRDOTJ4GJjUE=\n" "-----END RSA PRIVATE KEY-----\n" >>). erlang-jose-1.10.1/src/jose_chacha20_poly1305.erl0000644000232200023220000000421313605433351021611 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 31 May 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_chacha20_poly1305). -behaviour(jose_block_encryptor). -type digest() :: << _:16 >>. -type key() :: << _:32 >>. -type nonce() :: << _:12 >>. -callback decrypt(CipherText, CipherTag, AAD, IV, Key) -> PlainText | error when CipherText :: binary(), CipherTag :: digest(), AAD :: binary(), IV :: nonce(), Key :: key(), PlainText :: binary(). -callback encrypt(PlainText, AAD, IV, Key) -> CipherText when PlainText :: binary(), AAD :: binary(), IV :: nonce(), Key :: key(), CipherText :: binary(). -callback authenticate(Message, Key, Nonce) -> MAC when Message :: binary(), Key :: key(), Nonce :: nonce(), MAC :: digest(). -callback verify(MAC, Message, Key, Nonce) -> boolean() when MAC :: digest(), Message :: binary(), Key :: key(), Nonce :: nonce(). %% jose_block_encryptor callbacks -export([block_decrypt/4]). -export([block_encrypt/4]). -export([authenticate/3]). -export([verify/4]). %% Macros -define(JOSE_CHACHA20_POLY1305, (jose:chacha20_poly1305_module())). %%==================================================================== %% jose_block_encryptor callbacks %%==================================================================== block_decrypt({chacha20_poly1305, 256}, Key, IV, {AAD, CipherText, CipherTag}) -> ?JOSE_CHACHA20_POLY1305:decrypt(CipherText, CipherTag, AAD, IV, Key). block_encrypt({chacha20_poly1305, 256}, Key, IV, {AAD, PlainText}) -> ?JOSE_CHACHA20_POLY1305:encrypt(PlainText, AAD, IV, Key). authenticate(Message, Key, Nonce) -> ?JOSE_CHACHA20_POLY1305:authenticate(Message, Key, Nonce). verify(MAC, Message, Key, Nonce) -> ?JOSE_CHACHA20_POLY1305:verify(MAC, Message, Key, Nonce). erlang-jose-1.10.1/src/jose_sha3_keccakf1600_nif.erl0000644000232200023220000000240013605433351022330 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 05 Feb 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_sha3_keccakf1600_nif). -behaviour(jose_sha3). %% jose_sha3 callbacks -export([sha3_224/1]). -export([sha3_256/1]). -export([sha3_384/1]). -export([sha3_512/1]). -export([shake128/2]). -export([shake256/2]). %%==================================================================== %% jose_sha3 callbacks %%==================================================================== sha3_224(InputBytes) -> keccakf1600:hash(sha3_224, InputBytes). sha3_256(InputBytes) -> keccakf1600:hash(sha3_256, InputBytes). sha3_384(InputBytes) -> keccakf1600:hash(sha3_384, InputBytes). sha3_512(InputBytes) -> keccakf1600:hash(sha3_512, InputBytes). shake128(InputBytes, OutputByteLen) -> keccakf1600:hash(shake128, InputBytes, OutputByteLen). shake256(InputBytes, OutputByteLen) -> keccakf1600:hash(shake256, InputBytes, OutputByteLen). erlang-jose-1.10.1/src/jose_public_key.erl0000644000232200023220000007727613605433351021035 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2017, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 18 May 2017 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_public_key). -include("jose_compat.hrl"). -include("jose_public_key.hrl"). %% API -export([cipher/3]). -export([decipher/2]). -export([encrypt_parameters/1]). -export([decrypt_parameters/1]). -export([der_decode/1]). -export([der_decode/2]). -export([der_encode/2]). -export([pem_decode/1]). -export([pem_encode/1]). -export([pem_entry_decode/1]). -export([pem_entry_decode/2]). -export([pem_entry_encode/2]). -export([pem_entry_encode/3]). %%==================================================================== %% API functions %%==================================================================== cipher(DecryptedDER, CipherInfo, Password) -> try pubkey_pem:cipher(DecryptedDER, CipherInfo, Password) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_cipher(DecryptedDER, CipherInfo, Password) of {true, EncryptedDER} -> EncryptedDER; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. decipher(Encrypted = {_, EncryptedDER, CipherInfo}, Password) -> try pubkey_pem:decipher(Encrypted, Password) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_decipher(EncryptedDER, CipherInfo, Password) of {true, DecryptedDER} -> DecryptedDER; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. encrypt_parameters(Arg = {Cipher, Params}) -> try pubkey_pbe:encrypt_parameters(Arg) catch ?COMPAT_CATCH(Class, Reason, ST) -> case encrypt_parameters(Cipher, Params) of {true, Result} -> Result; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. %% @private encrypt_parameters(_Cipher, #'PBES2-params'{} = Params) -> {ok, Der} ='PKCS-FRAME':encode('PBES2-params', Params), {true, #'EncryptedPrivateKeyInfo_encryptionAlgorithm'{algorithm = ?'id-PBES2', parameters = encode_handle_open_type_wrapper(Der)}}; encrypt_parameters(_, _) -> false. decrypt_parameters(Arg = #'EncryptedPrivateKeyInfo_encryptionAlgorithm'{algorithm = Oid, parameters = Param}) -> try pubkey_pbe:decrypt_parameters(Arg) catch ?COMPAT_CATCH(Class, Reason, ST) -> case decrypt_parameters(Oid, decode_handle_open_type_wrapper(Param)) of {true, Result} -> Result; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. %% @private decrypt_parameters(?'id-PBES2', DekParams) -> {ok, Params} = 'PKCS-FRAME':decode('PBES2-params', DekParams), case cipher(Params#'PBES2-params'.encryptionScheme) of {true, Cipher} -> {true, {Cipher, Params}}; false -> false end; decrypt_parameters(_, _) -> false. %% @private cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes128-CBC'}) -> {true, "AES-128-CBC"}; cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes192-CBC'}) -> {true, "AES-192-CBC"}; cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes256-CBC'}) -> {true, "AES-256-CBC"}; cipher(_) -> false. der_decode(DER) when is_binary(DER) -> Result = try_der_decode([ 'Certificate', 'RSAPrivateKey', 'RSAPublicKey', 'SubjectPublicKeyInfo', 'DSAPrivateKey', 'DHParameter', 'PrivateKeyInfo', 'EncryptedPrivateKeyInfo', 'CertificationRequest', 'ContentInfo', 'CertificateList', 'EcpkParameters', 'ECPrivateKey', {no_asn1, new_openssh} %% Temporarily in the prototype of this format ], DER), case Result of PrivateKeyInfo=#'PrivateKeyInfo'{} -> i2k(PrivateKeyInfo); SubjectPublicKeyInfo=#'SubjectPublicKeyInfo'{} -> i2k(SubjectPublicKeyInfo); Other -> Other end. der_decode(ASN1Type, DER) when is_atom(ASN1Type) andalso is_binary(DER) -> public_key:der_decode(ASN1Type, DER). der_encode(ASN1Type, Entity) when is_atom(ASN1Type) -> try public_key:der_encode(ASN1Type, Entity) catch ?COMPAT_CATCH(Class, Reason, ST) -> case der_enc(ASN1Type, Entity) of {true, DERBinary} -> DERBinary; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. pem_decode(PEMBinary) when is_binary(PEMBinary) -> try public_key:pem_decode(PEMBinary) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_dec(PEMBinary) of {true, PEMEntries} -> PEMEntries; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. pem_encode(PEMEntries) when is_list(PEMEntries) -> try public_key:pem_encode(PEMEntries) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_enc(PEMEntries) of {true, PEMBinary} -> PEMBinary; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. pem_entry_decode(PEMEntry) -> Result = try public_key:pem_entry_decode(PEMEntry) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_entry_dec(PEMEntry) of {true, DecodedPEMEntry} -> DecodedPEMEntry; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end, case Result of PrivateKeyInfo=#'PrivateKeyInfo'{} -> i2k(PrivateKeyInfo); SubjectPublicKeyInfo=#'SubjectPublicKeyInfo'{} -> i2k(SubjectPublicKeyInfo); Other -> Other end. pem_entry_decode(PEMEntry, Password) -> Result = try public_key:pem_entry_decode(PEMEntry, Password) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_entry_dec(PEMEntry, Password) of {true, DecodedPEMEntry} -> DecodedPEMEntry; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end, case Result of PrivateKeyInfo=#'PrivateKeyInfo'{} -> i2k(PrivateKeyInfo); SubjectPublicKeyInfo=#'SubjectPublicKeyInfo'{} -> i2k(SubjectPublicKeyInfo); Other -> Other end. pem_entry_encode(ASN1Type, Entity) -> try public_key:pem_entry_encode(ASN1Type, Entity) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_entry_enc(ASN1Type, Entity) of {true, PEMEntry} -> PEMEntry; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. pem_entry_encode(ASN1Type, Entity, Password) -> try public_key:pem_entry_encode(ASN1Type, Entity, Password) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_entry_enc(ASN1Type, Entity, Password) of {true, PEMEntry} -> PEMEntry; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private try_der_decode([ASN1Type | Rest], DER) -> try der_decode(ASN1Type, DER) of Result -> Result catch ?COMPAT_CATCH(error, Reason={badmatch, _}, ST) -> try_der_decode(Rest, DER, {error, Reason, ?COMPAT_GET_STACKTRACE(ST)}) end. %% @private try_der_decode([], _DER, {Class, Reason, Stacktrace}) -> erlang:raise(Class, Reason, Stacktrace); try_der_decode([ASN1Type | Rest], DER, _) -> try der_decode(ASN1Type, DER) of Result -> Result catch ?COMPAT_CATCH(error, Reason={badmatch, _}, ST) -> try_der_decode(Rest, DER, {error, Reason, ?COMPAT_GET_STACKTRACE(ST)}) end. %% @private der_enc('EdDSA25519PrivateKey', K=#'jose_EdDSA25519PrivateKey'{}) -> EncodedDER = public_key:der_encode('PrivateKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('EdDSA25519PublicKey', K=#'jose_EdDSA25519PublicKey'{}) -> EncodedDER = public_key:der_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('EdDSA448PrivateKey', K=#'jose_EdDSA448PrivateKey'{}) -> EncodedDER = public_key:der_encode('PrivateKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('EdDSA448PublicKey', K=#'jose_EdDSA448PublicKey'{}) -> EncodedDER = public_key:der_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('SubjectPublicKeyInfo', K) -> EncodedDER = public_key:der_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('X25519PrivateKey', K=#'jose_X25519PrivateKey'{}) -> EncodedDER = public_key:der_encode('PrivateKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('X25519PublicKey', K=#'jose_X25519PublicKey'{}) -> EncodedDER = public_key:der_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('X448PrivateKey', K=#'jose_X448PrivateKey'{}) -> EncodedDER = public_key:der_encode('PrivateKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('X448PublicKey', K=#'jose_X448PublicKey'{}) -> EncodedDER = public_key:der_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('PrivateKeyInfo', K) -> case K of #'jose_EdDSA25519PrivateKey'{} -> der_enc('EdDSA25519PrivateKey', K); #'jose_EdDSA448PrivateKey'{} -> der_enc('EdDSA448PrivateKey', K); #'jose_X25519PrivateKey'{} -> der_enc('X25519PrivateKey', K); #'jose_X448PrivateKey'{} -> der_enc('X448PrivateKey', K); #'ECPrivateKey'{} -> der_enc('ECPrivateKey', K); #'RSAPrivateKey'{} -> der_enc('RSAPrivateKey', K); _ -> false end; %% Compatibility between PKCS1 and PKCS8 versions of public_key der_enc('ECPrivateKey', K=#'ECPrivateKey'{}) -> EncodedDER = public_key:der_encode('PrivateKeyInfo', k2i(K)), {true, EncodedDER}; der_enc('RSAPrivateKey', K=#'RSAPrivateKey'{}) -> EncodedDER = public_key:der_encode('PrivateKeyInfo', k2i(K)), {true, EncodedDER}; der_enc(_, _) -> false. %% @private pem_dec(PEMBinary) -> pem_dec(pem_dec_split_bin(PEMBinary), []). %% @private pem_dec([], Entries) -> {true, lists:reverse(Entries)}; pem_dec([<<>>], Entries) -> {true, lists:reverse(Entries)}; pem_dec([<<>> | Lines], Entries) -> pem_dec(Lines, Entries); pem_dec([Start| Lines], Entries) -> case pem_end(Start) of undefined -> pem_dec(Lines, Entries); _End -> {Entry, RestLines} = pem_dec_join_entry(Lines, []), case pem_dec_entry(Start, Entry) of {true, Head} -> pem_dec(RestLines, [Head | Entries]); false -> false end end. %% @private pem_dec_entry(Start, Lines) -> Type = asn1_type(Start), Cs = erlang:iolist_to_binary(Lines), Decoded = base64:mime_decode(Cs), case Type of 'EncryptedPrivateKeyInfo'-> decode_encrypted_private_keyinfo(Decoded); _ -> {true, {Type, Decoded, not_encrypted}} end. %% @private decode_encrypted_private_keyinfo(Der) -> #'EncryptedPrivateKeyInfo'{encryptionAlgorithm = AlgorithmInfo, encryptedData = Data} = der_decode('EncryptedPrivateKeyInfo', Der), DecryptParams = decrypt_parameters(AlgorithmInfo), {true, {'PrivateKeyInfo', Data, DecryptParams}}. %% @private %% Ignore white space at end of line pem_dec_join_entry([<<"-----END ", _/binary>>| Lines], Entry) -> {lists:reverse(Entry), Lines}; pem_dec_join_entry([<<"-----END X509 CRL-----", _/binary>>| Lines], Entry) -> {lists:reverse(Entry), Lines}; pem_dec_join_entry([Line | Lines], Entry) -> pem_dec_join_entry(Lines, [Line | Entry]). %% @private pem_dec_split_bin(Bin) -> pem_dec_split_bin(0, Bin). %% @private pem_dec_split_bin(N, Bin) -> case Bin of <> -> [Line | pem_dec_split_bin(0, Rest)]; <> -> [Line | pem_dec_split_bin(0, Rest)]; <> -> [Line]; _ -> pem_dec_split_bin(N+1, Bin) end. %% @private asn1_type(<<"-----BEGIN CERTIFICATE-----">>) -> 'Certificate'; asn1_type(<<"-----BEGIN RSA PRIVATE KEY-----">>) -> 'RSAPrivateKey'; asn1_type(<<"-----BEGIN RSA PUBLIC KEY-----">>) -> 'RSAPublicKey'; asn1_type(<<"-----BEGIN PUBLIC KEY-----">>) -> 'SubjectPublicKeyInfo'; asn1_type(<<"-----BEGIN DSA PRIVATE KEY-----">>) -> 'DSAPrivateKey'; asn1_type(<<"-----BEGIN DH PARAMETERS-----">>) -> 'DHParameter'; asn1_type(<<"-----BEGIN PRIVATE KEY-----">>) -> 'PrivateKeyInfo'; asn1_type(<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>) -> 'EncryptedPrivateKeyInfo'; asn1_type(<<"-----BEGIN CERTIFICATE REQUEST-----">>) -> 'CertificationRequest'; asn1_type(<<"-----BEGIN PKCS7-----">>) -> 'ContentInfo'; asn1_type(<<"-----BEGIN X509 CRL-----">>) -> 'CertificateList'; asn1_type(<<"-----BEGIN EC PARAMETERS-----">>) -> 'EcpkParameters'; asn1_type(<<"-----BEGIN EC PRIVATE KEY-----">>) -> 'ECPrivateKey'; asn1_type(<<"-----BEGIN OPENSSH PRIVATE KEY-----">>) -> {no_asn1, new_openssh}. %% Temporarily in the prototype of this format %% @private pem_end(<<"-----BEGIN CERTIFICATE-----">>) -> <<"-----END CERTIFICATE-----">>; pem_end(<<"-----BEGIN RSA PRIVATE KEY-----">>) -> <<"-----END RSA PRIVATE KEY-----">>; pem_end(<<"-----BEGIN RSA PUBLIC KEY-----">>) -> <<"-----END RSA PUBLIC KEY-----">>; pem_end(<<"-----BEGIN PUBLIC KEY-----">>) -> <<"-----END PUBLIC KEY-----">>; pem_end(<<"-----BEGIN DSA PRIVATE KEY-----">>) -> <<"-----END DSA PRIVATE KEY-----">>; pem_end(<<"-----BEGIN DH PARAMETERS-----">>) -> <<"-----END DH PARAMETERS-----">>; pem_end(<<"-----BEGIN PRIVATE KEY-----">>) -> <<"-----END PRIVATE KEY-----">>; pem_end(<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>) -> <<"-----END ENCRYPTED PRIVATE KEY-----">>; pem_end(<<"-----BEGIN CERTIFICATE REQUEST-----">>) -> <<"-----END CERTIFICATE REQUEST-----">>; pem_end(<<"-----BEGIN PKCS7-----">>) -> <<"-----END PKCS7-----">>; pem_end(<<"-----BEGIN X509 CRL-----">>) -> <<"-----END X509 CRL-----">>; pem_end(<<"-----BEGIN EC PARAMETERS-----">>) -> <<"-----END EC PARAMETERS-----">>; pem_end(<<"-----BEGIN EC PRIVATE KEY-----">>) -> <<"-----END EC PRIVATE KEY-----">>; pem_end(<<"-----BEGIN OPENSSH PRIVATE KEY-----">>) -> <<"-----END OPENSSH PRIVATE KEY-----">>; pem_end(_) -> undefined. %% @private pem_enc(Entries) -> pem_enc(Entries, []). %% @private pem_enc([Entry={'PrivateKeyInfo', _, _} | Entries], Acc) -> Encoded = try public_key:pem_encode([Entry]) catch _:_ -> pem_entry_enc(Entry) end, pem_enc(Entries, [Encoded | Acc]); pem_enc([Entry | Entries], Acc) -> Encoded = public_key:pem_encode([Entry]), pem_enc(Entries, [Encoded | Acc]); pem_enc([], Acc) -> {true, erlang:iolist_to_binary(lists:reverse(Acc))}. %% @private pem_entry_dec({ASN1Type='PrivateKeyInfo', Der, not_encrypted}) -> Entity = der_decode(ASN1Type, Der), {true, i2k(Entity)}; pem_entry_dec({ASN1Type='SubjectPublicKeyInfo', Der, not_encrypted}) -> Entity = der_decode(ASN1Type, Der), {true, i2k(Entity)}; pem_entry_dec(_) -> false. %% @private pem_entry_dec({Asn1Type, EncryptedDer, CipherInfo = {_, #'PBES2-params'{}}}, Password) when is_atom(Asn1Type) -> case decipher({Asn1Type, EncryptedDer, CipherInfo}, Password) of DecryptedDer when is_binary(DecryptedDer) -> {true, der_decode(Asn1Type, DecryptedDer)}; _ -> false end; pem_entry_dec(PEMEntry, _Password) -> pem_entry_dec(PEMEntry). %% @private pem_entry_enc({'PrivateKeyInfo', Der, EncParams}) -> EncodedPEM = public_key:pem_encode([{'ECPrivateKey', Der, EncParams}]), erlang:iolist_to_binary(binary:split(EncodedPEM, <<" EC">>, [global, trim_all])); pem_entry_enc(Entry) -> Entry. %% @private pem_entry_enc('EdDSA25519PrivateKey', K=#'jose_EdDSA25519PrivateKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('PrivateKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('EdDSA25519PublicKey', K=#'jose_EdDSA25519PublicKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('EdDSA448PrivateKey', K=#'jose_EdDSA448PrivateKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('PrivateKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('EdDSA448PublicKey', K=#'jose_EdDSA448PublicKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('X25519PrivateKey', K=#'jose_X25519PrivateKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('PrivateKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('X25519PublicKey', K=#'jose_X25519PublicKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('X448PrivateKey', K=#'jose_X448PrivateKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('PrivateKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('X448PublicKey', K=#'jose_X448PublicKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('SubjectPublicKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('PrivateKeyInfo', K) -> case K of #'jose_EdDSA25519PrivateKey'{} -> pem_entry_enc('EdDSA25519PrivateKey', K); #'jose_EdDSA448PrivateKey'{} -> pem_entry_enc('EdDSA448PrivateKey', K); #'jose_X25519PrivateKey'{} -> pem_entry_enc('X25519PrivateKey', K); #'jose_X448PrivateKey'{} -> pem_entry_enc('X448PrivateKey', K); #'ECPrivateKey'{} -> pem_entry_enc('ECPrivateKey', K); #'RSAPrivateKey'{} -> pem_entry_enc('RSAPrivateKey', K); _ -> false end; %% Compatibility between PKCS1 and PKCS8 versions of public_key pem_entry_enc('ECPrivateKey', K=#'ECPrivateKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('PrivateKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc('RSAPrivateKey', K=#'RSAPrivateKey'{}) -> EncodedPEMEntry = public_key:pem_entry_encode('PrivateKeyInfo', k2i(K)), {true, EncodedPEMEntry}; pem_entry_enc(_, _) -> false. %% @private pem_entry_enc('EdDSA25519PrivateKey', K=#'jose_EdDSA25519PrivateKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('PrivateKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('EdDSA25519PublicKey', K=#'jose_EdDSA25519PublicKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('SubjectPublicKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('EdDSA448PrivateKey', K=#'jose_EdDSA448PrivateKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('PrivateKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('EdDSA448PublicKey', K=#'jose_EdDSA448PublicKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('SubjectPublicKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('X25519PrivateKey', K=#'jose_X25519PrivateKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('PrivateKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('X25519PublicKey', K=#'jose_X25519PublicKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('SubjectPublicKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('X448PrivateKey', K=#'jose_X448PrivateKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('PrivateKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('X448PublicKey', K=#'jose_X448PublicKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('SubjectPublicKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('PrivateKeyInfo', K, Password) -> case K of #'jose_EdDSA25519PrivateKey'{} -> pem_entry_enc('EdDSA25519PrivateKey', K, Password); #'jose_EdDSA448PrivateKey'{} -> pem_entry_enc('EdDSA448PrivateKey', K, Password); #'jose_X25519PrivateKey'{} -> pem_entry_enc('X25519PrivateKey', K, Password); #'jose_X448PrivateKey'{} -> pem_entry_enc('X448PrivateKey', K, Password); #'ECPrivateKey'{} -> pem_entry_enc('ECPrivateKey', K, Password); #'RSAPrivateKey'{} -> pem_entry_enc('RSAPrivateKey', K, Password); _ -> false end; %% Compatibility between PKCS1 and PKCS8 versions of public_key pem_entry_enc('ECPrivateKey', K=#'ECPrivateKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('PrivateKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc('RSAPrivateKey', K=#'RSAPrivateKey'{}, Password) -> EncodedPEMEntry = pem_entry_enc0('PrivateKeyInfo', k2i(K), Password), {true, EncodedPEMEntry}; pem_entry_enc(_, _, _) -> false. %% @private pem_entry_enc0(ASN1Type, Entry, Cipher) -> try public_key:pem_entry_encode(ASN1Type, Entry, Cipher) catch ?COMPAT_CATCH(Class, Reason, ST) -> case pem_entry_enc1(ASN1Type, Entry, Cipher) of {true, Encoded} -> Encoded; false -> erlang:raise(Class, Reason, ?COMPAT_GET_STACKTRACE(ST)) end end. %% @private pem_entry_enc1(ASN1Type, Entry, {CipherInfo={C, _}, Password}) when C == "AES-128-CBC" orelse C == "AES-192-CBC" orelse C == "AES-256-CBC" -> DecryptedDer = der_encode(ASN1Type, Entry), case cipher(DecryptedDer, CipherInfo, Password) of EncryptedDer when is_binary(EncryptedDer) -> {true, {ASN1Type, EncryptedDer, CipherInfo}}; _ -> false end; pem_entry_enc1(_, _, _) -> false. %% @private pem_cipher(Data, {Cipher = "AES-128-CBC", KeyDevParams}, Password) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), {true, crypto:block_encrypt(aes_cbc128, Key, IV, jose_jwa_pkcs7:pad(Data))}; pem_cipher(Data, {Cipher = "AES-192-CBC", KeyDevParams}, Password) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), {true, crypto:block_encrypt(aes_cbc192, Key, IV, jose_jwa_pkcs7:pad(Data))}; pem_cipher(Data, {Cipher = "AES-256-CBC", KeyDevParams}, Password) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), {true, crypto:block_encrypt(aes_cbc256, Key, IV, jose_jwa_pkcs7:pad(Data))}; pem_cipher(_, _, _) -> false. %% @private pem_decipher(Data, {Cipher = "AES-128-CBC", KeyDevParams}, Password) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), {true, crypto:block_decrypt(aes_cbc128, Key, IV, Data)}; pem_decipher(Data, {Cipher = "AES-192-CBC", KeyDevParams}, Password) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), {true, crypto:block_decrypt(aes_cbc192, Key, IV, Data)}; pem_decipher(Data, {Cipher = "AES-256-CBC", KeyDevParams}, Password) -> {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams), {true, crypto:block_decrypt(aes_cbc256, Key, IV, Data)}; pem_decipher(_, _, _) -> false. %% @private ceiling(Float) -> erlang:round(Float + 0.5). %% @private derived_key_length(_, Len) when is_integer(Len) -> Len; derived_key_length(Cipher, _) when (Cipher == "AES-128-CBC"); (Cipher == ?'id-aes128-CBC') -> 16; derived_key_length(Cipher,_) when (Cipher == "AES-192-CBC"); (Cipher == ?'id-aes192-CBC') -> 24; derived_key_length(Cipher,_) when (Cipher == "AES-256-CBC"); (Cipher == ?'id-aes256-CBC') -> 32. %% @private password_to_key_and_iv(Password, _Cipher, Params = #'PBES2-params'{}) -> {Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoHash, PseudoOtputLen, IV} = key_derivation_params(Params), <> = pubkey_pbe:pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoHash, PseudoOtputLen), {Key, IV}; password_to_key_and_iv(Password, _Cipher, {#'PBEParameter'{salt = Salt, iterationCount = Count}, Hash}) -> <> = pubkey_pbe:pbdkdf1(Password, Salt, Count, Hash), {Key, IV}; password_to_key_and_iv(Password, Cipher, KeyDevParams) -> %% PKCS5_SALT_LEN is 8 bytes <> = KeyDevParams, KeyLen = derived_key_length(Cipher, undefined), <> = pem_encrypt(<<>>, Password, Salt, ceiling(KeyLen div 16), <<>>, md5), %% Old PEM encryption does not use standard encryption method %% pbdkdf1 and uses then salt as IV {Key, KeyDevParams}. %% @private pem_encrypt(_, _, _, 0, Acc, _) -> Acc; pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) -> Result = crypto:hash(Hash, [Prev, Password, Salt]), pem_encrypt(Result, Password, Salt, Count-1 , <>, Hash). %% @private key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc, encryptionScheme = EncScheme}) -> #'PBES2-params_keyDerivationFunc'{ algorithm = ?'id-PBKDF2', parameters = #'PBKDF2-params'{ salt = {specified, OctetSalt}, iterationCount = Count, keyLength = Length, prf = Prf } } = KeyDerivationFunc, #'PBES2-params_encryptionScheme'{algorithm = Algo} = EncScheme, {PseudoRandomFunction, PseudoHash, PseudoOtputLen} = pseudo_random_function(Prf), KeyLen = derived_key_length(Algo, Length), {OctetSalt, Count, KeyLen, PseudoRandomFunction, PseudoHash, PseudoOtputLen, iv(EncScheme)}. %% @private %% This function currently matches a tuple that ougth to be the value %% ?'id-hmacWithSHA1, but we need some kind of ASN1-fix for this. pseudo_random_function(#'PBKDF2-params_prf'{algorithm = {_,_, _,'id-hmacWithSHA1'}}) -> {fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')}; pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1' = Algo}) -> {fun crypto:hmac/4, sha, pseudo_output_length(Algo)}; pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA224'= Algo}) -> {fun crypto:hmac/4, sha224, pseudo_output_length(Algo)}; pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA256' = Algo}) -> {fun crypto:hmac/4, sha256, pseudo_output_length(Algo)}; pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA384' = Algo}) -> {fun crypto:hmac/4, sha384, pseudo_output_length(Algo)}; pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA512' = Algo}) -> {fun crypto:hmac/4, sha512, pseudo_output_length(Algo)}. %% @private pseudo_output_length(?'id-hmacWithSHA1') -> 20; %%160/8 pseudo_output_length(?'id-hmacWithSHA224') -> 28; %%%224/8 pseudo_output_length(?'id-hmacWithSHA256') -> 32; %%256/8 pseudo_output_length(?'id-hmacWithSHA384') -> 48; %%384/8 pseudo_output_length(?'id-hmacWithSHA512') -> 64. %%512/8 %% @private iv(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC', parameters = ASN1IV}) -> {ok, #'RC2-CBC-Parameter'{iv = IV}} = 'PKCS-FRAME':decode('RC2-CBC-Parameter', decode_handle_open_type_wrapper(ASN1IV)), erlang:iolist_to_binary(IV); iv(#'PBES2-params_encryptionScheme'{algorithm = _Algo, parameters = ASN1IV}) -> <<4, Len:8/unsigned-big-integer, IV:Len/binary>> = decode_handle_open_type_wrapper(ASN1IV), IV. %% @private decode_handle_open_type_wrapper({asn1_OPENTYPE, Type}) -> Type. %% @private encode_handle_open_type_wrapper(Type) -> {asn1_OPENTYPE, Type}. %% @private i2k(#'PrivateKeyInfo'{ privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'jose_id-EdDSA25519' }, privateKey = << 4, 32:8/integer, PrivateKey:32/binary >> }) -> PublicKey = jose_curve25519:eddsa_secret_to_public(PrivateKey), #'jose_EdDSA25519PrivateKey'{ publicKey = #'jose_EdDSA25519PublicKey'{ publicKey = PublicKey }, privateKey = PrivateKey }; i2k(#'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'jose_id-EdDSA25519' }, subjectPublicKey = << PublicKey:32/binary >> }) -> #'jose_EdDSA25519PublicKey'{ publicKey = PublicKey }; i2k(#'PrivateKeyInfo'{ privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'jose_id-EdDSA448' }, privateKey = << 4, 57:8/integer, PrivateKey:57/binary >> }) -> PublicKey = jose_curve448:eddsa_secret_to_public(PrivateKey), #'jose_EdDSA448PrivateKey'{ publicKey = #'jose_EdDSA448PublicKey'{ publicKey = PublicKey }, privateKey = PrivateKey }; i2k(#'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'jose_id-EdDSA448' }, subjectPublicKey = << PublicKey:57/binary >> }) -> #'jose_EdDSA448PublicKey'{ publicKey = PublicKey }; i2k(#'PrivateKeyInfo'{ privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'jose_id-X25519' }, privateKey = << 4, 32:8/integer, PrivateKey:32/binary >> }) -> PublicKey = jose_curve25519:x25519_secret_to_public(PrivateKey), #'jose_X25519PrivateKey'{ publicKey = #'jose_X25519PublicKey'{ publicKey = PublicKey }, privateKey = PrivateKey }; i2k(#'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'jose_id-X25519' }, subjectPublicKey = << PublicKey:32/binary >> }) -> #'jose_X25519PublicKey'{ publicKey = PublicKey }; i2k(#'PrivateKeyInfo'{ privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'jose_id-X448' }, privateKey = << 4, 56:8/integer, PrivateKey:56/binary >> }) -> PublicKey = jose_curve448:x448_secret_to_public(PrivateKey), #'jose_X448PrivateKey'{ publicKey = #'jose_X448PublicKey'{ publicKey = PublicKey }, privateKey = PrivateKey }; i2k(#'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'jose_id-X448' }, subjectPublicKey = << PublicKey:56/binary >> }) -> #'jose_X448PublicKey'{ publicKey = PublicKey }; % public_key compat i2k(#'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'id-ecPublicKey', parameters = ECParameters }, subjectPublicKey = ECPublicKey }) -> {#'ECPoint'{point = ECPublicKey}, der_decode('EcpkParameters', ECParameters)}; i2k(PrivateKeyInfo=#'PrivateKeyInfo'{ privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'id-ecPublicKey', parameters = {asn1_OPENTYPE, EcpkParameters} }, privateKey = PrivateKey }) -> case der_decode('ECPrivateKey', PrivateKey) of ECPrivateKey = #'ECPrivateKey'{parameters = asn1_NOVALUE} -> ECPrivateKey#'ECPrivateKey'{parameters = der_decode('EcpkParameters', EcpkParameters)}; _ -> PrivateKeyInfo end; i2k(Info) -> Info. %% @private k2i(#'jose_EdDSA25519PrivateKey'{privateKey=PrivateKey}) -> #'PrivateKeyInfo'{ version = v1, privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'jose_id-EdDSA25519', parameters = asn1_NOVALUE }, privateKey = << 4, 32:8/integer, PrivateKey:32/binary >>, attributes = asn1_NOVALUE }; k2i(#'jose_EdDSA25519PublicKey'{publicKey=PublicKey}) -> #'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'jose_id-EdDSA25519', parameters = asn1_NOVALUE }, subjectPublicKey = << PublicKey:32/binary >> }; k2i(#'jose_EdDSA448PrivateKey'{privateKey=PrivateKey}) -> #'PrivateKeyInfo'{ version = v1, privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'jose_id-EdDSA448', parameters = asn1_NOVALUE }, privateKey = << 4, 57:8/integer, PrivateKey:57/binary >>, attributes = asn1_NOVALUE }; k2i(#'jose_EdDSA448PublicKey'{publicKey=PublicKey}) -> #'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'jose_id-EdDSA448', parameters = asn1_NOVALUE }, subjectPublicKey = << PublicKey:57/binary >> }; k2i(#'jose_X25519PrivateKey'{privateKey=PrivateKey}) -> #'PrivateKeyInfo'{ version = v1, privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'jose_id-X25519', parameters = asn1_NOVALUE }, privateKey = << 4, 32:8/integer, PrivateKey:32/binary >>, attributes = asn1_NOVALUE }; k2i(#'jose_X25519PublicKey'{publicKey=PublicKey}) -> #'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'jose_id-X25519', parameters = asn1_NOVALUE }, subjectPublicKey = << PublicKey:32/binary >> }; k2i(#'jose_X448PrivateKey'{privateKey=PrivateKey}) -> #'PrivateKeyInfo'{ version = v1, privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'jose_id-X448', parameters = asn1_NOVALUE }, privateKey = << 4, 56:8/integer, PrivateKey:56/binary >>, attributes = asn1_NOVALUE }; k2i(#'jose_X448PublicKey'{publicKey=PublicKey}) -> #'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'jose_id-X448', parameters = asn1_NOVALUE }, subjectPublicKey = << PublicKey:56/binary >> }; % public_key compat k2i({#'ECPoint'{point=ECPublicKey}, ECParameters}) -> #'SubjectPublicKeyInfo'{ algorithm = #'AlgorithmIdentifier'{ algorithm = ?'id-ecPublicKey', parameters = der_encode('EcpkParameters', ECParameters) }, subjectPublicKey = ECPublicKey }; k2i(PrivateKey=#'ECPrivateKey'{parameters=ECParameters}) -> #'PrivateKeyInfo'{ version = v1, privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'id-ecPublicKey', parameters = encode_handle_open_type_wrapper(der_encode('EcpkParameters', ECParameters)) }, privateKey = der_encode('ECPrivateKey', PrivateKey#'ECPrivateKey'{parameters=asn1_NOVALUE}), attributes = asn1_NOVALUE }; k2i(PrivateKey=#'RSAPrivateKey'{}) -> #'PrivateKeyInfo'{ version = v1, privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{ algorithm = ?'rsaEncryption', parameters = asn1_NOVALUE }, privateKey = der_encode('RSAPrivateKey', PrivateKey), attributes = asn1_NOVALUE }. erlang-jose-1.10.1/src/jose_chacha20_poly1305_unsupported.erl0000644000232200023220000000216513605433351024265 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 31 May 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_chacha20_poly1305_unsupported). -behaviour(jose_chacha20_poly1305). %% jose_chacha20_poly1305 callbacks -export([decrypt/5]). -export([encrypt/4]). -export([authenticate/3]). -export([verify/4]). %% Macros -define(unsupported, erlang:error(chacha20_poly1305_unsupported)). %%==================================================================== %% jose_chacha20_poly1305 callbacks %%==================================================================== decrypt(_CipherText, _CipherTag, _AAD, _IV, _Key) -> ?unsupported. encrypt(_PlainText, _AAD, _IV, _Key) -> ?unsupported. authenticate(_Message, _Key, _Nonce) -> ?unsupported. verify(_MAC, _Message, _Key, _Nonce) -> ?unsupported. erlang-jose-1.10.1/examples/0000755000232200023220000000000013605433351016167 5ustar debalancedebalanceerlang-jose-1.10.1/examples/KEY-GENERATION.md0000644000232200023220000002224513605433351020577 0ustar debalancedebalance# Examples: Key Generation There are four key generation methods described below for each key type: * Method 1: OpenSSL * Method 2: `jose_jwk:generate_key/1` or `JOSE.JWK.generate_key/1` * Method 3: `jose_jwe:generate_key/1` or `JOSE.JWE.generate_key/1` * Method 4: `jose_jws:generate_key/1` or `JOSE.JWS.generate_key/1` ## EC 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: 1. `"P-256"` (openssl curve `secp256r1`) 2. `"P-384"` (openssl curve `secp384r1`) 3. `"P-521"` (openssl curve `secp521r1`) ### Method 1 The basic formula for key generation is `openssl ecparam -name CURVE -genkey -noout -out FILE`, for example: ```bash openssl ecparam -name secp256r1 -genkey -noout -out ec-secp256r1.pem openssl ecparam -name secp384r1 -genkey -noout -out ec-secp384r1.pem openssl ecparam -name secp521r1 -genkey -noout -out ec-secp521r1.pem ``` The PEM files can then be read using `jose_jwk:from_pem_file/1` or `JOSE.JWK.from_pem_file/1`: ```elixir jwk = JOSE.JWK.from_pem_file("ec-secp256r1.pem") ``` ### Method 2 The curve names are the same as the ones for OpenSSL. ```elixir jwk = JOSE.JWK.generate_key(:secp256r1) jwk = JOSE.JWK.generate_key(:secp384r1) jwk = JOSE.JWK.generate_key(:secp521r1) # Alternative explicit syntax: jwk = JOSE.JWK.generate_key({:ec, :secp256r1}) jwk = JOSE.JWK.generate_key({:ec, :secp384r1}) jwk = JOSE.JWK.generate_key({:ec, :secp521r1}) # Alternative curve alias syntax: jwk = JOSE.JWK.generate_key({:ec, "P-256"}) jwk = JOSE.JWK.generate_key({:ec, "P-384"}) jwk = JOSE.JWK.generate_key({:ec, "P-521"}) ``` Keys may also be generated based on other keys. The new key will use the same curve as the supplied key. ```elixir old_jwk = JOSE.JWK.from_pem_file("ec-secp256r1.pem") new_jwk = JOSE.JWK.generate_key(old_jwk) ``` ### Method 3 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. ```elixir # Based on the "epk" field. epk = JOSE.JWK.generate_key({:ec, "P-256"}) jwe = JOSE.JWE.from_map(%{"alg" => "ECDH-ES", "enc" => "A128GCM", "epk" => epk |> JOSE.JWK.to_map |> elem(1)}) jwk = JOSE.JWE.generate_key(jwe) # Otherwise, defaults to "P-521". jwk = JOSE.JWE.generate_key(%{"alg" => "ECDH-ES", "enc" => "A128GCM"}) ``` ### Method 4 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. ```elixir jwk_ec256 = JOSE.JWS.generate_key(%{"alg" => "ES256"}) jwk_ec384 = JOSE.JWS.generate_key(%{"alg" => "ES384"}) jwk_ec521 = JOSE.JWS.generate_key(%{"alg" => "ES512"}) ``` ## oct 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)). ### Method 1 The basic formula for generating a random octet sequence is `openssl rand -out FILE BYTE_SIZE`, for example: ```bash openssl rand -out oct-128-bit.bin 16 ``` The binary file can then be read using `jose_jwk:from_oct_file/1` or `JOSE.JWK.from_oct_file/1`: ```elixir jwk = JOSE.JWK.from_oct_file("oct-128-bit.bin") ``` ### Method 2 Calling either of these functions with an integer will generate a random octet sequence. ```elixir jwk = JOSE.JWK.generate_key(16) # Alternative explicit syntax: jwk = JOSE.JWK.generate_key({:oct, 16}) ``` Keys may also be generated based on other keys. The new key will use the same byte size as the supplied key. ```elixir old_jwk = JOSE.JWK.from_oct_file("oct-128-bit.bin") new_jwk = JOSE.JWK.generate_key(old_jwk) ``` ### Method 3 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"`. ```elixir jwk_oct16 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A128GCM"}) jwk_oct24 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A192GCM"}) jwk_oct32 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A256GCM"}) jwk_oct32 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A128CBC-HS256"}) jwk_oct48 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A192CBC-HS384"}) jwk_oct64 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A256CBC-HS512"}) ``` ### Method 4 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"`. ```elixir jwk_oct32 = JOSE.JWS.generate_key(%{"alg" => "HS256"}) jwk_oct48 = JOSE.JWS.generate_key(%{"alg" => "HS384"}) jwk_oct64 = JOSE.JWS.generate_key(%{"alg" => "HS512"}) ``` ## OKP 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)). ### Method 1 *NOTE:* Only `Ed25519` is currently supported by `ssh-keygen`. The basic formula for generating a octet key pair is `ssh-keygen -t TYPE -f FILE`, for example: ```bash ssh-keygen -t ed25519 -f ed25519 ``` The private key file can then be read using `jose_jwk:from_openssh_key_file/1` or `JOSE.JWK.from_openssh_key_file/1`: ```elixir jwk = JOSE.JWK.from_openssh_key_file("ed25519") ``` ### Method 2 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. ```elixir % Curve25519 jwk_Ed25519 = JOSE.JWK.generate_key({:okp, :Ed25519}) jwk_Ed25519ph = JOSE.JWK.generate_key({:okp, :Ed25519ph}) jwk_X25519 = JOSE.JWK.generate_key({:okp, :X25519}) % Curve448 jwk_Ed448 = JOSE.JWK.generate_key({:okp, :Ed448}) jwk_Ed448ph = JOSE.JWK.generate_key({:okp, :Ed448ph}) jwk_X448 = JOSE.JWK.generate_key({:okp, :X448}) ``` Keys may also be generated based on other keys. The new key will use the same curve as the supplied key. ```elixir old_jwk = JOSE.JWK.from_openssh_key_file("ed25519") new_jwk = JOSE.JWK.generate_key(old_jwk) ``` ### Method 3 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"`. ```elixir # Based on the "epk" field. epk = JOSE.JWK.generate_key({:okp, :X25519}) jwe = JOSE.JWE.from_map(%{"alg" => "ECDH-ES", "enc" => "A128GCM", "epk" => epk |> JOSE.JWK.to_map |> elem(1)}) jwk = JOSE.JWE.generate_key(jwe) ``` ### Method 4 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. ```elixir jwk_Ed25519 = JOSE.JWS.generate_key(%{"alg" => "Ed25519"}) jwk_Ed25519ph = JOSE.JWS.generate_key(%{"alg" => "Ed25519ph"}) jwk_Ed448 = JOSE.JWS.generate_key(%{"alg" => "Ed448"}) jwk_Ed448ph = JOSE.JWS.generate_key(%{"alg" => "Ed448ph"}) # EdDSA defaults to Ed25519 jwk_EdDSA = JOSE.JWS.generate_key(%{"alg" => "EdDSA"}) ``` ## RSA 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. See [`test/jose_SUITE_data/rsa-multi.pem`](https://github.com/potatosalad/erlang-jose/blob/master/test/jose_SUITE_data/rsa-multi.pem) for an example multi-prime RSA key. ### Method 1 The basic formula for generating a RSA key is `openssl genrsa -out FILE BIT_SIZE`, for example: ```bash openssl genrsa -out rsa-2048.pem 2048 ``` The PEM file can then be read using `jose_jwk:from_pem_file/1` or `JOSE.JWK.from_pem_file/1`: ```elixir jwk = JOSE.JWK.from_pem_file("rsa-2048.pem") ``` ### Method 2 _Note:_ RSA key generation is dependent on [`cutkey`](https://github.com/potatosalad/cutkey), which must be included as a dependency. An error will be thrown if `cutkey` is not found. The modulus bit size is the only required argument. Optionally, you may specify the public exponent as the second argument (default is `65537`). ```elixir jwk = JOSE.JWK.generate_key({:rsa, 2048}) # Alternative explicit syntax with public exponent: jwk = JOSE.JWK.generate_key({:rsa, 4096, 65537}) ``` 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. ```elixir old_jwk = JOSE.JWK.from_pem_file("rsa-2048.pem") new_jwk = JOSE.JWK.generate_key(old_jwk) ``` ### Method 3 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. ```elixir jwk_rsa1_5 = JOSE.JWE.generate_key(%{"alg" => "RSA1_5", "enc" => "A128GCM"}) jwk_rsa_oaep = JOSE.JWE.generate_key(%{"alg" => "RSA-OAEP", "enc" => "A128GCM"}) jwk_rsa_oaep256 = JOSE.JWE.generate_key(%{"alg" => "RSA-OAEP-256", "enc" => "A128GCM"}) ``` ### Method 4 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. ```elixir # RS256, RS384, RS512 jwk_rsa2048 = JOSE.JWS.generate_key(%{"alg" => "RS256"}) jwk_rsa3072 = JOSE.JWS.generate_key(%{"alg" => "RS384"}) jwk_rsa4096 = JOSE.JWS.generate_key(%{"alg" => "RS512"}) # PS256, PS384, PS512 jwk_rsa2048 = JOSE.JWS.generate_key(%{"alg" => "PS256"}) jwk_rsa3072 = JOSE.JWS.generate_key(%{"alg" => "PS384"}) jwk_rsa4096 = JOSE.JWS.generate_key(%{"alg" => "PS512"}) ``` erlang-jose-1.10.1/rebar.config0000644000232200023220000000032413605433351016632 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet {erl_opts, [ debug_info, warnings_as_errors ]}. {deps, [ {base64url, "0.0.1", {pkg, base64url}} ]}. erlang-jose-1.10.1/.formatter.exs0000644000232200023220000000017213605433351017153 0ustar debalancedebalance# Used by "mix format" [ inputs: ["{mix,.formatter}.exs", "{config,lib,priv,test}/**/*.{ex,exs}"], line_length: 132 ] erlang-jose-1.10.1/include/0000755000232200023220000000000013605433351015774 5ustar debalancedebalanceerlang-jose-1.10.1/include/jose_jws.hrl0000644000232200023220000000121213605433351020322 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -ifndef(JOSE_JWS_HRL). -record(jose_jws, { alg = undefined :: undefined | {module(), any()}, b64 = undefined :: undefined | boolean(), fields = #{} :: map() }). -define(JOSE_JWS_HRL, 1). -endif. erlang-jose-1.10.1/include/jose_compat.hrl0000644000232200023220000000145313605433351021011 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2018, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 19 Nov 2018 by Emil Falk %%%------------------------------------------------------------------- -ifndef(JOSE_COMPAT_HRL). -ifdef(OTP_RELEASE). %% this implies OTP 21 or higher -define(COMPAT_CATCH(Class, Reason, Stacktrace), Class:Reason:Stacktrace). -define(COMPAT_GET_STACKTRACE(Stacktrace), Stacktrace). -else. -define(COMPAT_CATCH(Class, Reason, _), Class:Reason). -define(COMPAT_GET_STACKTRACE(_), erlang:get_stacktrace()). -endif. -define(JOSE_COMPAT_HRL, 1). -endif. erlang-jose-1.10.1/include/jose_jwk.hrl0000644000232200023220000000122213605433351020313 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 21 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -ifndef(JOSE_JWK_HRL). -record(jose_jwk, { keys = undefined :: undefined | {module(), any()}, kty = undefined :: undefined | {module(), any()}, fields = #{} :: map() }). -define(JOSE_JWK_HRL, 1). -endif. erlang-jose-1.10.1/include/jose_jwt.hrl0000644000232200023220000000104013605433351020322 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 29 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -ifndef(JOSE_JWT_HRL). -record(jose_jwt, { fields = #{} :: map() }). -define(JOSE_JWT_HRL, 1). -endif. erlang-jose-1.10.1/include/jose_jwe.hrl0000644000232200023220000000131013605433351020303 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 22 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -ifndef(JOSE_JWE_HRL). -record(jose_jwe, { alg = undefined :: undefined | {module(), any()}, enc = undefined :: undefined | {module(), any()}, zip = undefined :: undefined | {module(), any()}, fields = #{} :: map() }). -define(JOSE_JWE_HRL, 1). -endif. erlang-jose-1.10.1/include/jose_base.hrl0000644000232200023220000000136113605433351020436 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2017-2019, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 11 May 2017 by Andrew Bennett %%%------------------------------------------------------------------- -ifndef(JOSE_BASE_HRL). -define(bnotzero(X), ((((X) bor ((bnot (X)) + 1)) bsr 7) band 1)). -define(is_iodata(I), (is_binary(I) orelse is_list(I))). -define(to_binary(I), (case I of _ when is_binary(I) -> I; _ when is_list(I) -> erlang:iolist_to_binary(I) end)). -define(JOSE_BASE_HRL, 1). -endif. erlang-jose-1.10.1/include/jose_public_key.hrl0000644000232200023220000000365613605433351021663 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2017, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 12 May 2017 by Andrew Bennett %%%------------------------------------------------------------------- -ifndef(JOSE_PUBLIC_KEY_HRL). -include_lib("public_key/include/public_key.hrl"). -ifndef('id-aes128-CBC'). -define('id-aes128-CBC', {2,16,840,1,101,3,4,1,2}). -endif. -ifndef('id-aes192-CBC'). -define('id-aes192-CBC', {2,16,840,1,101,3,4,1,22}). -endif. -ifndef('id-aes256-CBC'). -define('id-aes256-CBC', {2,16,840,1,101,3,4,1,42}). -endif. -define('jose_id-X25519', {1,3,101,110}). -define('jose_id-X448', {1,3,101,111}). -define('jose_id-EdDSA25519', {1,3,101,112}). -define('jose_id-EdDSA448', {1,3,101,113}). -record(jose_EdDSA25519PublicKey, { publicKey = undefined :: undefined | << _:256 >> }). -record(jose_EdDSA25519PrivateKey, { publicKey = undefined :: undefined | #jose_EdDSA25519PublicKey{}, privateKey = undefined :: undefined | << _:256 >> }). -record(jose_EdDSA448PublicKey, { publicKey = undefined :: undefined | << _:456 >> }). -record(jose_EdDSA448PrivateKey, { publicKey = undefined :: undefined | #jose_EdDSA448PublicKey{}, privateKey = undefined :: undefined | << _:456 >> }). -record(jose_X25519PublicKey, { publicKey = undefined :: undefined | << _:256 >> }). -record(jose_X25519PrivateKey, { publicKey = undefined :: undefined | #jose_X25519PublicKey{}, privateKey = undefined :: undefined | << _:256 >> }). -record(jose_X448PublicKey, { publicKey = undefined :: undefined | << _:448 >> }). -record(jose_X448PrivateKey, { publicKey = undefined :: undefined | #jose_X448PublicKey{}, privateKey = undefined :: undefined | << _:448 >> }). -define(JOSE_PUBLIC_KEY_HRL, 1). -endif. erlang-jose-1.10.1/include/jose.hrl0000644000232200023220000000112113605433351017436 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 23 Jul 2015 by Andrew Bennett %%%------------------------------------------------------------------- -ifndef(JOSE_HRL). -include("jose_jwe.hrl"). -include("jose_jwk.hrl"). -include("jose_jws.hrl"). -include("jose_jwt.hrl"). -define(JOSE_HRL, 1). -endif. erlang-jose-1.10.1/mix.exs0000644000232200023220000000374213605433351015675 0ustar debalancedebalancedefmodule JOSE.Mixfile do use Mix.Project def project() do [ app: :jose, version: "1.10.1", elixir: "~> 1.0", erlc_options: erlc_options(), build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, deps: deps(), name: "JOSE", source_url: "https://github.com/potatosalad/erlang-jose", docs: fn -> {ref, 0} = System.cmd("git", ["rev-parse", "--verify", "--quiet", "HEAD"]) [source_ref: ref, main: "JOSE", extras: ["README.md", "CHANGELOG.md", "examples/KEY-GENERATION.md", "ALGORITHMS.md"]] end, description: description(), package: package() ] end def application() do [mod: {:jose_app, []}, applications: [:crypto, :asn1, :public_key]] end defp deps() do [ # {:cutkey, github: "potatosalad/cutkey", only: [:dev, :test]}, {:jason, "~> 1.1", only: [:dev, :test]}, {:jsone, "~> 1.4", only: [:dev, :test]}, {:jsx, "~> 2.9", only: [:dev, :test]}, # {:keccakf1600, "~> 2.0.0", only: [:dev, :test]}, {:libdecaf, "~> 1.0.0", only: [:dev, :test]}, {:libsodium, "~> 0.0.10", only: [:dev, :test]}, {:ojson, "~> 1.0", only: [:dev, :test]}, {:poison, "~> 4.0", only: [:dev, :test]}, {:ex_doc, "~> 0.19", only: :dev}, {:earmark, "~> 1.3", only: :dev} ] end defp description() do "JSON Object Signing and Encryption (JOSE) for Erlang and Elixir." end def erlc_options() do extra_options = [] [:debug_info | if(Mix.env() == :prod, do: [], else: [:warnings_as_errors]) ++ extra_options] end defp package() do [ maintainers: ["Andrew Bennett"], files: [ "CHANGELOG*", "include", "lib", "LICENSE*", "priv", "mix.exs", "README*", "rebar.config", "src" ], licenses: ["MIT"], links: %{"Github" => "https://github.com/potatosalad/erlang-jose", "Docs" => "https://hexdocs.pm/jose"} ] end end erlang-jose-1.10.1/ALGORITHMS.md0000644000232200023220000001730513605433351016352 0ustar debalancedebalance# Algorithms | Algorithm | Purpose | OTP 17 | OTP 18 | OTP 19 | Fallback | Definition | | ----------------- | ---------- | ------ | ------ | ------ | -------- | ---------- | | AES CBC 128-bit | Encryption | X | X | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES CBC 192-bit | Encryption | | | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES CBC 256-bit | Encryption | X | X | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES CTR 128-bit | Encryption | X | X | X | | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES CTR 192-bit | Encryption | X | X | X | | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES CTR 256-bit | Encryption | X | X | X | | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES ECB 128-bit | Encryption | | X | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES ECB 192-bit | Encryption | | | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES ECB 256-bit | Encryption | | X | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf) | | AES GCM 128-bit | Encryption | | X | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf) | | AES GCM 192-bit | Encryption | | X | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf) | | AES GCM 256-bit | Encryption | | X | X | [`jose_jwa_aes`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes.erl) | [NIST.800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf) | | ChaCha20/Poly1305 | Encryption | | | | [`jose_jwa_chacha20_poly1305`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_chacha20_poly1305.erl) | [RFC 7539](https://tools.ietf.org/html/rfc7539) | | RSAES-OAEP | Encryption | X | X | X | [`jose_jwa_pkcs1`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs1.erl) | [RFC 3447](https://tools.ietf.org/html/rfc3447) | | RSAES-OAEP-256 | Encryption | | | | [`jose_jwa_pkcs1`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs1.erl) | [RFC 3447](https://tools.ietf.org/html/rfc3447) | | RSAES-PKCS1-v1_5 | Encryption | X | X | X | [`jose_jwa_pkcs1`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs1.erl) | [RFC 3447](https://tools.ietf.org/html/rfc3447) | | RSASSA-PKCS1-v1_5 | Signature | X | X | X | [`jose_jwa_pkcs1`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs1.erl) | [RFC 3447](https://tools.ietf.org/html/rfc3447) | | RSASSA-PSS | Signature | | | | [`jose_jwa_pkcs1`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs1.erl) | [RFC 3447](https://tools.ietf.org/html/rfc3447) | There are also several "helper" algorithms used with the above that have no native implementations currently in OTP: | Algorithm | Purpose | Fallback | Definition | | ----------------- | --------------- | -------- | ---------- | | AES Key Wrap | Key Wrap | [`jose_jwa_aes_kw`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_aes_kw.erl) | [RFC 3394](https://tools.ietf.org/html/rfc3394) | | Concat KDF | Key Derivation | [`jose_jwa_concat_kdf`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_concat_kdf.erl) | [NIST.800-56A](https://dx.doi.org/10.6028/NIST.SP.800-56Ar2) | | MGF1 | Mask Generation | [`jose_jwa_pkcs1`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs1.erl) | [RFC 3447](https://tools.ietf.org/html/rfc3447) | | PBKDF1 | Key Derivation | [`jose_jwa_pkcs5`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs5.erl) | [RFC 2898](https://tools.ietf.org/html/rfc2898) | | PBKDF2 | Key Derivation | [`jose_jwa_pkcs5`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs5.erl) | [RFC 2898](https://tools.ietf.org/html/rfc2898) | | PKCS #7 Padding | Padding | [`jose_jwa_pkcs7`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_pkcs7.erl) | [RFC 2315](https://tools.ietf.org/html/rfc2315) | The following are algorithms related to the draft [CFRG ECDH and signatures in JOSE](https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves): | Algorithm | Purpose | External | Fallback | Definition | | --------- | ------------ | -------- | -------- | ---------- | | Ed25519 | Signature | [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf), [`libsodium`](https://github.com/potatosalad/erlang-libsodium) | [`jose_jwa_curve25519`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_curve25519.erl) | [EdDSA](https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1) | | Ed25519ph | Signature | [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf), [`libsodium`](https://github.com/potatosalad/erlang-libsodium) | [`jose_jwa_curve25519`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_curve25519.erl) | [EdDSA](https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.1) | | Ed448 | Signature | [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf) | [`jose_jwa_curve448`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_curve448.erl) | [EdDSA](https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2) | | Ed448ph | Signature | [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf) | [`jose_jwa_curve448`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_curve448.erl) | [EdDSA](https://tools.ietf.org/html/draft-irtf-cfrg-eddsa#section-5.2) | | SHAKE256 | Hash | [`keccakf1600`](https://github.com/potatosalad/erlang-keccakf1600), [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf) | [`jose_jwa_sha3`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_sha3.erl) | [FIPS 202](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | | X25519 | Key Exchange | [`libsodium`](https://github.com/potatosalad/erlang-libsodium) | [`jose_jwa_curve25519`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_curve25519.erl) | [RFC 7748](https://tools.ietf.org/html/rfc7748#section-5) | | X448 | Key Exchange | [`libdecaf`](https://github.com/potatosalad/erlang-libdecaf) | [`jose_jwa_curve448`](https://github.com/potatosalad/erlang-jose/blob/master/src/jose_jwa_curve448.erl) | [RFC 7748](https://tools.ietf.org/html/rfc7748#section-5) | erlang-jose-1.10.1/test/0000755000232200023220000000000013605433351015330 5ustar debalancedebalanceerlang-jose-1.10.1/test/jose_ct.erl0000644000232200023220000000453613605433351017472 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_ct). -include_lib("common_test/include/ct.hrl"). %% API -export([start/2]). -export([stop/1]). -export([progress_start/0]). -export([progress_stop/1]). %% Internal API -export([init/1]). %% Macros -define(RED, "\e[0;31m"). -define(GREEN, "\e[0;32m"). -define(YELLOW, "\e[0;33m"). -define(WHITE, "\e[0;37m"). -define(CYAN, "\e[0;36m"). -define(RESET, "\e[0m"). -define(TIME, 1000). % timer:seconds(1) start(Group, Config) -> Now = os:timestamp(), io:format(user, "~s[ ] ~s :: ~s~s", [?WHITE, format_utc_timestamp(Now), Group, ?RESET]), {ok, Progress} = progress_start(), [{jose_ct, {Progress, Now}} | Config]. stop(Config) -> Now = os:timestamp(), {Progress, Old} = ?config(jose_ct, Config), ok = progress_stop(Progress), Diff = timer:now_diff(Now, Old), io:format(user, "~s[OK] ~s :: ~s elapsed~s~n", [?GREEN, format_utc_timestamp(Now), format_elapsed_time(Diff), ?RESET]), ok. progress_start() -> Ref = erlang:make_ref(), {ok, Pid} = proc_lib:start(?MODULE, init, [{self(), Ref}]), {ok, {Ref, Pid}}. progress_stop({Ref, Pid}) -> Pid ! {stop, self(), Ref}, receive Ref -> ok after 1000 -> ok end. %% @private format_elapsed_time(USec) -> Micro = USec rem 1000000, Second = ((USec - Micro) div 1000000) rem 60, Minute = ((USec - (Second * 1000000)) div 6000000) rem 60, Hour = ((USec - (Minute * 6000000)) div 360000000) rem 24, io_lib:format("~2..0w:~2..0w:~2..0w.~6..0w", [Hour,Minute,Second,Micro]). %% @private format_utc_timestamp(TS = {_, _, Micro}) -> {{Year,Month,Day},{Hour,Minute,Second}} = calendar:now_to_universal_time(TS), io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w.~6..0w", [Year,Month,Day,Hour,Minute,Second,Micro]). %% @private init({Parent, Ref}) -> process_flag(trap_exit, true), ok = proc_lib:init_ack(Parent, {ok, self()}), {ok, TRef} = timer:send_interval(?TIME, {tick, Ref}), loop(Ref, TRef). %% @private loop(Ref, TRef) -> receive {tick, Ref} -> io:format(user, "~s.~s", [?WHITE, ?RESET]), loop(Ref, TRef); {stop, Parent, Ref} when is_pid(Parent) -> io:format(user, "~n", []), catch timer:cancel(TRef), Parent ! Ref, exit(normal); Info -> io:format(user, "~n~s[~s] received unhandled message:~n~p~s~n", [?RED, ?MODULE, Info, ?RESET]), loop(Ref, TRef) end. erlang-jose-1.10.1/test/jose_jwa_chacha20_poly1305_SUITE.erl0000644000232200023220000005265213605433351023625 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2016, Andrew Bennett %%% @doc %%% @end %%% Created : 08 Aug 2016 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_chacha20_poly1305_SUITE). -include_lib("common_test/include/ct.hrl"). -include("jose.hrl"). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([aead/0]). -export([aead/1]). -export([block/0]). -export([block/1]). -export([encrypt/0]). -export([encrypt/1]). -export([key/0]). -export([key/1]). -export([mac/0]). -export([mac/1]). all() -> [ {group, chacha20}, {group, chacha20_poly1305}, {group, poly1305} ]. groups() -> [ {chacha20, [parallel], [ block, encrypt ]}, {chacha20_poly1305, [parallel], [ aead ]}, {poly1305, [parallel], [ key, mac ]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), Config. end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(Group, Config) -> jose_ct:start(Group, group_config(Group, Config)). end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== aead() -> [{doc, "Test ChaCha20/Poly1305 AEAD function"}]. aead(Config) when is_list(Config) -> AEADs = lazy_eval(proplists:get_value(aead, Config)), lists:foreach(fun aead_cipher/1, AEADs). block() -> [{doc, "Test ChaCha20 Block function"}]. block(Config) when is_list(Config) -> Blocks = lazy_eval(proplists:get_value(block, Config)), lists:foreach(fun chacha20_block/1, Blocks). encrypt() -> [{doc, "Test ChaCha20 Encryption function"}]. encrypt(Config) when is_list(Config) -> Encrypts = lazy_eval(proplists:get_value(encrypt, Config)), lists:foreach(fun chacha20_encrypt/1, Encrypts). key() -> [{doc, "Test Poly1305 Key Generation function"}]. key(Config) when is_list(Config) -> Keys = lazy_eval(proplists:get_value(key, Config)), lists:foreach(fun poly1305_key/1, Keys). mac() -> [{doc, "Test Poly1305 MAC function"}]. mac(Config) when is_list(Config) -> MACs = lazy_eval(proplists:get_value(mac, Config)), lists:foreach(fun poly1305_mac/1, MACs). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private aead_cipher({Key, PlainText, IV, AAD, CipherText, CipherTag}) -> case jose_jwa_chacha20_poly1305:encrypt(PlainText, AAD, IV, Key) of {CipherText, CipherTag} -> ok; Other0 -> ct:fail({{jose_jwa_chacha20_poly1305, encrypt, [PlainText, AAD, IV, Key]}, {expected, {CipherText, CipherTag}}, {got, Other0}}) end, case jose_jwa_chacha20_poly1305:decrypt(CipherText, CipherTag, AAD, IV, Key) of PlainText -> ok; Other1 -> ct:fail({{jose_jwa_chacha20_poly1305, decrypt, [CipherText, CipherTag, AAD, IV, Key]}, {expected, PlainText}, {got, Other1}}) end. %% @private chacha20_block({Key, Nonce, Counter, State}) -> case jose_jwa_chacha20:block(Key, Counter, Nonce) of State -> ok; Other0 -> ct:fail({{jose_jwa_chacha20, block, [Key, Counter, Nonce]}, {expected, State}, {got, Other0}}) end. %% @private chacha20_encrypt({Key, Nonce, Counter, PlainText, CipherText}) -> case jose_jwa_chacha20:encrypt(Key, Counter, Nonce, PlainText) of CipherText -> ok; Other0 -> ct:fail({{jose_jwa_chacha20, encrypt, [Key, Counter, Nonce, PlainText]}, {expected, CipherText}, {got, Other0}}) end, case jose_jwa_chacha20:encrypt(Key, Counter, Nonce, CipherText) of PlainText -> ok; Other1 -> ct:fail({{jose_jwa_chacha20, encrypt, [Key, Counter, Nonce, CipherText]}, {expected, PlainText}, {got, Other1}}) end. %% @private poly1305_key({Key, Nonce, OneTimeKey}) -> case jose_jwa_chacha20_poly1305:poly1305_key_gen(Key, Nonce) of OneTimeKey -> ok; Other0 -> ct:fail({{jose_jwa_chacha20_poly1305, poly1305_key_gen, [Key, Nonce]}, {expected, OneTimeKey}, {got, Other0}}) end. %% @private poly1305_mac({OneTimeKey, Text, Tag}) -> case jose_jwa_poly1305:mac(Text, OneTimeKey) of Tag -> ok; Other0 -> ct:fail({{jose_jwa_poly1305, mac, [Text, OneTimeKey]}, {expected, Tag}, {got, Other0}}) end. %% @private group_config(chacha20, Config) -> Block = chacha20_block(), Encrypt = chacha20_encrypt(), [{block, Block}, {encrypt, Encrypt} | Config]; group_config(chacha20_poly1305, Config) -> AEAD = chacha20_poly1305(), [{aead, AEAD} | Config]; group_config(poly1305, Config) -> Key = poly1305_key(), MAC = poly1305_mac(), [{key, Key}, {mac, MAC} | Config]. %% @private hexstr2bin(S) -> list_to_binary(hexstr2list(S)). %% @private hexstr2list([X,Y|T]) -> [mkint(X)*16 + mkint(Y) | hexstr2list(T)]; hexstr2list([]) -> []. %% @private hexts(TS) -> [begin list_to_tuple([begin case V of _ when is_list(V) -> hexstr2bin(V); _ -> V end end || V <- tuple_to_list(T)]) end || T <- TS]. %% Building huge terms (like long_msg/0) in init_per_group seems to cause %% test_server crash with 'no_answer_from_tc_supervisor' sometimes on some %% machines. Therefore lazy evaluation when test case has started. lazy_eval(F) when is_function(F) -> F(); lazy_eval(Lst) when is_list(Lst) -> lists:map(fun lazy_eval/1, Lst); lazy_eval(Tpl) when is_tuple(Tpl) -> list_to_tuple(lists:map(fun lazy_eval/1, tuple_to_list(Tpl))); lazy_eval(Term) -> Term. %% @private mkint(C) when $0 =< C, C =< $9 -> C - $0; mkint(C) when $A =< C, C =< $F -> C - $A + 10; mkint(C) when $a =< C, C =< $f -> C - $a + 10. %% ChaCha20 Block test vectors from: %% https://tools.ietf.org/html/rfc7539#appendix-A.1 chacha20_block() -> hexts([ % Test Vector #1 { "00000000000000000000000000000000" %% Key "00000000000000000000000000000000", "000000000000000000000000", %% Nonce 0, %% Block Counter "76b8e0ada0f13d90405d6ae55386bd28" %% State "bdd219b8a08ded1aa836efcc8b770dc7" "da41597c5157488d7724e03fb8d84a37" "6a43b8f41518a11cc387b669b2ee6586" }, % Test Vector #2 { "00000000000000000000000000000000" %% Key "00000000000000000000000000000000", "000000000000000000000000", %% Nonce 1, %% Block Counter "9f07e7be5551387a98ba977c732d080d" %% State "cb0f29a048e3656912c6533e32ee7aed" "29b721769ce64e43d57133b074d839d5" "31ed1f28510afb45ace10a1f4b794d6f" }, % Test Vector #3 { "00000000000000000000000000000000" %% Key "00000000000000000000000000000001", "000000000000000000000000", %% Nonce 1, %% Block Counter "3aeb5224ecf849929b9d828db1ced4dd" %% State "832025e8018b8160b82284f3c949aa5a" "8eca00bbb4a73bdad192b5c42f73f2fd" "4e273644c8b36125a64addeb006c13a0" }, % Test Vector #4 { "00ff0000000000000000000000000000" %% Key "00000000000000000000000000000000", "000000000000000000000000", %% Nonce 2, %% Block Counter "72d54dfbf12ec44b362692df94137f32" %% State "8fea8da73990265ec1bbbea1ae9af0ca" "13b25aa26cb4a648cb9b9d1be65b2c09" "24a66c54d545ec1b7374f4872e99f096" }, % Test Vector #5 { "00000000000000000000000000000000" %% Key "00000000000000000000000000000000", "000000000000000000000002", %% Nonce 0, %% Block Counter "c2c64d378cd536374ae204b9ef933fcd" %% State "1a8b2288b3dfa49672ab765b54ee27c7" "8a970e0e955c14f3a88e741b97c286f7" "5f8fc299e8148362fa198a39531bed6d" } ]). %% ChaCha20 Encryption test vectors from: %% https://tools.ietf.org/html/rfc7539#appendix-A.2 chacha20_encrypt() -> hexts([ % Test Vector #1 { "00000000000000000000000000000000" %% Key "00000000000000000000000000000000", "000000000000000000000000", %% Nonce 0, %% Block Counter "00000000000000000000000000000000" %% PlainText "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000", "76b8e0ada0f13d90405d6ae55386bd28" %% CipherText "bdd219b8a08ded1aa836efcc8b770dc7" "da41597c5157488d7724e03fb8d84a37" "6a43b8f41518a11cc387b669b2ee6586" }, % Test Vector #2 { "00000000000000000000000000000000" %% Key "00000000000000000000000000000001", "000000000000000000000002", %% Nonce 1, %% Block Counter "416e79207375626d697373696f6e2074" %% PlainText "6f20746865204945544620696e74656e" "6465642062792074686520436f6e7472" "696275746f7220666f72207075626c69" "636174696f6e20617320616c6c206f72" "2070617274206f6620616e2049455446" "20496e7465726e65742d447261667420" "6f722052464320616e6420616e792073" "746174656d656e74206d616465207769" "7468696e2074686520636f6e74657874" "206f6620616e20494554462061637469" "7669747920697320636f6e7369646572" "656420616e20224945544620436f6e74" "7269627574696f6e222e205375636820" "73746174656d656e747320696e636c75" "6465206f72616c2073746174656d656e" "747320696e2049455446207365737369" "6f6e732c2061732077656c6c20617320" "7772697474656e20616e6420656c6563" "74726f6e696320636f6d6d756e696361" "74696f6e73206d61646520617420616e" "792074696d65206f7220706c6163652c" "20776869636820617265206164647265" "7373656420746f", "a3fbf07df3fa2fde4f376ca23e827370" %% CipherText "41605d9f4f4f57bd8cff2c1d4b7955ec" "2a97948bd3722915c8f3d337f7d37005" "0e9e96d647b7c39f56e031ca5eb6250d" "4042e02785ececfa4b4bb5e8ead0440e" "20b6e8db09d881a7c6132f420e527950" "42bdfa7773d8a9051447b3291ce1411c" "680465552aa6c405b7764d5e87bea85a" "d00f8449ed8f72d0d662ab052691ca66" "424bc86d2df80ea41f43abf937d3259d" "c4b2d0dfb48a6c9139ddd7f76966e928" "e635553ba76c5c879d7b35d49eb2e62b" "0871cdac638939e25e8a1e0ef9d5280f" "a8ca328b351c3c765989cbcf3daa8b6c" "cc3aaf9f3979c92b3720fc88dc95ed84" "a1be059c6499b9fda236e7e818b04b0b" "c39c1e876b193bfe5569753f88128cc0" "8aaa9b63d1a16f80ef2554d7189c411f" "5869ca52c5b83fa36ff216b9c1d30062" "bebcfd2dc5bce0911934fda79a86f6e6" "98ced759c3ff9b6477338f3da4f9cd85" "14ea9982ccafb341b2384dd902f3d1ab" "7ac61dd29c6f21ba5b862f3730e37cfd" "c4fd806c22f221" }, % Test Vector #3 { "1c9240a5eb55d38af333888604f6b5f0" %% Key "473917c1402b80099dca5cbc207075c0", "000000000000000000000002", %% Nonce 42, %% Block Counter "2754776173206272696c6c69672c2061" %% PlainText "6e642074686520736c6974687920746f" "7665730a446964206779726520616e64" "2067696d626c6520696e207468652077" "6162653a0a416c6c206d696d73792077" "6572652074686520626f726f676f7665" "732c0a416e6420746865206d6f6d6520" "7261746873206f757467726162652e", "62e6347f95ed87a45ffae7426f27a1df" %% CipherText "5fb69110044c0d73118effa95b01e5cf" "166d3df2d721caf9b21e5fb14c616871" "fd84c54f9d65b283196c7fe4f60553eb" "f39c6402c42234e32a356b3e764312a6" "1a5532055716ead6962568f87d3f3f77" "04c6a8d1bcd1bf4d50d6154b6da731b1" "87b58dfd728afa36757a797ac188d1" } ]). %% ChaCha20/Poly1305 AEAD test vectors from: %% https://tools.ietf.org/html/rfc7539#section-2.8.2 %% https://tools.ietf.org/html/rfc7539#appendix-A.5 chacha20_poly1305() -> hexts([ { "808182838485868788898a8b8c8d8e8f" %% Key "909192939495969798999a9b9c9d9e9f", "4c616469657320616e642047656e746c" %% PlainText "656d656e206f662074686520636c6173" "73206f66202739393a20496620492063" "6f756c64206f6666657220796f75206f" "6e6c79206f6e652074697020666f7220" "746865206675747572652c2073756e73" "637265656e20776f756c642062652069" "742e", "070000004041424344454647", %% IV "50515253c0c1c2c3c4c5c6c7", %% AAD "d31a8d34648e60db7b86afbc53ef7ec2" %% CipherText "a4aded51296e08fea9e2b5a736ee62d6" "3dbea45e8ca9671282fafb69da92728b" "1a71de0a9e060b2905d6a5b67ecd3b36" "92ddbd7f2d778b8c9803aee328091b58" "fab324e4fad675945585808b4831d7bc" "3ff4def08e4b7a9de576d26586cec64b" "6116", "1ae10b594f09e26a7e902ecbd0600691" %% CipherTag }, { "1c9240a5eb55d38af333888604f6b5f0" %% Key "473917c1402b80099dca5cbc207075c0", "496e7465726e65742d44726166747320" %% PlainText "61726520647261667420646f63756d65" "6e74732076616c696420666f72206120" "6d6178696d756d206f6620736978206d" "6f6e74687320616e64206d6179206265" "20757064617465642c207265706c6163" "65642c206f72206f62736f6c65746564" "206279206f7468657220646f63756d65" "6e747320617420616e792074696d652e" "20497420697320696e617070726f7072" "6961746520746f2075736520496e7465" "726e65742d4472616674732061732072" "65666572656e6365206d617465726961" "6c206f7220746f206369746520746865" "6d206f74686572207468616e20617320" "2fe2809c776f726b20696e2070726f67" "726573732e2fe2809d", "000000000102030405060708", %% IV "f33388860000000000004e91", %% AAD "64a0861575861af460f062c79be643bd" %% CipherText "5e805cfd345cf389f108670ac76c8cb2" "4c6cfc18755d43eea09ee94e382d26b0" "bdb7b73c321b0100d4f03b7f355894cf" "332f830e710b97ce98c8a84abd0b9481" "14ad176e008d33bd60f982b1ff37c855" "9797a06ef4f0ef61c186324e2b350638" "3606907b6a7c02b0f9f6157b53c867e4" "b9166c767b804d46a59b5216cde7a4e9" "9040c5a40433225ee282a1b0a06c523e" "af4534d7f83fa1155b0047718cbc546a" "0d072b04b3564eea1b422273f548271a" "0bb2316053fa76991955ebd63159434e" "cebb4e466dae5a1073a6727627097a10" "49e617d91d361094fa68f0ff77987130" "305beaba2eda04df997b714d6c6f2c29" "a6ad5cb4022b02709b", "eead9d67890cbb22392336fea1851f38" %% CipherTag } ]). %% Poly1305 Key Generation test vectors from: %% https://tools.ietf.org/html/rfc7539#appendix-A.4 poly1305_key() -> hexts([ % Test Vector #1 { "00000000000000000000000000000000" %% Key "00000000000000000000000000000000", "000000000000000000000000", %% Nonce "76b8e0ada0f13d90405d6ae55386bd28" %% One-Time Key "bdd219b8a08ded1aa836efcc8b770dc7" }, % Test Vector #2 { "00000000000000000000000000000000" %% Key "00000000000000000000000000000001", "000000000000000000000002", %% Nonce "ecfa254f845f647473d3cb140da9e876" %% One-Time Key "06cb33066c447b87bc2666dde3fbb739" }, % Test Vector #3 { "1c9240a5eb55d38af333888604f6b5f0" %% Key "473917c1402b80099dca5cbc207075c0", "000000000000000000000002", %% Nonce "965e3bc6f9ec7ed9560808f4d229f94b" %% One-Time Key "137ff275ca9b3fcbdd59deaad23310ae" } ]). %% Poly1305 MAC test vectors from: %% https://tools.ietf.org/html/rfc7539#appendix-A.3 poly1305_mac() -> hexts([ % Test Vector #1 { "00000000000000000000000000000000" %% One-Time Key "00000000000000000000000000000000", "00000000000000000000000000000000" %% Text "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000", "00000000000000000000000000000000" %% Tag }, % Test Vector #2 { "00000000000000000000000000000000" %% One-Time Key "36e5f6b5c5e06070f0efca96227a863e", "416e79207375626d697373696f6e2074" %% Text "6f20746865204945544620696e74656e" "6465642062792074686520436f6e7472" "696275746f7220666f72207075626c69" "636174696f6e20617320616c6c206f72" "2070617274206f6620616e2049455446" "20496e7465726e65742d447261667420" "6f722052464320616e6420616e792073" "746174656d656e74206d616465207769" "7468696e2074686520636f6e74657874" "206f6620616e20494554462061637469" "7669747920697320636f6e7369646572" "656420616e20224945544620436f6e74" "7269627574696f6e222e205375636820" "73746174656d656e747320696e636c75" "6465206f72616c2073746174656d656e" "747320696e2049455446207365737369" "6f6e732c2061732077656c6c20617320" "7772697474656e20616e6420656c6563" "74726f6e696320636f6d6d756e696361" "74696f6e73206d61646520617420616e" "792074696d65206f7220706c6163652c" "20776869636820617265206164647265" "7373656420746f", "36e5f6b5c5e06070f0efca96227a863e" %% Tag }, % Test Vector #3 { "36e5f6b5c5e06070f0efca96227a863e" %% One-Time Key "00000000000000000000000000000000", "416e79207375626d697373696f6e2074" %% Text "6f20746865204945544620696e74656e" "6465642062792074686520436f6e7472" "696275746f7220666f72207075626c69" "636174696f6e20617320616c6c206f72" "2070617274206f6620616e2049455446" "20496e7465726e65742d447261667420" "6f722052464320616e6420616e792073" "746174656d656e74206d616465207769" "7468696e2074686520636f6e74657874" "206f6620616e20494554462061637469" "7669747920697320636f6e7369646572" "656420616e20224945544620436f6e74" "7269627574696f6e222e205375636820" "73746174656d656e747320696e636c75" "6465206f72616c2073746174656d656e" "747320696e2049455446207365737369" "6f6e732c2061732077656c6c20617320" "7772697474656e20616e6420656c6563" "74726f6e696320636f6d6d756e696361" "74696f6e73206d61646520617420616e" "792074696d65206f7220706c6163652c" "20776869636820617265206164647265" "7373656420746f", "f3477e7cd95417af89a6b8794c310cf0" %% Tag }, % Test Vector #4 { "1c9240a5eb55d38af333888604f6b5f0" %% One-Time Key "473917c1402b80099dca5cbc207075c0", "2754776173206272696c6c69672c2061" %% Text "6e642074686520736c6974687920746f" "7665730a446964206779726520616e64" "2067696d626c6520696e207468652077" "6162653a0a416c6c206d696d73792077" "6572652074686520626f726f676f7665" "732c0a416e6420746865206d6f6d6520" "7261746873206f757467726162652e", "4541669a7eaaee61e708dc7cbcc5eb62" %% Tag }, % Test Vector #5 { "02000000000000000000000000000000" %% One-Time Key "00000000000000000000000000000000", "ffffffffffffffffffffffffffffffff", %% Text "03000000000000000000000000000000" %% Tag }, % Test Vector #6 { "02000000000000000000000000000000" %% One-Time Key "ffffffffffffffffffffffffffffffff", "02000000000000000000000000000000", %% Text "03000000000000000000000000000000" %% Tag }, % Test Vector #7 { "01000000000000000000000000000000" %% One-Time Key "00000000000000000000000000000000", "ffffffffffffffffffffffffffffffff" %% Text "f0ffffffffffffffffffffffffffffff" "11000000000000000000000000000000", "05000000000000000000000000000000" %% Tag }, % Test Vector #8 { "01000000000000000000000000000000" %% One-Time Key "00000000000000000000000000000000", "ffffffffffffffffffffffffffffffff" %% Text "fbfefefefefefefefefefefefefefefe" "01010101010101010101010101010101", "00000000000000000000000000000000" %% Tag }, % Test Vector #9 { "02000000000000000000000000000000" %% One-Time Key "00000000000000000000000000000000", "fdffffffffffffffffffffffffffffff", %% Text "faffffffffffffffffffffffffffffff" %% Tag }, % Test Vector #10 { "01000000000000000400000000000000" %% One-Time Key "00000000000000000000000000000000", "e33594d7505e43b90000000000000000" %% Text "3394d7505e4379cd0100000000000000" "00000000000000000000000000000000" "01000000000000000000000000000000", "14000000000000005500000000000000" %% Tag }, % Test Vector #11 { "01000000000000000400000000000000" %% One-Time Key "00000000000000000000000000000000", "e33594d7505e43b90000000000000000" %% Text "3394d7505e4379cd0100000000000000" "00000000000000000000000000000000", "13000000000000000000000000000000" %% Tag } ]). erlang-jose-1.10.1/test/cavp_SUITE.erl0000644000232200023220000020636513605433351017752 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 11 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(cavp_SUITE). -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). -include_lib("stdlib/include/zip.hrl"). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([concatenation_kdf/1]). -export([curve25519/1]). -export([curve448/1]). -export([ed25519/1]). -export([ed25519ph/1]). -export([ed448/1]). -export([ed448ph/1]). -export([emc_rsa_oaep_encrypt_and_decrypt/1]). -export([emc_rsa_pss_sign_and_verify/1]). -export([fips_aes_encrypt_and_decrypt/1]). -export([fips_aes_gcm_encrypt_and_decrypt/1]). -export([fips_aeskw_unwrap/1]). -export([fips_aeskw_wrap/1]). -export([fips_rsa_pss_sign/1]). -export([fips_rsa_pss_verify/1]). -export([fips_sha3/1]). -export([pbkdf1/1]). -export([pbkdf2/1]). -export([pkcs7_pad_and_unpad/1]). -export([x25519/1]). -export([x448/1]). %% Macros. -define(tv_ok(T, M, F, A, E), case erlang:apply(M, F, A) of E -> ok; T -> ct:fail({{M, F, A}, {expected, E}, {got, T}}) end). all() -> [ {group, '186-3rsatestvectors'}, {group, 'aesmmt'}, {group, 'curve25519'}, {group, 'curve448'}, {group, 'gcmtestvectors'}, {group, 'KAT_AES'}, {group, 'keccaktestvectors'}, {group, 'kwtestvectors'}, {group, 'nist-800-56A'}, {group, 'pkcs-1v2-1-vec'}, {group, 'pkcs-5'}, {group, 'pkcs-7'} ]. groups() -> [ {'186-3rsatestvectors', [parallel], [ fips_rsa_pss_sign, fips_rsa_pss_verify ]}, {'aesmmt', [], [ fips_aes_encrypt_and_decrypt ]}, {'curve25519', [parallel], [ curve25519, ed25519, ed25519ph, x25519 ]}, {'curve448', [parallel], [ curve448, ed448, ed448ph, x448 ]}, {'gcmtestvectors', [], [ fips_aes_gcm_encrypt_and_decrypt ]}, {'KAT_AES', [], [ fips_aes_encrypt_and_decrypt ]}, {'keccaktestvectors', [], [ fips_sha3 ]}, {'kwtestvectors', [parallel], [ fips_aeskw_unwrap, fips_aeskw_wrap ]}, {'nist-800-56A', [], [ concatenation_kdf ]}, {'pkcs-1v2-1-vec', [parallel], [ emc_rsa_oaep_encrypt_and_decrypt, emc_rsa_pss_sign_and_verify ]}, {'pkcs-5', [parallel], [ pbkdf1, pbkdf2 ]}, {'pkcs-7', [], [ pkcs7_pad_and_unpad ]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), data_setup(Config). end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(G='186-3rsatestvectors', Config) -> SigGenFile = data_file("186-3rsatestvectors/SigGenPSS_186-3.txt", Config), SigVerFile = data_file("186-3rsatestvectors/SigVerPSS_186-3.rsp", Config), [{sig_gen_file, SigGenFile}, {sig_ver_file, SigVerFile} | jose_ct:start(G, Config)]; init_per_group(G='aesmmt', Config) -> Folder = data_file("aesmmt", Config), {ok, Entries} = file:list_dir(Folder), Files = [filename:join([Folder, Entry]) || Entry <- Entries], [{aes_files, Files} | jose_ct:start(G, Config)]; init_per_group(G='curve25519', Config) -> [ {curve25519, [ { 31029842492115040904895560451863089656472772604678260265531221036453811406496, % Input scalar 34426434033919594451155107781188821651316167215306631574996226621102155684838, % Input u-coordinate hexstr2lint("c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552") % Output u-coordinate }, { 35156891815674817266734212754503633747128614016119564763269015315466259359304, % Input scalar 8883857351183929894090759386610649319417338800022198945255395922347792736741, % Input u-coordinate hexstr2lint("95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957") % Output u-coordinate } ]}, {ed25519, [ { % TEST 1 hexstr2bin( "9d61b19deffd5a60ba844af492ec2cc4" "4449c5697b326919703bac031cae7f60"), % SECRET KEY hexstr2bin( "d75a980182b10ab7d54bfed3c964073a" "0ee172f3daa62325af021a68f707511a"), % PUBLIC KEY <<>>, % MESSAGE hexstr2bin( "e5564300c360ac729086e2cc806e828a" "84877f1eb8e5d974d873e06522490155" "5fb8821590a33bacc61e39701cf9b46b" "d25bf5f0595bbe24655141438e7a100b") % SIGNATURE }, { % TEST 2 hexstr2bin( "4ccd089b28ff96da9db6c346ec114e0f" "5b8a319f35aba624da8cf6ed4fb8a6fb"), % SECRET KEY hexstr2bin( "3d4017c3e843895a92b70aa74d1b7ebc" "9c982ccf2ec4968cc0cd55f12af4660c"), % PUBLIC KEY hexstr2bin("72"), % MESSAGE hexstr2bin( "92a009a9f0d4cab8720e820b5f642540" "a2b27b5416503f8fb3762223ebdb69da" "085ac1e43e15996e458f3613d0f11d8c" "387b2eaeb4302aeeb00d291612bb0c00") % SIGNATURE }, { % TEST 3 hexstr2bin( "c5aa8df43f9f837bedb7442f31dcb7b1" "66d38535076f094b85ce3a2e0b4458f7"), % SECRET KEY hexstr2bin( "fc51cd8e6218a1a38da47ed00230f058" "0816ed13ba3303ac5deb911548908025"), % PUBLIC KEY hexstr2bin("af82"), % MESSAGE hexstr2bin( "6291d657deec24024827e69c3abe01a3" "0ce548a284743a445e3680d7db5ac3ac" "18ff9b538d16f290ae67f760984dc659" "4a7c15e9716ed28dc027beceea1ec40a") % SIGNATURE }, { % TEST 1024 hexstr2bin( "f5e5767cf153319517630f226876b86c" "8160cc583bc013744c6bf255f5cc0ee5"), % SECRET KEY hexstr2bin( "278117fc144c72340f67d0f2316e8386" "ceffbf2b2428c9c51fef7c597f1d426e"), % PUBLIC KEY hexstr2bin( "08b8b2b733424243760fe426a4b54908" "632110a66c2f6591eabd3345e3e4eb98" "fa6e264bf09efe12ee50f8f54e9f77b1" "e355f6c50544e23fb1433ddf73be84d8" "79de7c0046dc4996d9e773f4bc9efe57" "38829adb26c81b37c93a1b270b20329d" "658675fc6ea534e0810a4432826bf58c" "941efb65d57a338bbd2e26640f89ffbc" "1a858efcb8550ee3a5e1998bd177e93a" "7363c344fe6b199ee5d02e82d522c4fe" "ba15452f80288a821a579116ec6dad2b" "3b310da903401aa62100ab5d1a36553e" "06203b33890cc9b832f79ef80560ccb9" "a39ce767967ed628c6ad573cb116dbef" "efd75499da96bd68a8a97b928a8bbc10" "3b6621fcde2beca1231d206be6cd9ec7" "aff6f6c94fcd7204ed3455c68c83f4a4" "1da4af2b74ef5c53f1d8ac70bdcb7ed1" "85ce81bd84359d44254d95629e9855a9" "4a7c1958d1f8ada5d0532ed8a5aa3fb2" "d17ba70eb6248e594e1a2297acbbb39d" "502f1a8c6eb6f1ce22b3de1a1f40cc24" "554119a831a9aad6079cad88425de6bd" "e1a9187ebb6092cf67bf2b13fd65f270" "88d78b7e883c8759d2c4f5c65adb7553" "878ad575f9fad878e80a0c9ba63bcbcc" "2732e69485bbc9c90bfbd62481d9089b" "eccf80cfe2df16a2cf65bd92dd597b07" "07e0917af48bbb75fed413d238f5555a" "7a569d80c3414a8d0859dc65a46128ba" "b27af87a71314f318c782b23ebfe808b" "82b0ce26401d2e22f04d83d1255dc51a" "ddd3b75a2b1ae0784504df543af8969b" "e3ea7082ff7fc9888c144da2af58429e" "c96031dbcad3dad9af0dcbaaaf268cb8" "fcffead94f3c7ca495e056a9b47acdb7" "51fb73e666c6c655ade8297297d07ad1" "ba5e43f1bca32301651339e22904cc8c" "42f58c30c04aafdb038dda0847dd988d" "cda6f3bfd15c4b4c4525004aa06eeff8" "ca61783aacec57fb3d1f92b0fe2fd1a8" "5f6724517b65e614ad6808d6f6ee34df" "f7310fdc82aebfd904b01e1dc54b2927" "094b2db68d6f903b68401adebf5a7e08" "d78ff4ef5d63653a65040cf9bfd4aca7" "984a74d37145986780fc0b16ac451649" "de6188a7dbdf191f64b5fc5e2ab47b57" "f7f7276cd419c17a3ca8e1b939ae49e4" "88acba6b965610b5480109c8b17b80e1" "b7b750dfc7598d5d5011fd2dcc5600a3" "2ef5b52a1ecc820e308aa342721aac09" "43bf6686b64b2579376504ccc493d97e" "6aed3fb0f9cd71a43dd497f01f17c0e2" "cb3797aa2a2f256656168e6c496afc5f" "b93246f6b1116398a346f1a641f3b041" "e989f7914f90cc2c7fff357876e506b5" "0d334ba77c225bc307ba537152f3f161" "0e4eafe595f6d9d90d11faa933a15ef1" "369546868a7f3a45a96768d40fd9d034" "12c091c6315cf4fde7cb68606937380d" "b2eaaa707b4c4185c32eddcdd306705e" "4dc1ffc872eeee475a64dfac86aba41c" "0618983f8741c5ef68d3a101e8a3b8ca" "c60c905c15fc910840b94c00a0b9d0"), % MESSAGE hexstr2bin( "0aab4c900501b3e24d7cdf4663326a3a" "87df5e4843b2cbdb67cbf6e460fec350" "aa5371b1508f9f4528ecea23c436d94b" "5e8fcd4f681e30a6ac00a9704a188a03") % SIGNATURE }, { % TEST SHA(abc) hexstr2bin( "833fe62409237b9d62ec77587520911e" "9a759cec1d19755b7da901b96dca3d42"), % SECRET KEY hexstr2bin( "ec172b93ad5e563bf4932c70e1245034" "c35467ef2efd4d64ebf819683467e2bf"), % PUBLIC KEY hexstr2bin( "ddaf35a193617abacc417349ae204131" "12e6fa4e89a97ea20a9eeee64b55d39a" "2192992a274fc1a836ba3c23a3feebbd" "454d4423643ce80e2a9ac94fa54ca49f"), % MESSAGE hexstr2bin( "dc2a4459e7369633a52b1bf277839a00" "201009a3efbf3ecb69bea2186c26b589" "09351fc9ac90b3ecfdfbc7c66431e030" "3dca179c138ac17ad9bef1177331a704") % SIGNATURE } ]}, {ed25519ph, [ { % TEST abc hexstr2bin( "833fe62409237b9d62ec77587520911e" "9a759cec1d19755b7da901b96dca3d42"), % SECRET KEY hexstr2bin( "ec172b93ad5e563bf4932c70e1245034" "c35467ef2efd4d64ebf819683467e2bf"), % PUBLIC KEY hexstr2bin("616263"), % MESSAGE hexstr2bin( "dc2a4459e7369633a52b1bf277839a00" "201009a3efbf3ecb69bea2186c26b589" "09351fc9ac90b3ecfdfbc7c66431e030" "3dca179c138ac17ad9bef1177331a704") % SIGNATURE } ]}, {x25519, [ { hexstr2bin("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"), % Alice's private key, f hexstr2bin("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"), % Alice's public key, X25519(f, 9) hexstr2bin("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"), % Bob's private key, g hexstr2bin("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"), % Bob's public key, X25519(g, 9) hexstr2bin("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742") % Their shared secret, K } ]} | jose_ct:start(G, Config) ]; init_per_group(G='curve448', Config) -> [ {curve448, [ { 599189175373896402783756016145213256157230856085026129926891459468622403380588640249457727683869421921443004045221642549886377526240828, % Input scalar 382239910814107330116229961234899377031416365240571325148346555922438025162094455820962429142971339584360034337310079791515452463053830, % Input u-coordinate hexstr2lint("ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f") % Output u-coordinate }, { 633254335906970592779259481534862372382525155252028961056404001332122152890562527156973881968934311400345568203929409663925541994577184, % Input scalar 622761797758325444462922068431234180649590390024811299761625153767228042600197997696167956134770744996690267634159427999832340166786063, % Input u-coordinate hexstr2lint("884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d") % Output u-coordinate } ]}, {ed448, [ { % Blank hexstr2bin( "6c82a562cb808d10d632be89c8513ebf" "6c929f34ddfa8c9f63c9960ef6e348a3" "528c8a3fcc2f044e39a3fc5b94492f8f" "032e7549a20098f95b"), % SECRET KEY hexstr2bin( "5fd7449b59b461fd2ce787ec616ad46a" "1da1342485a70e1f8a0ea75d80e96778" "edf124769b46c7061bd6783df1e50f6c" "d1fa1abeafe8256180"), % PUBLIC KEY <<>>, % MESSAGE hexstr2bin( "533a37f6bbe457251f023c0d88f976ae" "2dfb504a843e34d2074fd823d41a591f" "2b233f034f628281f2fd7a22ddd47d78" "28c59bd0a21bfd3980ff0d2028d4b18a" "9df63e006c5d1c2d345b925d8dc00b41" "04852db99ac5c7cdda8530a113a0f4db" "b61149f05a7363268c71d95808ff2e65" "2600") % SIGNATURE }, { % 1 octet hexstr2bin( "c4eab05d357007c632f3dbb48489924d" "552b08fe0c353a0d4a1f00acda2c463a" "fbea67c5e8d2877c5e3bc397a659949e" "f8021e954e0a12274e"), % SECRET KEY hexstr2bin( "43ba28f430cdff456ae531545f7ecd0a" "c834a55d9358c0372bfa0c6c6798c086" "6aea01eb00742802b8438ea4cb82169c" "235160627b4c3a9480"), % PUBLIC KEY hexstr2bin("03"), % MESSAGE hexstr2bin( "26b8f91727bd62897af15e41eb43c377" "efb9c610d48f2335cb0bd0087810f435" "2541b143c4b981b7e18f62de8ccdf633" "fc1bf037ab7cd779805e0dbcc0aae1cb" "cee1afb2e027df36bc04dcecbf154336" "c19f0af7e0a6472905e799f1953d2a0f" "f3348ab21aa4adafd1d234441cf807c0" "3a00") % SIGNATURE }, { % 1 octet (with context) hexstr2bin( "c4eab05d357007c632f3dbb48489924d" "552b08fe0c353a0d4a1f00acda2c463a" "fbea67c5e8d2877c5e3bc397a659949e" "f8021e954e0a12274e"), % SECRET KEY hexstr2bin( "43ba28f430cdff456ae531545f7ecd0a" "c834a55d9358c0372bfa0c6c6798c086" "6aea01eb00742802b8438ea4cb82169c" "235160627b4c3a9480"), % PUBLIC KEY hexstr2bin("03"), % MESSAGE hexstr2bin("666f6f"), % CONTEXT hexstr2bin( "d4f8f6131770dd46f40867d6fd5d5055" "de43541f8c5e35abbcd001b32a89f7d2" "151f7647f11d8ca2ae279fb842d60721" "7fce6e042f6815ea000c85741de5c8da" "1144a6a1aba7f96de42505d7a7298524" "fda538fccbbb754f578c1cad10d54d0d" "5428407e85dcbc98a49155c13764e66c" "3c00") % SIGNATURE }, { % 11 octets hexstr2bin( "cd23d24f714274e744343237b93290f5" "11f6425f98e64459ff203e8985083ffd" "f60500553abc0e05cd02184bdb89c4cc" "d67e187951267eb328"), % SECRET KEY hexstr2bin( "dcea9e78f35a1bf3499a831b10b86c90" "aac01cd84b67a0109b55a36e9328b1e3" "65fce161d71ce7131a543ea4cb5f7e9f" "1d8b00696447001400"), % PUBLIC KEY hexstr2bin("0c3e544074ec63b0265e0c"), % MESSAGE hexstr2bin( "1f0a8888ce25e8d458a21130879b840a" "9089d999aaba039eaf3e3afa090a09d3" "89dba82c4ff2ae8ac5cdfb7c55e94d5d" "961a29fe0109941e00b8dbdeea6d3b05" "1068df7254c0cdc129cbe62db2dc957d" "bb47b51fd3f213fb8698f064774250a5" "028961c9bf8ffd973fe5d5c206492b14" "0e00") % SIGNATURE }, { % 12 octets hexstr2bin( "258cdd4ada32ed9c9ff54e63756ae582" "fb8fab2ac721f2c8e676a72768513d93" "9f63dddb55609133f29adf86ec9929dc" "cb52c1c5fd2ff7e21b"), % SECRET KEY hexstr2bin( "3ba16da0c6f2cc1f30187740756f5e79" "8d6bc5fc015d7c63cc9510ee3fd44adc" "24d8e968b6e46e6f94d19b945361726b" "d75e149ef09817f580"), % PUBLIC KEY hexstr2bin("64a65f3cdedcdd66811e2915"), % MESSAGE hexstr2bin( "7eeeab7c4e50fb799b418ee5e3197ff6" "bf15d43a14c34389b59dd1a7b1b85b4a" "e90438aca634bea45e3a2695f1270f07" "fdcdf7c62b8efeaf00b45c2c96ba457e" "b1a8bf075a3db28e5c24f6b923ed4ad7" "47c3c9e03c7079efb87cb110d3a99861" "e72003cbae6d6b8b827e4e6c143064ff" "3c00") % SIGNATURE }, { % 13 octets hexstr2bin( "7ef4e84544236752fbb56b8f31a23a10" "e42814f5f55ca037cdcc11c64c9a3b29" "49c1bb60700314611732a6c2fea98eeb" "c0266a11a93970100e"), % SECRET KEY hexstr2bin( "b3da079b0aa493a5772029f0467baebe" "e5a8112d9d3a22532361da294f7bb381" "5c5dc59e176b4d9f381ca0938e13c6c0" "7b174be65dfa578e80"), % PUBLIC KEY hexstr2bin("64a65f3cdedcdd66811e2915e7"), % MESSAGE hexstr2bin( "6a12066f55331b6c22acd5d5bfc5d712" "28fbda80ae8dec26bdd306743c5027cb" "4890810c162c027468675ecf645a8317" "6c0d7323a2ccde2d80efe5a1268e8aca" "1d6fbc194d3f77c44986eb4ab4177919" "ad8bec33eb47bbb5fc6e28196fd1caf5" "6b4e7e0ba5519234d047155ac727a105" "3100") % SIGNATURE }, { % 64 octets hexstr2bin( "d65df341ad13e008567688baedda8e9d" "cdc17dc024974ea5b4227b6530e339bf" "f21f99e68ca6968f3cca6dfe0fb9f4fa" "b4fa135d5542ea3f01"), % SECRET KEY hexstr2bin( "df9705f58edbab802c7f8363cfe5560a" "b1c6132c20a9f1dd163483a26f8ac53a" "39d6808bf4a1dfbd261b099bb03b3fb5" "0906cb28bd8a081f00"), % PUBLIC KEY hexstr2bin( "bd0f6a3747cd561bdddf4640a332461a" "4a30a12a434cd0bf40d766d9c6d458e5" "512204a30c17d1f50b5079631f64eb31" "12182da3005835461113718d1a5ef944"), % MESSAGE hexstr2bin( "554bc2480860b49eab8532d2a533b7d5" "78ef473eeb58c98bb2d0e1ce488a98b1" "8dfde9b9b90775e67f47d4a1c3482058" "efc9f40d2ca033a0801b63d45b3b722e" "f552bad3b4ccb667da350192b61c508c" "f7b6b5adadc2c8d9a446ef003fb05cba" "5f30e88e36ec2703b349ca229c267083" "3900") % SIGNATURE }, { % 64 octets hexstr2bin( "d65df341ad13e008567688baedda8e9d" "cdc17dc024974ea5b4227b6530e339bf" "f21f99e68ca6968f3cca6dfe0fb9f4fa" "b4fa135d5542ea3f01"), % SECRET KEY hexstr2bin( "df9705f58edbab802c7f8363cfe5560a" "b1c6132c20a9f1dd163483a26f8ac53a" "39d6808bf4a1dfbd261b099bb03b3fb5" "0906cb28bd8a081f00"), % PUBLIC KEY hexstr2bin( "bd0f6a3747cd561bdddf4640a332461a" "4a30a12a434cd0bf40d766d9c6d458e5" "512204a30c17d1f50b5079631f64eb31" "12182da3005835461113718d1a5ef944"), % MESSAGE hexstr2bin( "554bc2480860b49eab8532d2a533b7d5" "78ef473eeb58c98bb2d0e1ce488a98b1" "8dfde9b9b90775e67f47d4a1c3482058" "efc9f40d2ca033a0801b63d45b3b722e" "f552bad3b4ccb667da350192b61c508c" "f7b6b5adadc2c8d9a446ef003fb05cba" "5f30e88e36ec2703b349ca229c267083" "3900") % SIGNATURE }, { % 256 octets hexstr2bin( "2ec5fe3c17045abdb136a5e6a913e32a" "b75ae68b53d2fc149b77e504132d3756" "9b7e766ba74a19bd6162343a21c8590a" "a9cebca9014c636df5"), % SECRET KEY hexstr2bin( "79756f014dcfe2079f5dd9e718be4171" "e2ef2486a08f25186f6bff43a9936b9b" "fe12402b08ae65798a3d81e22e9ec80e" "7690862ef3d4ed3a00"), % PUBLIC KEY hexstr2bin( "15777532b0bdd0d1389f636c5f6b9ba7" "34c90af572877e2d272dd078aa1e567c" "fa80e12928bb542330e8409f31745041" "07ecd5efac61ae7504dabe2a602ede89" "e5cca6257a7c77e27a702b3ae39fc769" "fc54f2395ae6a1178cab4738e543072f" "c1c177fe71e92e25bf03e4ecb72f47b6" "4d0465aaea4c7fad372536c8ba516a60" "39c3c2a39f0e4d832be432dfa9a706a6" "e5c7e19f397964ca4258002f7c0541b5" "90316dbc5622b6b2a6fe7a4abffd9610" "5eca76ea7b98816af0748c10df048ce0" "12d901015a51f189f3888145c03650aa" "23ce894c3bd889e030d565071c59f409" "a9981b51878fd6fc110624dcbcde0bf7" "a69ccce38fabdf86f3bef6044819de11"), % MESSAGE hexstr2bin( "c650ddbb0601c19ca11439e1640dd931" "f43c518ea5bea70d3dcde5f4191fe53f" "00cf966546b72bcc7d58be2b9badef28" "743954e3a44a23f880e8d4f1cfce2d7a" "61452d26da05896f0a50da66a239a8a1" "88b6d825b3305ad77b73fbac0836ecc6" "0987fd08527c1a8e80d5823e65cafe2a" "3d00") % SIGNATURE }, { % 1023 octets hexstr2bin( "872d093780f5d3730df7c212664b37b8" "a0f24f56810daa8382cd4fa3f77634ec" "44dc54f1c2ed9bea86fafb7632d8be19" "9ea165f5ad55dd9ce8"), % SECRET KEY hexstr2bin( "a81b2e8a70a5ac94ffdbcc9badfc3feb" "0801f258578bb114ad44ece1ec0e799d" "a08effb81c5d685c0c56f64eecaef8cd" "f11cc38737838cf400"), % PUBLIC KEY hexstr2bin( "6ddf802e1aae4986935f7f981ba3f035" "1d6273c0a0c22c9c0e8339168e675412" "a3debfaf435ed651558007db4384b650" "fcc07e3b586a27a4f7a00ac8a6fec2cd" "86ae4bf1570c41e6a40c931db27b2faa" "15a8cedd52cff7362c4e6e23daec0fbc" "3a79b6806e316efcc7b68119bf46bc76" "a26067a53f296dafdbdc11c77f7777e9" "72660cf4b6a9b369a6665f02e0cc9b6e" "dfad136b4fabe723d2813db3136cfde9" "b6d044322fee2947952e031b73ab5c60" "3349b307bdc27bc6cb8b8bbd7bd32321" "9b8033a581b59eadebb09b3c4f3d2277" "d4f0343624acc817804728b25ab79717" "2b4c5c21a22f9c7839d64300232eb66e" "53f31c723fa37fe387c7d3e50bdf9813" "a30e5bb12cf4cd930c40cfb4e1fc6225" "92a49588794494d56d24ea4b40c89fc0" "596cc9ebb961c8cb10adde976a5d602b" "1c3f85b9b9a001ed3c6a4d3b1437f520" "96cd1956d042a597d561a596ecd3d173" "5a8d570ea0ec27225a2c4aaff26306d1" "526c1af3ca6d9cf5a2c98f47e1c46db9" "a33234cfd4d81f2c98538a09ebe76998" "d0d8fd25997c7d255c6d66ece6fa56f1" "1144950f027795e653008f4bd7ca2dee" "85d8e90f3dc315130ce2a00375a318c7" "c3d97be2c8ce5b6db41a6254ff264fa6" "155baee3b0773c0f497c573f19bb4f42" "40281f0b1f4f7be857a4e59d416c06b4" "c50fa09e1810ddc6b1467baeac5a3668" "d11b6ecaa901440016f389f80acc4db9" "77025e7f5924388c7e340a732e554440" "e76570f8dd71b7d640b3450d1fd5f041" "0a18f9a3494f707c717b79b4bf75c984" "00b096b21653b5d217cf3565c9597456" "f70703497a078763829bc01bb1cbc8fa" "04eadc9a6e3f6699587a9e75c94e5bab" "0036e0b2e711392cff0047d0d6b05bd2" "a588bc109718954259f1d86678a579a3" "120f19cfb2963f177aeb70f2d4844826" "262e51b80271272068ef5b3856fa8535" "aa2a88b2d41f2a0e2fda7624c2850272" "ac4a2f561f8f2f7a318bfd5caf969614" "9e4ac824ad3460538fdc25421beec2cc" "6818162d06bbed0c40a387192349db67" "a118bada6cd5ab0140ee273204f628aa" "d1c135f770279a651e24d8c14d75a605" "9d76b96a6fd857def5e0b354b27ab937" "a5815d16b5fae407ff18222c6d1ed263" "be68c95f32d908bd895cd76207ae7264" "87567f9a67dad79abec316f683b17f2d" "02bf07e0ac8b5bc6162cf94697b3c27c" "d1fea49b27f23ba2901871962506520c" "392da8b6ad0d99f7013fbc06c2c17a56" "9500c8a7696481c1cd33e9b14e40b82e" "79a5f5db82571ba97bae3ad3e0479515" "bb0e2b0f3bfcd1fd33034efc6245eddd" "7ee2086ddae2600d8ca73e214e8c2b0b" "db2b047c6a464a562ed77b73d2d841c4" "b34973551257713b753632efba348169" "abc90a68f42611a40126d7cb21b58695" "568186f7e569d2ff0f9e745d0487dd2e" "b997cafc5abf9dd102e62ff66cba87"), % MESSAGE hexstr2bin( "e301345a41a39a4d72fff8df69c98075" "a0cc082b802fc9b2b6bc503f926b65bd" "df7f4c8f1cb49f6396afc8a70abe6d8a" "ef0db478d4c6b2970076c6a0484fe76d" "76b3a97625d79f1ce240e7c576750d29" "5528286f719b413de9ada3e8eb78ed57" "3603ce30d8bb761785dc30dbc320869e" "1a00") % SIGNATURE } ]}, {ed448ph, [ { % TEST abc hexstr2bin( "833fe62409237b9d62ec77587520911e" "9a759cec1d19755b7da901b96dca3d42" "ef7822e0d5104127dc05d6dbefde69e3" "ab2cec7c867c6e2c49"), % SECRET KEY hexstr2bin( "259b71c19f83ef77a7abd26524cbdb31" "61b590a48f7d17de3ee0ba9c52beb743" "c09428a131d6b1b57303d90d8132c276" "d5ed3d5d01c0f53880"), % PUBLIC KEY hexstr2bin("616263"), % MESSAGE hexstr2bin( "963cf799d20fdf51c460310c1cf65d0e" "83c4ef5aa73332ba5b4c1e7635ff9e9b" "6a12b16436fa3681b92575e7eba40ee2" "79c487ad724b6d1080e1860e63dbdd58" "9f5125505b4de024264625e61b097956" "8703f9d9e2bbf5523a1886ee6da1ecb2" "0552bb506eb35a042658ec534bfc1c2c" "1a00") % SIGNATURE }, { % TEST abc (with context) hexstr2bin( "833fe62409237b9d62ec77587520911e" "9a759cec1d19755b7da901b96dca3d42" "ef7822e0d5104127dc05d6dbefde69e3" "ab2cec7c867c6e2c49"), % SECRET KEY hexstr2bin( "259b71c19f83ef77a7abd26524cbdb31" "61b590a48f7d17de3ee0ba9c52beb743" "c09428a131d6b1b57303d90d8132c276" "d5ed3d5d01c0f53880"), % PUBLIC KEY hexstr2bin("616263"), % MESSAGE hexstr2bin("666f6f"), % CONTEXT hexstr2bin( "86a6bf52f9e8f84f451b2f392a8d1c3a" "414425fac0068f74aeead53b0e6b53d4" "555cea1726da4a65202880d407267087" "9e8e6fa4d9694c060054f2065dc206a6" "e615d0d8c99b95209b696c8125c5fbb9" "bc82a0f7ed3d99c4c11c47798ef0f7eb" "97b3b72ab4ac86eaf8b43449e8ac30ff" "3f00") % SIGNATURE } ]}, {x448, [ { hexstr2bin("9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b"), % Alice's private key, f hexstr2bin("9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0"), % Alice's public key, X448(f, 9) hexstr2bin("1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d"), % Bob's private key, g hexstr2bin("3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609"), % Bob's public key, X448(g, 9) hexstr2bin("07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d") % Their shared secret, K } ]} | jose_ct:start(G, Config) ]; init_per_group(G='gcmtestvectors', Config) -> Folder = data_file("gcmtestvectors", Config), {ok, Entries} = file:list_dir(Folder), Files = [filename:join([Folder, Entry]) || Entry <- Entries], [{aes_gcm_files, Files}, {one_in, 10} | jose_ct:start(G, Config)]; init_per_group(G='KAT_AES', Config) -> Folder = data_file("KAT_AES", Config), {ok, Entries} = file:list_dir(Folder), Files = [filename:join([Folder, Entry]) || Entry <- Entries], [{aes_files, Files} | jose_ct:start(G, Config)]; init_per_group(G='keccaktestvectors', Config) -> Folder = data_file("keccaktestvectors", Config), {ok, Entries} = file:list_dir(Folder), Files = [filename:join([Folder, Entry]) || Entry <- Entries], [{sha3_files, Files} | jose_ct:start(G, Config)]; init_per_group(G='kwtestvectors', Config) -> Folder = data_file("kwtestvectors", Config), {ok, Entries} = file:list_dir(Folder), Files = [filename:join([Folder, Entry]) || Entry <- Entries], [{aeskw_files, Files}, {one_in, 5} | jose_ct:start(G, Config)]; init_per_group(G='nist-800-56A', Config) -> Vectors = [ %% See [https://tools.ietf.org/html/rfc7518#appendix-C] {sha256, <<158,86,217,29,129,113,53,211,114,131,66,131,191,132,38,156,251,49,110,163,218,128,106,72,246,218,167,121,140,254,144,196>>, {<<"A128GCM">>, <<"Alice">>, <<"Bob">>, << 0, 0, 0, 128 >>, <<>>}, 128, <<86,170,141,234,248,35,109,32,92,34,40,205,113,167,16,26>>}, %% See [https://bitbucket.org/b_c/jose4j/src/cb968fdb10bdef6ecedf279b030f9b3af59f5e8e/src/test/java/org/jose4j/jwe/kdf/ConcatKeyDerivationFunctionTest.java] {sha256, jose_jwa_base64url:decode(<<"Sq8rGLm4rEtzScmnSsY5r1n-AqBl_iBU8FxN80Uc0S0">>), {<<"A256CBC-HS512">>, <<>>, <<>>, << 0, 0, 2, 0 >>, <<>>}, 512, jose_jwa_base64url:decode(<<"pgs50IOZ6BxfqvTSie4t9OjWxGr4whiHo1v9Dti93CRiJE2PP60FojLatVVrcjg3BxpuFjnlQxL97GOwAfcwLA">>)}, {sha256, jose_jwa_base64url:decode(<<"LfkHot2nGTVlmfxbgxQfMg">>), {<<"A128CBC-HS256">>, <<>>, <<>>, << 0, 0, 1, 0 >>, <<>>}, 256, jose_jwa_base64url:decode(<<"vphyobtvExGXF7TaOvAkx6CCjHQNYamP2ET8xkhTu-0">>)}, {sha256, jose_jwa_base64url:decode(<<"KSDnQpf2iurUsAbcuI4YH-FKfk2gecN6cWHTYlBzrd8">>), {<<"meh">>, <<"Alice">>, <<"Bob">>, << 0, 0, 4, 0 >>, <<>>}, 1024, jose_jwa_base64url:decode(<<"yRbmmZJpxv3H1aq3FgzESa453frljIaeMz6pt5rQZ4Q5Hs-4RYoFRXFh_qBsbTjlsj8JxIYTWj-cp5LKtgi1fBRsf_5yTEcLDv4pKH2fNxjbEOKuVVDWA1_Qv2IkEC0_QSi3lSSELcJaNX-hDG8occ7oQv-w8lg6lLJjg58kOes">>)}, {sha256, jose_jwa_base64url:decode(<<"zp9Hot2noTVlmfxbkXqfn1">>), {<<"A192CBC-HS384">>, <<>>, <<>>, << 0, 0, 1, 128 >>, <<>>}, 384, jose_jwa_base64url:decode(<<"SNOvl6h5iSYWJ_EhlnvK8o6om9iyR8HkKMQtQYGkYKkVY0HFMleoUm-H6-kLz8sW">>)} ], [{vectors, Vectors} | jose_ct:start(G, Config)]; init_per_group(G='pkcs-1v2-1-vec', Config) -> OAEPVectFile = data_file("pkcs-1v2-1-vec/oaep-vect.txt", Config), PSSVectFile = data_file("pkcs-1v2-1-vec/pss-vect.txt", Config), [{oaep_vect_file, OAEPVectFile}, {pss_vect_file, PSSVectFile} | jose_ct:start(G, Config)]; init_per_group(G='pkcs-5', Config) -> PBKDF1Vectors = [ %% See [https://github.com/erlang/otp/blob/OTP-18.0/lib/public_key/test/pbe_SUITE.erl] {sha, <<"password">>, <<16#78,16#57,16#8E,16#5A,16#5D,16#63,16#CB,16#06>>, 1000, 16, << 16#DC, 16#19, 16#84, 16#7E, 16#05, 16#C6, 16#4D, 16#2F, 16#AF, 16#10, 16#EB, 16#FB, 16#4A, 16#3D, 16#2A, 16#20 >>} ], PBKDF2Vectors = [ %% See [https://tools.ietf.org/html/rfc6070] {sha, <<"password">>, <<"salt">>, 1, 20, hex:hex_to_bin(<<"0c60c80f961f0e71f3a9b524af6012062fe037a6">>)}, {sha, <<"password">>, <<"salt">>, 2, 20, hex:hex_to_bin(<<"ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957">>)}, {sha, <<"password">>, <<"salt">>, 4096, 20, hex:hex_to_bin(<<"4b007901b765489abead49d926f721d065a429c1">>)}, {sha, <<"password">>, <<"salt">>, 16777216, 20, hex:hex_to_bin(<<"eefe3d61cd4da4e4e9945b3d6ba2158c2634e984">>)}, {sha, <<"passwordPASSWORDpassword">>, <<"saltSALTsaltSALTsaltSALTsaltSALTsalt">>, 4096, 25, hex:hex_to_bin(<<"3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038">>)}, {sha, <<"pass\0word">>, <<"sa\0lt">>, 4096, 16, hex:hex_to_bin(<<"56fa6aa75548099dcc37d7f03425e0c3">>)}, %% See [http://stackoverflow.com/a/5136918/818187] {sha256, <<"password">>, <<"salt">>, 1, 32, hex:hex_to_bin(<<"120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b">>)}, {sha256, <<"password">>, <<"salt">>, 2, 32, hex:hex_to_bin(<<"ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43">>)}, {sha256, <<"password">>, <<"salt">>, 4096, 32, hex:hex_to_bin(<<"c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a">>)}, {sha256, <<"password">>, <<"salt">>, 16777216, 32, hex:hex_to_bin(<<"cf81c66fe8cfc04d1f31ecb65dab4089f7f179e89b3b0bcb17ad10e3ac6eba46">>)}, {sha256, <<"passwordPASSWORDpassword">>, <<"saltSALTsaltSALTsaltSALTsaltSALTsalt">>, 4096, 40, hex:hex_to_bin(<<"348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9">>)}, {sha256, <<"pass\0word">>, <<"sa\0lt">>, 4096, 16, hex:hex_to_bin(<<"89b69d0516f829893c696226650a8687">>)} ], [{pbkdf1_vectors, PBKDF1Vectors}, {pbkdf2_vectors, PBKDF2Vectors} | jose_ct:start(G, Config)]; init_per_group(G='pkcs-7', Config) -> Vectors = [begin {hex:hex_to_bin(K), hex:hex_to_bin(V)} end || {K, V} <- [ {<< >>, <<"10101010101010101010101010101010">>}, {<<"00" >>, <<"000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f">>}, {<<"0000" >>, <<"00000e0e0e0e0e0e0e0e0e0e0e0e0e0e">>}, {<<"000000" >>, <<"0000000d0d0d0d0d0d0d0d0d0d0d0d0d">>}, {<<"00000000" >>, <<"000000000c0c0c0c0c0c0c0c0c0c0c0c">>}, {<<"0000000000" >>, <<"00000000000b0b0b0b0b0b0b0b0b0b0b">>}, {<<"000000000000" >>, <<"0000000000000a0a0a0a0a0a0a0a0a0a">>}, {<<"00000000000000" >>, <<"00000000000000090909090909090909">>}, {<<"0000000000000000" >>, <<"00000000000000000808080808080808">>}, {<<"000000000000000000" >>, <<"00000000000000000007070707070707">>}, {<<"00000000000000000000" >>, <<"00000000000000000000060606060606">>}, {<<"0000000000000000000000" >>, <<"00000000000000000000000505050505">>}, {<<"000000000000000000000000" >>, <<"00000000000000000000000004040404">>}, {<<"00000000000000000000000000" >>, <<"00000000000000000000000000030303">>}, {<<"0000000000000000000000000000" >>, <<"00000000000000000000000000000202">>}, {<<"000000000000000000000000000000" >>, <<"00000000000000000000000000000001">>}, {<<"00000000000000000000000000000000">>, <<"0000000000000000000000000000000010101010101010101010101010101010">>} ]], [{vectors, Vectors} | jose_ct:start(G, Config)]. end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== concatenation_kdf(Config) -> Vectors = ?config(vectors, Config), concatenation_kdf(Vectors, Config). curve25519(Config) -> Vectors = ?config(curve25519, Config), lists:foreach(fun curve25519_vector/1, Vectors). curve448(Config) -> Vectors = ?config(curve448, Config), lists:foreach(fun curve448_vector/1, Vectors). ed25519(Config) -> Vectors = ?config(ed25519, Config), lists:foreach(fun ed25519_vector/1, Vectors). ed25519ph(Config) -> Vectors = ?config(ed25519ph, Config), lists:foreach(fun ed25519ph_vector/1, Vectors). ed448(Config) -> Vectors = ?config(ed448, Config), lists:foreach(fun ed448_vector/1, Vectors). ed448ph(Config) -> Vectors = ?config(ed448ph, Config), lists:foreach(fun ed448ph_vector/1, Vectors). emc_rsa_oaep_encrypt_and_decrypt(Config) -> Vectors = emc_testvector:from_file(?config(oaep_vect_file, Config)), emc_rsa_oaep_encrypt_and_decrypt(Vectors, Config). emc_rsa_pss_sign_and_verify(Config) -> Vectors = emc_testvector:from_file(?config(pss_vect_file, Config)), emc_rsa_pss_sign_and_verify(Vectors, Config). fips_aes_encrypt_and_decrypt(Config) -> Files = ?config(aes_files, Config), lists:foldl(fun fips_aes_encrypt_and_decrypt/2, Config, Files). fips_aes_gcm_encrypt_and_decrypt(Config) -> Files = ?config(aes_gcm_files, Config), lists:foldl(fun fips_aes_gcm_encrypt_and_decrypt/2, Config, Files). fips_aeskw_unwrap(Config) -> Filter = fun(File) -> case filename:basename(File) of "KW_AD_" ++ _ -> true; _ -> false end end, Files = [File || File <- ?config(aeskw_files, Config), Filter(File)], lists:foldl(fun fips_aeskw_unwrap/2, Config, Files). fips_aeskw_wrap(Config) -> Filter = fun(File) -> case filename:basename(File) of "KW_AE_" ++ _ -> true; _ -> false end end, Files = [File || File <- ?config(aeskw_files, Config), Filter(File)], lists:foldl(fun fips_aeskw_wrap/2, Config, Files). fips_rsa_pss_sign(Config) -> Vectors = fips_testvector:from_file(?config(sig_gen_file, Config)), fips_rsa_pss_sign(Vectors, Config). fips_rsa_pss_verify(Config) -> Vectors = fips_testvector:from_file(?config(sig_ver_file, Config)), fips_rsa_pss_verify(Vectors, Config). fips_sha3(Config) -> Files = [File || File <- ?config(sha3_files, Config)], lists:foldl(fun fips_sha3/2, Config, Files). pbkdf1(Config) -> Vectors = ?config(pbkdf1_vectors, Config), pbkdf1(Vectors, Config). pbkdf2(Config) -> Vectors = ?config(pbkdf2_vectors, Config), pbkdf2(Vectors, Config). pkcs7_pad_and_unpad(Config) -> Vectors = ?config(vectors, Config), pkcs7_pad_and_unpad(Vectors, Config). x25519(Config) -> Vectors = ?config(x25519, Config), lists:foreach(fun x25519_vector/1, Vectors). x448(Config) -> Vectors = ?config(x448, Config), lists:foreach(fun x448_vector/1, Vectors). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private archive_file(File, Config) -> filename:join([?config(data_dir, Config), "archive", File]). %% @private concatenation_kdf([{Hash, Z, OtherInfo, KeyDataLen, DerivedKey} | Vectors], Config) -> case jose_jwa_concat_kdf:kdf(Hash, Z, OtherInfo, KeyDataLen) of DerivedKey -> concatenation_kdf(Vectors, Config); Other -> ct:fail({{jose_jwa_concat_kdf, kdf, [Hash, Z, OtherInfo, KeyDataLen]}, {expected, DerivedKey}, {got, Other}}) end; concatenation_kdf([], _Config) -> ok. %% @private curve25519_vector({InputK, InputU, OutputU}) -> ?tv_ok(T0, jose_jwa_x25519, curve25519, [InputK, InputU], OutputU). %% @private curve448_vector({InputK, InputU, OutputU}) -> ?tv_ok(T0, jose_jwa_x448, curve448, [InputK, InputU], OutputU). %% @private data_file(File, Config) -> filename:join([?config(data_dir, Config), File]). %% @private data_setup(Config) -> ArchiveDir = data_file("archive", Config), case filelib:is_dir(ArchiveDir) of true -> ok; false -> ok = file:make_dir(ArchiveDir) end, lists:foldl(fun(F, C) -> io:format(user, "\e[0;36m[FETCH] ~s\e[0m", [F]), {ok, Progress} = jose_ct:progress_start(), NewC = data_setup(F, C), ok = jose_ct:progress_stop(Progress), NewC end, Config, [ "186-3rsatestvectors.zip", "aesmmt.zip", "gcmtestvectors.zip", "KAT_AES.zip", "keccaktestvectors", "kwtestvectors.zip", "pkcs-1v2-1-vec.zip" ]). %% @private data_setup(F = "186-3rsatestvectors.zip", Config) -> Zip = archive_file(F, Config), Dir = data_file("186-3rsatestvectors", Config), URL = "https://github.com/potatosalad/test-vector-archive/raw/1.0.0/archive/186-3rsatestvectors.zip", ok = data_setup(Zip, Dir, URL), Filter = fun (#zip_file{name = "SigGenPSS_186-3.txt"}) -> true; (#zip_file{name = "SigVerPSS_186-3.rsp"}) -> true; (_) -> false end, ok = data_setup(Zip, Dir, "SigGenPSS_186-3.txt", Filter), Config; data_setup(F = "aesmmt.zip", Config) -> Zip = archive_file(F, Config), Dir = data_file("aesmmt", Config), URL = "https://github.com/potatosalad/test-vector-archive/raw/1.0.0/archive/aesmmt.zip", ok = data_setup(Zip, Dir, URL), Filter = fun (#zip_file{name = "CBC" ++ _}) -> true; (#zip_file{name = "ECB" ++ _}) -> true; (_) -> false end, ok = data_setup(Zip, Dir, "CBCMMT128.rsp", Filter), Config; data_setup(F = "gcmtestvectors.zip", Config) -> Zip = archive_file(F, Config), Dir = data_file("gcmtestvectors", Config), URL = "https://github.com/potatosalad/test-vector-archive/raw/1.0.0/archive/gcmtestvectors.zip", ok = data_setup(Zip, Dir, URL), case filelib:is_file(filename:join([Dir, "gcmDecrypt128.rsp"])) of true -> ok; false -> {ok, FileList} = zip:unzip(Zip, [ {cwd, Dir} ]), _ = [begin file:change_mode(File, 8#00644) end || File <- FileList], ok end, Config; data_setup(F = "KAT_AES.zip", Config) -> Zip = archive_file(F, Config), Dir = data_file("KAT_AES", Config), URL = "https://github.com/potatosalad/test-vector-archive/raw/1.0.0/archive/KAT_AES.zip", ok = data_setup(Zip, Dir, URL), Filter = fun (#zip_file{name = "CBC" ++ _}) -> true; (#zip_file{name = "ECB" ++ _}) -> true; (_) -> false end, ok = data_setup(Zip, Dir, "CBCGFSbox128.rsp", Filter), Config; data_setup(F = "keccaktestvectors", Config) -> BaseURL = "https://raw.githubusercontent.com/gvanas/KeccakCodePackage/1893f17c8029d0e6423f1fa4de4d15f76b188a27/TestVectors/", Files = [ "ShortMsgKAT_SHA3-224.txt", "ShortMsgKAT_SHA3-256.txt", "ShortMsgKAT_SHA3-384.txt", "ShortMsgKAT_SHA3-512.txt", "ShortMsgKAT_SHAKE128.txt", "ShortMsgKAT_SHAKE256.txt" ], URLs = [BaseURL ++ File || File <- Files], Directory = data_file(F, Config), DataFiles = [data_file(filename:join(F, File), Config) || File <- Files], ok = data_setup_multiple(DataFiles, Directory, URLs), Config; data_setup(F = "kwtestvectors.zip", Config) -> Zip = archive_file(F, Config), Dir = data_file("kwtestvectors", Config), URL = "https://github.com/potatosalad/test-vector-archive/raw/1.0.0/archive/kwtestvectors.zip", ok = data_setup(Zip, Dir, URL), Filter = fun (#zip_file{name = "KW_" ++ Name}) -> case lists:reverse(Name) of "txt.vni_" ++ _ -> false; _ -> true end; (_) -> false end, ok = data_setup(Zip, Dir, "KW_AD_128.txt", Filter), Config; data_setup(F = "pkcs-1v2-1-vec.zip", Config) -> Zip = archive_file(F, Config), Dir = data_file("pkcs-1v2-1-vec", Config), URL = "https://github.com/potatosalad/test-vector-archive/raw/1.0.0/archive/pkcs-1v2-1-vec.zip", ok = data_setup(Zip, Dir, URL), Filter = fun (#zip_file{name = "oaep-vect.txt"}) -> true; (#zip_file{name = "pss-vect.txt"}) -> true; (_) -> false end, ok = data_setup(Zip, Dir, "oaep-vect.txt", Filter), Config. %% @private data_setup(Zip, Directory, URL) -> case filelib:is_file(Zip) of true -> ok; false -> ok = fetch:fetch(URL, Zip) end, case filelib:is_dir(Directory) of true -> ok; false -> ok = file:make_dir(Directory) end, ok. %% @private data_setup(Zip, Dir, Check, Filter) -> case filelib:is_file(filename:join([Dir, Check])) of true -> ok; false -> Options = case is_function(Filter, 1) of false -> [{cwd, Dir}]; true -> [{cwd, Dir}, {file_filter, Filter}] end, {ok, FileList} = zip:unzip(Zip, Options), _ = [begin file:change_mode(File, 8#00644) end || File <- FileList], ok end. %% @private data_setup_multiple([DataFile | DataFiles], Directory, [URL | URLs]) -> case filelib:is_dir(Directory) of true -> ok; false -> ok = file:make_dir(Directory) end, case filelib:is_file(DataFile) of true -> ok; false -> ok = fetch:fetch(URL, DataFile) end, data_setup_multiple(DataFiles, Directory, URLs); data_setup_multiple([], _Directory, []) -> ok. %% @private ed25519_vector({Secret, PK, Message, Signature}) -> SK = << Secret/binary, PK/binary >>, ?tv_ok(T0, jose_jwa_curve25519, eddsa_secret_to_public, [Secret], PK), ?tv_ok(T1, jose_jwa_curve25519, ed25519_sign, [Message, SK], Signature), ?tv_ok(T2, jose_jwa_curve25519, ed25519_verify, [Signature, Message, PK], true). %% @private ed25519ph_vector({Secret, PK, Message, Signature}) -> SK = << Secret/binary, PK/binary >>, ?tv_ok(T0, jose_jwa_curve25519, eddsa_secret_to_public, [Secret], PK), ?tv_ok(T1, jose_jwa_curve25519, ed25519ph_sign, [Message, SK], Signature), ?tv_ok(T2, jose_jwa_curve25519, ed25519ph_verify, [Signature, Message, PK], true). %% @private ed448_vector({Secret, PK, Message, Signature}) -> SK = << Secret/binary, PK/binary >>, ?tv_ok(T0, jose_jwa_curve448, eddsa_secret_to_public, [Secret], PK), ?tv_ok(T1, jose_jwa_curve448, ed448_sign, [Message, SK], Signature), ?tv_ok(T2, jose_jwa_curve448, ed448_verify, [Signature, Message, PK], true); ed448_vector({Secret, PK, Message, Context, Signature}) -> SK = << Secret/binary, PK/binary >>, ?tv_ok(T0, jose_jwa_curve448, eddsa_secret_to_public, [Secret], PK), ?tv_ok(T1, jose_jwa_curve448, ed448_sign, [Message, SK, Context], Signature), ?tv_ok(T2, jose_jwa_curve448, ed448_verify, [Signature, Message, PK, Context], true). %% @private ed448ph_vector({Secret, PK, Message, Signature}) -> SK = << Secret/binary, PK/binary >>, ?tv_ok(T0, jose_jwa_curve448, eddsa_secret_to_public, [Secret], PK), ?tv_ok(T1, jose_jwa_curve448, ed448ph_sign, [Message, SK], Signature), ?tv_ok(T2, jose_jwa_curve448, ed448ph_verify, [Signature, Message, PK], true); ed448ph_vector({Secret, PK, Message, Context, Signature}) -> SK = << Secret/binary, PK/binary >>, ?tv_ok(T0, jose_jwa_curve448, eddsa_secret_to_public, [Secret], PK), ?tv_ok(T1, jose_jwa_curve448, ed448ph_sign, [Message, SK, Context], Signature), ?tv_ok(T2, jose_jwa_curve448, ed448ph_verify, [Signature, Message, PK, Context], true). %% @private emc_rsa_oaep_encrypt_and_decrypt([ divider, {example, Example}, {component, <<"Components of the RSA Key Pair">>}, {vector, {<<"RSA modulus n">>, N}}, {vector, {<<"RSA public exponent e">>, E}}, {vector, {<<"RSA private exponent d">>, D}}, {vector, {<<"Prime p">>, P}}, {vector, {<<"Prime q">>, Q}}, {vector, {<<"p's CRT exponent dP">>, DP}}, {vector, {<<"q's CRT exponent dQ">>, DQ}}, {vector, {<<"CRT coefficient qInv">>, QI}} | Vectors ], Config) -> RSAPrivateKey = #'RSAPrivateKey'{ version = 'two-prime', otherPrimeInfos = 'asn1_NOVALUE', privateExponent = crypto:bytes_to_integer(D), exponent1 = crypto:bytes_to_integer(DP), exponent2 = crypto:bytes_to_integer(DQ), publicExponent = crypto:bytes_to_integer(E), modulus = crypto:bytes_to_integer(N), prime1 = crypto:bytes_to_integer(P), prime2 = crypto:bytes_to_integer(Q), coefficient = crypto:bytes_to_integer(QI) }, RSAPublicKey = #'RSAPublicKey'{ publicExponent = crypto:bytes_to_integer(E), modulus = crypto:bytes_to_integer(N) }, io:format("~s", [Example]), emc_rsa_oaep_encrypt_and_decrypt(Vectors, {RSAPrivateKey, RSAPublicKey}, Config); emc_rsa_oaep_encrypt_and_decrypt([divider], _Config) -> ok; emc_rsa_oaep_encrypt_and_decrypt([], _Config) -> ok. %% @private emc_rsa_oaep_encrypt_and_decrypt([ {component, Component}, {vector, {<<"Message to be encrypted">>, Message}}, {vector, {<<"Seed">>, Seed}}, {vector, {<<"Encryption">>, Encryption}} | Vectors ], {RSAPrivateKey, RSAPublicKey}, Config) -> io:format("\t~s", [Component]), HashFun = sha, Label = <<>>, case jose_jwa_pkcs1:rsaes_oaep_encrypt(HashFun, Message, Label, Seed, RSAPublicKey) of {ok, Encryption} -> ok; EncryptError -> ct:fail({{jose_jwa_pkcs1, rsaes_oaep_encrypt, [HashFun, Message, Label, Seed, RSAPublicKey]}, {expected, {ok, Encryption}}, {got, EncryptError}}) end, case jose_jwa_pkcs1:rsaes_oaep_decrypt(HashFun, Encryption, Label, RSAPrivateKey) of Message -> emc_rsa_oaep_encrypt_and_decrypt(Vectors, {RSAPrivateKey, RSAPublicKey}, Config); DecryptError -> ct:fail({{jose_jwa_pkcs1, rsaes_oaep_decrypt, [HashFun, Encryption, Label, RSAPrivateKey]}, {expected, Message}, {got, DecryptError}}) end; emc_rsa_oaep_encrypt_and_decrypt(Vectors = [divider | _], _RSAKeyPair, Config) -> emc_rsa_oaep_encrypt_and_decrypt(Vectors, Config). %% @private emc_rsa_pss_sign_and_verify([ divider, {example, Example}, {component, <<"Components of the RSA Key Pair">>}, {vector, {<<"RSA modulus n">>, N}}, {vector, {<<"RSA public exponent e">>, E}}, {vector, {<<"RSA private exponent d">>, D}}, {vector, {<<"Prime p">>, P}}, {vector, {<<"Prime q">>, Q}}, {vector, {<<"p's CRT exponent dP">>, DP}}, {vector, {<<"q's CRT exponent dQ">>, DQ}}, {vector, {<<"CRT coefficient qInv">>, QI}} | Vectors ], Config) -> RSAPrivateKey = #'RSAPrivateKey'{ version = 'two-prime', otherPrimeInfos = 'asn1_NOVALUE', privateExponent = crypto:bytes_to_integer(D), exponent1 = crypto:bytes_to_integer(DP), exponent2 = crypto:bytes_to_integer(DQ), publicExponent = crypto:bytes_to_integer(E), modulus = crypto:bytes_to_integer(N), prime1 = crypto:bytes_to_integer(P), prime2 = crypto:bytes_to_integer(Q), coefficient = crypto:bytes_to_integer(QI) }, RSAPublicKey = #'RSAPublicKey'{ publicExponent = crypto:bytes_to_integer(E), modulus = crypto:bytes_to_integer(N) }, io:format("~s", [Example]), emc_rsa_pss_sign_and_verify(Vectors, {RSAPrivateKey, RSAPublicKey}, Config); emc_rsa_pss_sign_and_verify([divider], _Config) -> ok; emc_rsa_pss_sign_and_verify([], _Config) -> ok. %% @private emc_rsa_pss_sign_and_verify([ {component, Component}, {vector, {<<"Message to be signed">>, Message}}, {vector, {<<"Salt">>, Salt}}, {vector, {<<"Signature">>, Signature}} | Vectors ], {RSAPrivateKey, RSAPublicKey}, Config) -> io:format("\t~s", [Component]), HashFun = sha, case jose_jwa_pkcs1:rsassa_pss_sign(HashFun, Message, Salt, RSAPrivateKey) of {ok, Signature} -> ok; Other -> ct:fail({{jose_jwa_pkcs1, rsassa_pss_sign, [HashFun, Message, Salt, RSAPrivateKey]}, {expected, {ok, Signature}}, {got, Other}}) end, SaltLen = byte_size(Salt), case jose_jwa_pkcs1:rsassa_pss_verify(HashFun, Message, Signature, SaltLen, RSAPublicKey) of true -> emc_rsa_pss_sign_and_verify(Vectors, {RSAPrivateKey, RSAPublicKey}, Config); false -> ct:fail({{jose_jwa_pkcs1, rsassa_pss_verify, [HashFun, Message, Signature, SaltLen, RSAPublicKey]}, {expected, true}, {got, false}}) end; emc_rsa_pss_sign_and_verify(Vectors = [divider | _], _RSAKeyPair, Config) -> emc_rsa_pss_sign_and_verify(Vectors, Config). %% @private fips_aes_encrypt_and_decrypt(File, Config) -> VectorsName = iolist_to_binary(filename:basename(File)), Algorithm = case VectorsName of << "CBC", _/binary >> -> aes_cbc; << "ECB", _/binary >> -> aes_ecb end, {Pos, 3} = binary:match(VectorsName, [<<"128">>, <<"192">>, <<"256">>]), Bits = binary_to_integer(binary:part(VectorsName, Pos, 3)), Cipher = {Algorithm, Bits}, Vectors = fips_testvector:from_file(File), io:format("~s", [VectorsName]), fips_aes_encrypt_and_decrypt(Vectors, Cipher, Config). %% @private fips_aes_encrypt_and_decrypt([ {vector, {<<"COUNT">>, Count}, _}, {vector, {<<"KEY">>, Key}, _}, {vector, {<<"PLAINTEXT">>, PlainText}, _}, {vector, {<<"CIPHERTEXT">>, CipherText}, _} | Vectors ], Cipher, Config) -> io:format("\tENCRYPT = ~w", [Count]), case jose_jwa_aes:block_encrypt(Cipher, Key, PlainText) of CipherText -> fips_aes_encrypt_and_decrypt(Vectors, Cipher, Config); EncryptError -> ct:fail({{jose_jwa_aes, block_encrypt, [Cipher, Key, PlainText]}, {expected, CipherText}, {got, EncryptError}}) end; fips_aes_encrypt_and_decrypt([ {vector, {<<"COUNT">>, Count}, _}, {vector, {<<"KEY">>, Key}, _}, {vector, {<<"CIPHERTEXT">>, CipherText}, _}, {vector, {<<"PLAINTEXT">>, PlainText}, _} | Vectors ], Cipher, Config) -> io:format("\tDECRYPT = ~w", [Count]), case jose_jwa_aes:block_decrypt(Cipher, Key, CipherText) of PlainText -> fips_aes_encrypt_and_decrypt(Vectors, Cipher, Config); DecryptError -> ct:fail({{jose_jwa_aes, block_decrypt, [Cipher, Key, CipherText]}, {expected, PlainText}, {got, DecryptError}}) end; fips_aes_encrypt_and_decrypt([ {vector, {<<"COUNT">>, Count}, _}, {vector, {<<"KEY">>, Key}, _}, {vector, {<<"IV">>, IV}, _}, {vector, {<<"PLAINTEXT">>, PlainText}, _}, {vector, {<<"CIPHERTEXT">>, CipherText}, _} | Vectors ], Cipher, Config) -> io:format("\tENCRYPT = ~w", [Count]), case jose_jwa_aes:block_encrypt(Cipher, Key, IV, PlainText) of CipherText -> fips_aes_encrypt_and_decrypt(Vectors, Cipher, Config); EncryptError -> ct:fail({{jose_jwa_aes, block_encrypt, [Cipher, Key, IV, PlainText]}, {expected, CipherText}, {got, EncryptError}}) end; fips_aes_encrypt_and_decrypt([ {vector, {<<"COUNT">>, Count}, _}, {vector, {<<"KEY">>, Key}, _}, {vector, {<<"IV">>, IV}, _}, {vector, {<<"CIPHERTEXT">>, CipherText}, _}, {vector, {<<"PLAINTEXT">>, PlainText}, _} | Vectors ], Cipher, Config) -> io:format("\tDECRYPT = ~w", [Count]), case jose_jwa_aes:block_decrypt(Cipher, Key, IV, CipherText) of PlainText -> fips_aes_encrypt_and_decrypt(Vectors, Cipher, Config); DecryptError -> ct:fail({{jose_jwa_aes, block_decrypt, [Cipher, Key, IV, CipherText]}, {expected, PlainText}, {got, DecryptError}}) end; fips_aes_encrypt_and_decrypt([ {flag, Flag} | Vectors ], Cipher, Config) when Flag =:= <<"DECRYPT">> orelse Flag =:= <<"ENCRYPT">> -> fips_aes_encrypt_and_decrypt(Vectors, Cipher, Config); fips_aes_encrypt_and_decrypt([], _Cipher, Config) -> Config. %% @private fips_aes_gcm_encrypt_and_decrypt(File, Config) -> VectorsName = iolist_to_binary(filename:basename(File)), {Algorithm, Mode} = case VectorsName of << "gcmDecrypt", _/binary >> -> {aes_gcm, decrypt}; << "gcmEncrypt", _/binary >> -> {aes_gcm, encrypt} end, {Pos, 3} = binary:match(VectorsName, [<<"128">>, <<"192">>, <<"256">>]), Bits = binary_to_integer(binary:part(VectorsName, Pos, 3)), Cipher = {Algorithm, Bits}, Vectors = fips_testvector:from_file(File), io:format("~s", [VectorsName]), fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, Mode, undefined}, Config). %% @private fips_aes_gcm_encrypt_and_decrypt([ {vector, {<<"Count">>, Count}, _}, {vector, {<<"Key">>, Key}, _}, {vector, {<<"IV">>, IV}, _}, {vector, {<<"CT">>, CT}, _}, {vector, {<<"AAD">>, AAD}, _}, {vector, {<<"Tag">>, Tag}, _}, {token, <<"FAIL">>} | Vectors ], {Cipher, decrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, Counts}}, Config) when bit_size(Key) =:= Keylen andalso bit_size(IV) =:= IVlen andalso bit_size(CT) =:= PTlen andalso bit_size(AAD) =:= AADlen andalso bit_size(Tag) =:= Taglen -> case rand:uniform(?config(one_in, Config)) of 1 -> case jose_jwa_aes:block_decrypt(Cipher, Key, IV, {AAD, CT, Tag}) of error -> fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, decrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, << Counts/binary, (integer_to_binary(Count))/binary, "..." >>}}, Config); OtherDecrypt -> io:format("\t\tCounts = ~s", [<< Counts/binary, (integer_to_binary(Count))/binary, "..." >>]), ct:fail({{jose_jwa_aes, block_decrypt, [Cipher, Key, IV, {AAD, CT, Tag}]}, {expected, error}, {got, OtherDecrypt}}) end; _ -> fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, decrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, << Counts/binary, (integer_to_binary(Count))/binary, "..." >>}}, Config) end; fips_aes_gcm_encrypt_and_decrypt([ {vector, {<<"Count">>, Count}, _}, {vector, {<<"Key">>, Key}, _}, {vector, {<<"IV">>, IV}, _}, {vector, {<<"CT">>, CT}, _}, {vector, {<<"AAD">>, AAD}, _}, {vector, {<<"Tag">>, Tag}, _}, {vector, {<<"PT">>, PT}, _} | Vectors ], {Cipher, decrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, Counts}}, Config) when bit_size(Key) =:= Keylen andalso bit_size(IV) =:= IVlen andalso bit_size(CT) =:= PTlen andalso bit_size(AAD) =:= AADlen andalso bit_size(Tag) =:= Taglen andalso bit_size(PT) =:= PTlen -> case rand:uniform(?config(one_in, Config)) of 1 -> case jose_jwa_aes:block_decrypt(Cipher, Key, IV, {AAD, CT, Tag}) of PT -> fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, decrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, << Counts/binary, (integer_to_binary(Count))/binary, "..." >>}}, Config); OtherDecrypt -> io:format("\t\tCounts = ~s", [<< Counts/binary, (integer_to_binary(Count))/binary, "..." >>]), io:format("{Cipher, Key, IV, CT, AAD, Tag, PT} = ~w~n", [{Cipher, Key, IV, CT, AAD, Tag, PT}]), ct:fail({{jose_jwa_aes, block_decrypt, [Cipher, Key, IV, {AAD, CT, Tag}]}, {expected, PT}, {got, OtherDecrypt}}) end; _ -> fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, decrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, << Counts/binary, (integer_to_binary(Count))/binary, "..." >>}}, Config) end; fips_aes_gcm_encrypt_and_decrypt([ {vector, {<<"Count">>, Count}, _}, {vector, {<<"Key">>, Key}, _}, {vector, {<<"IV">>, IV}, _}, {vector, {<<"PT">>, PT}, _}, {vector, {<<"AAD">>, AAD}, _}, {vector, {<<"CT">>, CT}, _}, {vector, {<<"Tag">>, Tag}, _} | Vectors ], {Cipher, encrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, Counts}}, Config) when bit_size(Key) =:= Keylen andalso bit_size(IV) =:= IVlen andalso bit_size(PT) =:= PTlen andalso bit_size(AAD) =:= AADlen andalso bit_size(CT) =:= PTlen andalso bit_size(Tag) =:= Taglen -> case rand:uniform(?config(one_in, Config)) of 1 -> case jose_jwa_aes:block_encrypt(Cipher, Key, IV, {AAD, PT}) of {CT, << Tag:Taglen/bitstring, _/bitstring >>} -> fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, encrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, << Counts/binary, (integer_to_binary(Count))/binary, "..." >>}}, Config); OtherEncrypt -> io:format("\t\tCounts = ~s", [<< Counts/binary, (integer_to_binary(Count))/binary, "..." >>]), ct:fail({{jose_jwa_aes, block_encrypt, [Cipher, Key, IV, {AAD, PT}]}, {expected, {CT, Tag}}, {got, OtherEncrypt}}) end; _ -> fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, encrypt, {Keylen, IVlen, PTlen, AADlen, Taglen, << Counts/binary, (integer_to_binary(Count))/binary, "..." >>}}, Config) end; fips_aes_gcm_encrypt_and_decrypt([ {option, {<<"Keylen">>, Keylen}}, {option, {<<"IVlen">>, IVlen}}, {option, {<<"PTlen">>, PTlen}}, {option, {<<"AADlen">>, AADlen}}, {option, {<<"Taglen">>, Taglen}} | Vectors ], {Cipher, Mode, undefined}, Config) -> Options = { binary_to_integer(Keylen), binary_to_integer(IVlen), binary_to_integer(PTlen), binary_to_integer(AADlen), binary_to_integer(Taglen), <<>> }, fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, Mode, Options}, Config); fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, Mode, {_Keylen, _IVlen, _PTlen, _AADlen, _Taglen, _Counts}}, Config) -> fips_aes_gcm_encrypt_and_decrypt(Vectors, {Cipher, Mode, undefined}, Config); fips_aes_gcm_encrypt_and_decrypt([], _Cipher, Config) -> Config. %% @private fips_aeskw_unwrap(File, Config) -> << "KW_AD_", BitsBin:3/binary, _/binary >> = iolist_to_binary(filename:basename(File)), Bits = binary_to_integer(BitsBin), Vectors = fips_testvector:from_file(File), io:format("~s", [filename:basename(File)]), fips_aeskw_unwrap(Vectors, {Bits, undefined}, Config). %% @private fips_aeskw_unwrap([ {vector, {<<"COUNT">>, Count}, _}, {vector, {<<"K">>, K}, _}, {vector, {<<"C">>, C}, _}, {vector, {<<"P">>, P}, _} | Vectors ], {Bits, Len}, Config) when is_integer(Len) andalso bit_size(K) =:= Bits andalso bit_size(P) =:= Len -> case rand:uniform(?config(one_in, Config)) of 1 -> case jose_jwa_aes_kw:unwrap(C, K) of P -> fips_aeskw_unwrap(Vectors, {Bits, Len}, Config); Other -> io:format("\t\tCOUNT = ~w", [Count]), ct:fail({{jose_jwa_aes_kw, unwrap, [C, K]}, {expected, P}, {got, Other}}) end; _ -> fips_aeskw_unwrap(Vectors, {Bits, Len}, Config) end; fips_aeskw_unwrap([ {vector, {<<"COUNT">>, Count}, _}, {vector, {<<"K">>, K}, _}, {vector, {<<"C">>, C}, _}, {token, <<"FAIL">>} | Vectors ], {Bits, Len}, Config) when is_integer(Len) andalso bit_size(K) =:= Bits -> case rand:uniform(?config(one_in, Config)) of 1 -> try jose_jwa_aes_kw:unwrap(C, K) of Other -> io:format("\t\tCOUNT = ~w", [Count]), ct:fail({{jose_jwa_aes_kw, unwrap, [C, K]}, {expected, badarg}, {got, Other}}) catch _:_ -> fips_aeskw_unwrap(Vectors, {Bits, Len}, Config) end; _ -> fips_aeskw_unwrap(Vectors, {Bits, Len}, Config) end; fips_aeskw_unwrap([{option, {<<"PLAINTEXTLENGTH">>, LenBin}} | Vectors], {Bits, _}, Config) -> Len = binary_to_integer(LenBin), io:format("\tPLAINTEXTLENGTH = ~w", [Len]), fips_aeskw_unwrap(Vectors, {Bits, Len}, Config); fips_aeskw_unwrap([], _, Config) -> Config. %% @private fips_aeskw_wrap(File, Config) -> << "KW_AE_", BitsBin:3/binary, _/binary >> = iolist_to_binary(filename:basename(File)), Bits = binary_to_integer(BitsBin), Vectors = fips_testvector:from_file(File), io:format("~s", [filename:basename(File)]), fips_aeskw_wrap(Vectors, {Bits, undefined}, Config). %% @private fips_aeskw_wrap([ {vector, {<<"COUNT">>, Count}, _}, {vector, {<<"K">>, K}, _}, {vector, {<<"P">>, P}, _}, {vector, {<<"C">>, C}, _} | Vectors ], {Bits, Len}, Config) when is_integer(Len) andalso bit_size(K) =:= Bits andalso bit_size(P) =:= Len -> case rand:uniform(?config(one_in, Config)) of 1 -> case jose_jwa_aes_kw:wrap(P, K) of C -> fips_aeskw_wrap(Vectors, {Bits, Len}, Config); Other -> io:format("\t\tCOUNT = ~w", [Count]), ct:fail({{jose_jwa_aes_kw, wrap, [P, K]}, {expected, C}, {got, Other}}) end; _ -> fips_aeskw_wrap(Vectors, {Bits, Len}, Config) end; fips_aeskw_wrap([{option, {<<"PLAINTEXTLENGTH">>, LenBin}} | Vectors], {Bits, _}, Config) -> Len = binary_to_integer(LenBin), io:format("\tPLAINTEXTLENGTH = ~w", [Len]), fips_aeskw_wrap(Vectors, {Bits, Len}, Config); fips_aeskw_wrap([], _, Config) -> Config. %% @private fips_rsa_pss_sign([ {option, {<<"mod">>, ModVal}}, {vector, {<<"n">>, N}, _}, {vector, {<<"e">>, E}, _}, {vector, {<<"d">>, D}, _} | Vectors ], Config) -> ModulusSize = binary_to_integer(ModVal), RSAPrivateKey = #'RSAPrivateKey'{ modulus = crypto:bytes_to_integer(N), privateExponent = crypto:bytes_to_integer(D), publicExponent = crypto:bytes_to_integer(E) }, fips_rsa_pss_sign(Vectors, ModulusSize, RSAPrivateKey, Config); fips_rsa_pss_sign([], _Config) -> ok. %% @private fips_rsa_pss_sign([ {vector, {<<"SHAAlg">>, SHAAlg}, _}, {vector, {<<"Msg">>, Msg}, _}, {vector, {<<"S">>, S}, _}, {vector, {<<"SaltVal">>, SaltVal}, _} | Vectors ], ModulusSize, RSAPrivateKey, Config) -> HashFun = shaalg_to_hash_fun(SHAAlg), case jose_jwa_pkcs1:rsassa_pss_sign(HashFun, Msg, SaltVal, RSAPrivateKey) of {ok, S} -> ok; Other -> ct:fail({{jose_jwa_pkcs1, rsassa_pss_sign, [HashFun, Msg, SaltVal, RSAPrivateKey]}, {expected, {ok, S}}, {got, Other}}) end, RSAPublicKey = rsa_private_to_public(RSAPrivateKey), SaltLen = byte_size(SaltVal), case jose_jwa_pkcs1:rsassa_pss_verify(HashFun, Msg, S, SaltLen, RSAPublicKey) of true -> fips_rsa_pss_sign(Vectors, ModulusSize, RSAPrivateKey, Config); false -> ct:fail({{jose_jwa_pkcs1, rsassa_pss_verify, [HashFun, Msg, S, SaltLen, RSAPublicKey]}, {expected, true}, {got, false}}) end; fips_rsa_pss_sign(Vectors, _ModulusSize, _RSAPrivateKey, Config) -> fips_rsa_pss_sign(Vectors, Config). %% @private fips_rsa_pss_verify([ {option, {<<"mod">>, ModVal}}, {vector, {<<"n">>, N}, _}, {vector, {<<"p">>, P}, _}, {vector, {<<"q">>, Q}, _} | Vectors ], Config) -> ModulusSize = binary_to_integer(ModVal), RSAPrivateKey = #'RSAPrivateKey'{ modulus = crypto:bytes_to_integer(N), prime1 = crypto:bytes_to_integer(P), prime2 = crypto:bytes_to_integer(Q) }, fips_rsa_pss_verify(Vectors, ModulusSize, RSAPrivateKey, Config); fips_rsa_pss_verify([], _Config) -> ok. %% @private fips_rsa_pss_verify([ {vector, {<<"n">>, N}, _}, {vector, {<<"p">>, P}, _}, {vector, {<<"q">>, Q}, _} | Vectors ], ModulusSize, Config) -> RSAPrivateKey = #'RSAPrivateKey'{ modulus = crypto:bytes_to_integer(N), prime1 = crypto:bytes_to_integer(P), prime2 = crypto:bytes_to_integer(Q) }, fips_rsa_pss_verify(Vectors, ModulusSize, RSAPrivateKey, Config); fips_rsa_pss_verify(Vectors, _ModulusSize, Config) -> fips_rsa_pss_verify(Vectors, Config). %% @private fips_rsa_pss_verify([ {vector, {<<"SHAAlg">>, SHAAlg}, _}, {vector, {<<"e">>, E}, _}, {vector, {<<"d">>, D}, _}, {vector, {<<"Msg">>, Msg}, _}, {vector, {<<"S">>, S}, _}, {vector, {<<"SaltVal">>, SaltVal}, _}, {vector, {<<"EM", _/binary>>, _}, _}, {vector, {<<"Result">>, << R, _/binary >>}, _} | Vectors ], ModulusSize, RSAPrivateKey0, Config) -> Expected = case R of $F -> false; $P -> true end, HashFun = shaalg_to_hash_fun(SHAAlg), RSAPrivateKey = RSAPrivateKey0#'RSAPrivateKey'{ privateExponent = crypto:bytes_to_integer(D), publicExponent = crypto:bytes_to_integer(E) }, RSAPublicKey = rsa_private_to_public(RSAPrivateKey), SaltLen = case SaltVal of << 0 >> -> 0; _ -> byte_size(SaltVal) end, case jose_jwa_pkcs1:rsassa_pss_verify(HashFun, Msg, S, SaltLen, RSAPublicKey) of Expected -> fips_rsa_pss_verify(Vectors, ModulusSize, RSAPrivateKey0, Config); Other -> ct:fail({{jose_jwa_pkcs1, rsassa_pss_verify, [HashFun, Msg, S, SaltLen, RSAPublicKey]}, {expected, Expected}, {got, Other}}) end; fips_rsa_pss_verify([ {vector, {<<"SHAAlg">>, SHAAlg}, _}, {vector, {<<"e">>, E}, _}, {vector, {<<"d">>, D}, _}, {vector, {<<"Msg">>, Msg}, _}, {vector, {<<"S">>, S}, _}, {vector, {<<"SaltVal">>, SaltVal}, _}, {vector, {<<"Result">>, << R, _/binary >>}, _} | Vectors ], ModulusSize, RSAPrivateKey0, Config) -> Expected = case R of $F -> false; $P -> true end, HashFun = shaalg_to_hash_fun(SHAAlg), RSAPrivateKey = RSAPrivateKey0#'RSAPrivateKey'{ privateExponent = crypto:bytes_to_integer(D), publicExponent = crypto:bytes_to_integer(E) }, RSAPublicKey = rsa_private_to_public(RSAPrivateKey), SaltLen = case SaltVal of << 0 >> -> 0; _ -> byte_size(SaltVal) end, case jose_jwa_pkcs1:rsassa_pss_verify(HashFun, Msg, S, SaltLen, RSAPublicKey) of Expected -> fips_rsa_pss_verify(Vectors, ModulusSize, RSAPrivateKey0, Config); Other -> ct:fail({{jose_jwa_pkcs1, rsassa_pss_verify, [HashFun, Msg, S, SaltLen, RSAPublicKey]}, {expected, Expected}, {got, Other}}) end; fips_rsa_pss_verify(Vectors, ModulusSize, _RSAPrivateKey, Config) -> fips_rsa_pss_verify(Vectors, ModulusSize, Config). %% @private fips_sha3(File, Config) -> Options = case iolist_to_binary(filename:basename(File)) of << "ShortMsgKAT_SHA3-", BitsBin:3/binary, _/binary >> -> Bits = binary_to_integer(BitsBin), Bytes = (Bits + 7) div 8, Function = list_to_atom("sha3_" ++ integer_to_list(Bits)), Arity = 1, {Function, Arity, Bytes}; << "ShortMsgKAT_SHAKE", BitsBin:3/binary, _/binary >> -> Bits = binary_to_integer(BitsBin), Bytes = 512, Function = list_to_atom("shake" ++ integer_to_list(Bits)), Arity = 2, {Function, Arity, Bytes} end, Vectors = fips_testvector:from_file(File), io:format("~s", [filename:basename(File)]), fips_sha3(Vectors, Options, Config). %% @private fips_sha3([ {vector, {<<"Len">>, Len}, _}, {vector, {<<"Msg">>, Msg}, _}, {vector, {<<"MD">>, MD}, _} | Vectors ], {Function, Arity=1, OutputByteLen}, Config) when Len rem 8 =:= 0 -> InputBytes = binary:part(Msg, 0, Len div 8), case jose_jwa_sha3:Function(InputBytes) of MD -> fips_sha3(Vectors, {Function, Arity, OutputByteLen}, Config); Other -> ct:fail({{jose_jwa_sha3, Function, [InputBytes]}, {expected, MD}, {got, Other}}) end; fips_sha3([ {vector, {<<"Len">>, Len}, _}, {vector, {<<"Msg">>, Msg}, _}, {vector, {<<"Squeezed">>, Squeezed}, _} | Vectors ], {Function, Arity=2, OutputByteLen}, Config) when Len rem 8 =:= 0 -> InputBytes = binary:part(Msg, 0, Len div 8), case jose_jwa_sha3:Function(InputBytes, OutputByteLen) of Squeezed -> fips_sha3(Vectors, {Function, Arity, OutputByteLen}, Config); Other -> ct:fail({{jose_jwa_sha3, Function, [InputBytes, OutputByteLen]}, {expected, Squeezed}, {got, Other}}) end; fips_sha3([ {vector, {<<"Len">>, _Len}, _}, {vector, {<<"Msg">>, _Msg}, _}, {vector, {<<"MD">>, _MD}, _} | Vectors ], Options, Config) -> fips_sha3(Vectors, Options, Config); fips_sha3([ {vector, {<<"Len">>, _Len}, _}, {vector, {<<"Msg">>, _Msg}, _}, {vector, {<<"Squeezed">>, _Squeezed}, _} | Vectors ], Options, Config) -> fips_sha3(Vectors, Options, Config); fips_sha3([], _Opts, _Config) -> ok. %% @private hexstr2bin(S) -> list_to_binary(hexstr2list(S)). %% @private hexstr2lint(S) -> Bin = hexstr2bin(S), Size = byte_size(Bin), << Int:Size/unsigned-little-integer-unit:8 >> = Bin, Int. %% @private hexstr2list([X,Y|T]) -> [mkint(X)*16 + mkint(Y) | hexstr2list(T)]; hexstr2list([]) -> []. %% @private mkint(C) when $0 =< C, C =< $9 -> C - $0; mkint(C) when $A =< C, C =< $F -> C - $A + 10; mkint(C) when $a =< C, C =< $f -> C - $a + 10. %% @private pbkdf1([{Hash, Password, Salt, Iterations, DerivedKeyLen, DerivedKey} | Vectors], Config) -> case jose_jwa_pkcs5:pbkdf1(Hash, Password, Salt, Iterations, DerivedKeyLen) of {ok, DerivedKey} -> pbkdf1(Vectors, Config); Other -> ct:fail({{jose_jwa_pkcs5, pbkdf1, [Hash, Password, Salt, Iterations, DerivedKeyLen]}, {expected, {ok, DerivedKey}}, {got, Other}}) end; pbkdf1([], _Config) -> ok. %% @private pbkdf2([{Mac, Password, Salt, Iterations, DerivedKeyLen, DerivedKey} | Vectors], Config) -> case jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt, Iterations, DerivedKeyLen) of {ok, DerivedKey} -> pbkdf2(Vectors, Config); Other -> ct:fail({{jose_jwa_pkcs5, pbkdf2, [Mac, Password, Salt, Iterations, DerivedKeyLen]}, {expected, {ok, DerivedKey}}, {got, Other}}) end; pbkdf2([], _Config) -> ok. %% @private pkcs7_pad_and_unpad([{Unpadded, Padded} | Vectors], Config) -> case jose_jwa_pkcs7:pad(Unpadded) of Padded -> ok; PadOther -> ct:fail({{jose_jwa_pkcs7, pad, [Unpadded]}, {expected, Padded}, {got, PadOther}}) end, case jose_jwa_pkcs7:unpad(Padded) of Unpadded -> pkcs7_pad_and_unpad(Vectors, Config); UnpadOther -> ct:fail({{jose_jwa_pkcs7, unpad, [Padded]}, {expected, Unpadded}, {got, UnpadOther}}) end; pkcs7_pad_and_unpad([], _Config) -> ok. %% @private rsa_private_to_public(#'RSAPrivateKey'{ modulus = Modulus, publicExponent = PublicExponent }) -> #'RSAPublicKey'{ modulus = Modulus, publicExponent = PublicExponent }. %% @private shaalg_to_hash_fun(<<"SHA1">>) -> sha; shaalg_to_hash_fun(<<"SHA224">>) -> sha224; shaalg_to_hash_fun(<<"SHA256">>) -> sha256; shaalg_to_hash_fun(<<"SHA384">>) -> sha384; shaalg_to_hash_fun(<<"SHA512">>) -> sha512. %% @private x25519_vector({AliceSK, AlicePK, BobSK, BobPK, Shared}) -> ?tv_ok(T0, jose_jwa_curve25519, x25519_secret_to_public, [AliceSK], AlicePK), ?tv_ok(T1, jose_jwa_curve25519, x25519_secret_to_public, [BobSK], BobPK), ?tv_ok(T2, jose_jwa_curve25519, x25519_shared_secret, [AliceSK, BobPK], Shared), ?tv_ok(T3, jose_jwa_curve25519, x25519_shared_secret, [BobSK, AlicePK], Shared). %% @private x448_vector({AliceSK, AlicePK, BobSK, BobPK, Shared}) -> ?tv_ok(T0, jose_jwa_curve448, x448_secret_to_public, [AliceSK], AlicePK), ?tv_ok(T1, jose_jwa_curve448, x448_secret_to_public, [BobSK], BobPK), ?tv_ok(T2, jose_jwa_curve448, x448_shared_secret, [AliceSK, BobPK], Shared), ?tv_ok(T3, jose_jwa_curve448, x448_shared_secret, [BobSK, AlicePK], Shared). erlang-jose-1.10.1/test/jose_jws_SUITE.erl0000644000232200023220000001063413605433351020634 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jws_SUITE). -include_lib("common_test/include/ct.hrl"). -include("jose.hrl"). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([alg_ecdsa_from_map_and_to_map/1]). -export([alg_ecdsa_sign_and_verify/1]). -export([alg_eddsa_from_map_and_to_map/1]). -export([alg_eddsa_sign_and_verify/1]). -export([alg_hmac_from_map_and_to_map/1]). -export([alg_hmac_sign_and_verify/1]). -export([alg_none_from_map_and_to_map/1]). -export([alg_none_sign_and_verify/1]). -export([alg_poly1305_from_map_and_to_map/1]). -export([alg_poly1305_sign_and_verify/1]). -export([alg_rsa_pkcs1_v1_5_from_map_and_to_map/1]). -export([alg_rsa_pkcs1_v1_5_sign_and_verify/1]). -export([alg_rsa_pss_from_map_and_to_map/1]). -export([alg_rsa_pss_sign_and_verify/1]). all() -> [ {group, jose_jws_alg_ecdsa}, {group, jose_jws_alg_eddsa}, {group, jose_jws_alg_hmac}, {group, jose_jws_alg_none}, {group, jose_jws_alg_poly1305}, {group, jose_jws_alg_rsa_pkcs1_v1_5}, {group, jose_jws_alg_rsa_pss} ]. groups() -> [ {jose_jws_alg_ecdsa, [parallel], [ alg_ecdsa_from_map_and_to_map, alg_ecdsa_sign_and_verify ]}, {jose_jws_alg_eddsa, [parallel], [ alg_eddsa_from_map_and_to_map, alg_eddsa_sign_and_verify ]}, {jose_jws_alg_hmac, [parallel], [ alg_hmac_from_map_and_to_map, alg_hmac_sign_and_verify ]}, {jose_jws_alg_none, [parallel], [ alg_none_from_map_and_to_map, alg_none_sign_and_verify ]}, {jose_jws_alg_poly1305, [parallel], [ alg_poly1305_from_map_and_to_map, alg_poly1305_sign_and_verify ]}, {jose_jws_alg_rsa_pkcs1_v1_5, [parallel], [ alg_rsa_pkcs1_v1_5_from_map_and_to_map, alg_rsa_pkcs1_v1_5_sign_and_verify ]}, {jose_jws_alg_rsa_pss, [parallel], [ alg_rsa_pss_from_map_and_to_map, alg_rsa_pss_sign_and_verify ]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), ct_property_test:init_per_suite(Config). end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(Group, Config) -> jose_ct:start(Group, Config). end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== alg_ecdsa_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jws_alg_ecdsa_props:prop_from_map_and_to_map(), Config). alg_ecdsa_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jws_alg_ecdsa_props:prop_sign_and_verify(), Config). alg_eddsa_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jws_alg_eddsa_props:prop_from_map_and_to_map(), Config). alg_eddsa_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jws_alg_eddsa_props:prop_sign_and_verify(), Config). alg_hmac_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jws_alg_hmac_props:prop_from_map_and_to_map(), Config). alg_hmac_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jws_alg_hmac_props:prop_sign_and_verify(), Config). alg_none_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jws_alg_none_props:prop_from_map_and_to_map(), Config). alg_none_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jws_alg_none_props:prop_sign_and_verify(), Config). alg_poly1305_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jws_alg_poly1305_props:prop_from_map_and_to_map(), Config). alg_poly1305_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jws_alg_poly1305_props:prop_sign_and_verify(), Config). alg_rsa_pkcs1_v1_5_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jws_alg_rsa_pkcs1_v1_5_props:prop_from_map_and_to_map(), Config). alg_rsa_pkcs1_v1_5_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jws_alg_rsa_pkcs1_v1_5_props:prop_sign_and_verify(), Config). alg_rsa_pss_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jws_alg_rsa_pss_props:prop_from_map_and_to_map(), Config). alg_rsa_pss_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jws_alg_rsa_pss_props:prop_sign_and_verify(), Config). erlang-jose-1.10.1/test/jose_SUITE_data/0000755000232200023220000000000013605433351020232 5ustar debalancedebalanceerlang-jose-1.10.1/test/jose_SUITE_data/rsa-multi.pem0000644000232200023220000000201013605433351022643 0ustar debalancedebalance-----BEGIN RSA PRIVATE KEY----- MIICyAIBAQKBgGs61DcjCl4A/KJcIGy4H06ZyaVd8i+HQoyLhNbF1mSt/GbbfhIg COqIHSbG2wcTi7en5HChpfuieP5oTxIWPbATGo0p22i2HfwiQ3vCs5lI5bUEa38B LHPY6NBphDST74ODwhUGzcyCeFq5vA2Kc7sOSLC1YqV9R7/12kesLp+FAgMBAAEC gYApeDdxWW5de5E4s1tg4HZNdhU1Yga1pOsAchJKPHeBPrL0G+jm/36r7gMRlROD eCS3HQ/id8JM9vvdJTDkruLFpjuRJJ4J+7ecu6oc23Zz6+PxS6CJrJr5iTo6TcM+ ktmx2Wm4BBPZYwe8yzoSCZhXuU75C063r+rLuFSXYypAAQIRAN7iFqWrvIa2Q5UU 9G1fakMCEQCnWJQqst2Lio5LKmrtDqAZAhBdcGVUMSpJQ5ITpwRN8glnAhEAg28l yDd9m8hyJAUnwBJ5mQIRAM55rA6yEXm/OkZJF+Gkp6swggFYMDcCEQCuPzHHhBfb DkKUVhrvvbrNAhBTcpxKaq5qECg+lgYMbpa5AhB4DZVFlG43I1/F6PPFae1nMDcC EQDsULiKdbFMJoxzA3aVVPqFAhAwAg4bguFr+QDbdL6og8UJAhAPZR25SnZcZOSm +WpCFO+PMDcCEQCHLlPV6I+V5kR5Jlxv6t0fAhAOdhtL3/Q0YgzjNQJgiqybAhBt 1NnjprH6FBuaD5gL50tyMDgCEQCif1kbMPnVWDd4JiCmsgVRAhEAn8cIHqxxe01a fVFAGahBgQIQCHW4I73pxUofd9g9POX8ZTA3AhEAw/kGDS4Dehb7iWmsDHGA4wIQ Z3Bp4UsISskWu9ErHuZKQQIQZl+jNgR8jNK/BJekl0PsTDA4AhEEkKjcHEsf4l5r Ekr8WpFfKwIRBB/aoDtj2GPCIIS/gO4mx08CEFpfy3k0MT3bSESfKYaWzD4= -----END RSA PRIVATE KEY-----erlang-jose-1.10.1/test/jose_SUITE_data/jose_ecdh_1pu/0000755000232200023220000000000013605433351022742 5ustar debalancedebalanceerlang-jose-1.10.1/test/jose_SUITE_data/jose_ecdh_1pu/a.config0000644000232200023220000000247013605433351024354 0ustar debalancedebalance{"a.ussk.jwk+json", <<"{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"WKn-ZIGevcwGIyyrzFoZNBdaq9_TsqzGl96oc0CWuis\",\"y\":\"y77t-RvAHRKTsSGdIYUfweuOvwrvDD-Q3Hv5J0fSKbE\",\"d\":\"Hndv7ZZjs_ke8o9zXYo3iq-Yr8SewI5vrqd0pAvEPqg\"}">>}. {"a.vssk.jwk+json", <<"{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ\",\"y\":\"e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck\",\"d\":\"VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw\"}">>}. {"a.uesk.jwk+json", <<"{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0\",\"y\":\"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps\",\"d\":\"0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo\"}">>}. {"a.jwe+json", <<"{\"alg\":\"ECDH-1PU\",\"enc\":\"A256GCM\",\"apu\":\"QWxpY2U\",\"apv\":\"Qm9i\",\"epk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0\",\"y\":\"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps\"}}">>}. {"a.ze+hex", <<"9e56d91d817135d372834283bf84269cfb316ea3da806a48f6daa7798cfe90c4">>}. {"a.zs+hex", <<"e3ca3474384c9f62b30bfd4c688b3e7d4110a1b4badc3cc54ef7b81241efd50d">>}. {"a.z+hex", <<"9e56d91d817135d372834283bf84269cfb316ea3da806a48f6daa7798cfe90c4e3ca3474384c9f62b30bfd4c688b3e7d4110a1b4badc3cc54ef7b81241efd50d">>}. {"a.cek+hex", <<"6caf13723d14850ad4b42cd6dde935bffd2fff00a9ba70de05c203a5e1722ca7">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jwe/0000755000232200023220000000000013605433351021017 5ustar debalancedebalanceerlang-jose-1.10.1/test/jose_SUITE_data/jwe/a.3.config0000644000232200023220000000312713605433351022572 0ustar debalancedebalance{"a.3.txt", <<76,105,118,101,32,108,111,110,103,32,97,110,100,32,112,114,111,115,112,101,114,46>>}. {"a.3.1.jwe+json", <<"{\"alg\":\"A128KW\",\"enc\":\"A128CBC-HS256\"}">>}. {"a.3.1.jwe+json.b64", <<"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0">>}. {"a.3.2.cek", <<4,211,31,197,84,157,252,254,11,100,157,250,63,170,106,206,107,124,212,45,111,107,9,219,200,177,0,240,143,156,44,207>>}. {"a.3.3.jwk+json", <<"{\"kty\":\"oct\",\"k\":\"GawgguFyGrWKav7AX4VKUg\"}">>}. {"a.3.3.cek.encrypted", <<232,160,123,211,183,76,245,132,200,128,123,75,190,216,22,67,201,138,193,186,9,91,122,31,246,90,28,139,57,3,76,124,193,11,98,37,173,61,104,57>>}. {"a.3.3.cek.encrypted.b64", <<"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ">>}. {"a.3.4.iv", <<3,22,60,12,43,67,104,105,108,108,105,99,111,116,104,101>>}. {"a.3.4.iv.b64", <<"AxY8DCtDaGlsbGljb3RoZQ">>}. {"a.3.5.aad", <<101,121,74,104,98,71,99,105,79,105,74,66,77,84,73,52,83,49,99,105,76,67,74,108,98,109,77,105,79,105,74,66,77,84,73,52,81,48,74,68,76,85,104,84,77,106,85,50,73,110,48>>}. {"a.3.6.txt.cipher", <<40,57,83,181,119,33,133,148,198,185,243,24,152,230,6,75,129,223,127,19,210,82,183,230,168,33,215,104,143,112,56,102>>}. {"a.3.6.txt.tag", <<83,73,191,98,104,205,211,128,201,189,199,133,32,38,194,85>>}. {"a.3.6.txt.cipher.b64", <<"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY">>}. {"a.3.6.txt.tag.b64", <<"U0m_YmjN04DJvceFICbCVQ">>}. {"a.3.7.jwe+compact", <<"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.U0m_YmjN04DJvceFICbCVQ">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jwe/a.1.config0000644000232200023220000001142213605433351022565 0ustar debalancedebalance{"a.1.txt", <<84,104,101,32,116,114,117,101,32,115,105,103,110,32,111,102,32,105,110,116,101,108,108,105,103,101,110,99,101,32,105,115,32,110,111,116,32,107,110,111,119,108,101,100,103,101,32,98,117,116,32,105,109,97,103,105,110,97,116,105,111,110,46>>}. {"a.1.1.jwe+json", <<"{\"alg\":\"RSA-OAEP\",\"enc\":\"A256GCM\"}">>}. {"a.1.1.jwe+json.b64", <<"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ">>}. {"a.1.2.cek", <<177,161,244,128,84,143,225,115,63,180,3,255,107,154,212,246,138,7,110,91,112,46,34,105,47,130,203,46,122,234,64,252>>}. {"a.1.3.jwk+json", <<"{\"kty\":\"RSA\",\"n\":\"oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUWcJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3Spsk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2asbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMStPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2djYgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw\",\"e\":\"AQAB\",\"d\":\"kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5NWV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD93Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghkqDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vlt3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSndVTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ\",\"p\":\"1r52Xk46c-LsfB5P442p7atdPUrxQSy4mti_tZI3Mgf2EuFVbUoDBvaRQ-SWxkbkmoEzL7JXroSBjSrK3YIQgYdMgyAEPTPjXv_hI2_1eTSPVZfzL0lffNn03IXqWF5MDFuoUYE0hzb2vhrlN_rKrbfDIwUbTrjjgieRbwC6Cl0\",\"q\":\"wLb35x7hmQWZsWJmB_vle87ihgZ19S8lBEROLIsZG4ayZVe9Hi9gDVCOBmUDdaDYVTSNx_8Fyw1YYa9XGrGnDew00J28cRUoeBB_jKI1oma0Orv1T9aXIWxKwd4gvxFImOWr3QRL9KEBRzk2RatUBnmDZJTIAfwTs0g68UZHvtc\",\"dp\":\"ZK-YwE7diUh0qR1tR7w8WHtolDx3MZ_OTowiFvgfeQ3SiresXjm9gZ5KLhMXvo-uz-KUJWDxS5pFQ_M0evdo1dKiRTjVw_x4NyqyXPM5nULPkcpU827rnpZzAJKpdhWAgqrXGKAECQH0Xt4taznjnd_zVpAmZZq60WPMBMfKcuE\",\"dq\":\"Dq0gfgJ1DdFGXiLvQEZnuKEN0UUmsJBxkjydc3j4ZYdBiMRAy86x0vHCjywcMlYYg4yoC4YZa9hNVcsjqA3FeiL19rk8g6Qn29Tt0cj8qqyFpz9vNDBUfCAiJVeESOjJDZPYHdHY8v1b-o-Z2X5tvLx-TCekf7oxyeKDUqKWjis\",\"qi\":\"VIMpMYbPf47dT1w_zDUXfPimsSegnMOA1zTaX7aGk_8urY6R8-ZW1FxU7AlWAyLWybqq6t16VFd7hQd0y6flUK4SlOydB61gwanOsXGOAOv82cHq0E3eL4HrtZkUuKvnPrMnsUUFlfUdybVzxyjz9JF_XyaY14ardLSjf4L_FNY\"}">>}. {"a.1.3.cek.encrypted", <<56,163,154,192,58,53,222,4,105,218,136,218,29,94,203,22,150,92,129,94,211,232,53,89,41,60,138,56,196,216,82,98,168,76,37,73,70,7,36,8,191,100,136,196,244,220,145,158,138,155,4,117,141,230,199,247,173,45,182,214,74,177,107,211,153,11,205,196,171,226,162,128,171,182,13,237,239,99,193,4,91,219,121,223,107,167,61,119,228,173,156,137,134,200,80,219,74,253,56,185,91,177,34,158,89,154,205,96,55,18,138,43,96,218,215,128,124,75,138,243,85,25,109,117,140,26,155,249,67,167,149,231,100,6,41,65,214,251,232,87,72,40,182,149,154,168,31,193,126,215,89,28,111,219,125,182,139,235,195,197,23,234,55,58,63,180,68,202,206,149,75,205,248,176,67,39,178,60,98,193,32,238,122,96,158,222,57,183,111,210,55,188,215,206,180,166,150,166,106,250,55,229,72,40,69,214,216,104,23,40,135,212,28,127,41,80,175,174,168,115,171,197,89,116,92,103,246,83,216,182,176,84,37,147,35,45,219,172,99,226,233,73,37,124,42,72,49,242,35,127,184,134,117,114,135,206>>}. {"a.1.3.cek.encrypted.b64", <<"OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg">>}. {"a.1.4.iv", <<227,197,117,252,2,219,233,68,180,225,77,219>>}. {"a.1.4.iv.b64", <<"48V1_ALb6US04U3b">>}. {"a.1.5.aad", <<101,121,74,104,98,71,99,105,79,105,74,83,85,48,69,116,84,48,70,70,85,67,73,115,73,109,86,117,89,121,73,54,73,107,69,121,78,84,90,72,81,48,48,105,102,81>>}. {"a.1.6.txt.cipher", <<229,236,166,241,53,191,115,196,174,43,73,109,39,122,233,96,140,206,120,52,51,237,48,11,190,219,186,80,111,104,50,142,47,167,59,61,181,127,196,21,40,82,242,32,123,143,168,226,73,216,176,144,138,247,106,60,16,205,160,109,64,63,192>>}. {"a.1.6.txt.tag", <<92,80,104,49,133,25,161,215,173,101,219,211,136,91,210,145>>}. {"a.1.6.txt.cipher.b64", <<"5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A">>}. {"a.1.6.txt.tag.b64", <<"XFBoMYUZodetZdvTiFvSkQ">>}. {"a.1.7.jwe+compact", <<"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jwe/a.2.config0000644000232200023220000001077613605433351022601 0ustar debalancedebalance{"a.2.txt", <<76,105,118,101,32,108,111,110,103,32,97,110,100,32,112,114,111,115,112,101,114,46>>}. {"a.2.1.jwe+json", <<"{\"alg\":\"RSA1_5\",\"enc\":\"A128CBC-HS256\"}">>}. {"a.2.1.jwe+json.b64", <<"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0">>}. {"a.2.2.cek", <<4,211,31,197,84,157,252,254,11,100,157,250,63,170,106,206,107,124,212,45,111,107,9,219,200,177,0,240,143,156,44,207>>}. {"a.2.3.jwk+json", <<"{\"kty\":\"RSA\",\"n\":\"sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1WlUzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDprecbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_7svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBIY2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU7-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw\",\"e\":\"AQAB\",\"d\":\"VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq1OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-rynq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_0ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-KyvjT1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ\",\"p\":\"9gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEPkrdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM\",\"q\":\"uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-yBhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0\",\"dp\":\"w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuvngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcraHawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs\",\"dq\":\"o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff7B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU\",\"qi\":\"eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlCtUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZB9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo\"}">>}. {"a.2.3.cek.encrypted", <<80,104,72,58,11,130,236,139,132,189,255,205,61,86,151,176,99,40,44,233,176,189,205,70,202,169,72,40,226,181,156,223,120,156,115,232,150,209,145,133,104,112,237,156,116,250,65,102,212,210,103,240,177,61,93,40,71,231,223,226,240,157,15,31,150,89,200,215,198,203,108,70,117,66,212,238,193,205,23,161,169,218,243,203,128,214,127,253,215,139,43,17,135,103,179,220,28,2,212,206,131,158,128,66,62,240,78,186,141,125,132,227,60,137,43,31,152,199,54,72,34,212,115,11,152,101,70,42,219,233,142,66,151,250,126,146,141,216,190,73,50,177,146,5,52,247,28,197,21,59,170,247,181,89,131,241,169,182,246,99,15,36,102,166,182,172,197,136,230,120,60,58,219,243,149,94,222,150,154,194,110,227,225,112,39,89,233,112,207,211,241,124,174,69,221,179,107,196,225,127,167,112,226,12,242,16,24,28,120,182,244,213,244,153,194,162,69,160,244,248,63,165,141,4,207,249,193,79,131,0,169,233,127,167,101,151,125,56,112,111,248,29,232,90,29,147,110,169,146,114,165,204,71,136,41,252>>}. {"a.2.3.cek.encrypted.b64", <<"UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A">>}. {"a.2.4.iv", <<3,22,60,12,43,67,104,105,108,108,105,99,111,116,104,101>>}. {"a.2.4.iv.b64", <<"AxY8DCtDaGlsbGljb3RoZQ">>}. {"a.2.5.aad", <<101,121,74,104,98,71,99,105,79,105,74,83,85,48,69,120,88,122,85,105,76,67,74,108,98,109,77,105,79,105,74,66,77,84,73,52,81,48,74,68,76,85,104,84,77,106,85,50,73,110,48>>}. {"a.2.6.txt.cipher", <<40,57,83,181,119,33,133,148,198,185,243,24,152,230,6,75,129,223,127,19,210,82,183,230,168,33,215,104,143,112,56,102>>}. {"a.2.6.txt.tag", <<246,17,244,190,4,95,98,3,231,0,115,157,242,203,100,191>>}. {"a.2.6.txt.cipher.b64", <<"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY">>}. {"a.2.6.txt.tag.b64", <<"9hH0vgRfYgPnAHOd8stkvw">>}. {"a.2.7.jwe+compact", <<"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.9hH0vgRfYgPnAHOd8stkvw">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jwk/0000755000232200023220000000000013605433351021025 5ustar debalancedebalanceerlang-jose-1.10.1/test/jose_SUITE_data/jwk/c.2.jwe+json0000644000232200023220000000015513605433351023064 0ustar debalancedebalance{"alg":"PBES2-HS256+A128KW","p2s":"2WCTcJZ1Rvd_CJuJripQ1w","p2c":4096,"enc":"A128CBC-HS256","cty":"jwk+json"}erlang-jose-1.10.1/test/jose_SUITE_data/jwk/c.1.jwk+json0000644000232200023220000000316613605433351023076 0ustar debalancedebalance{"kty":"RSA","kid":"juliet@capulet.lit","use":"enc","n":"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRyO125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0XOC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q","e":"AQAB","d":"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfSNkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9UvqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnuToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsurY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2ahecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ","p":"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHfQP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws","q":"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6Iedis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYKrYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s","dp":"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1wY52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c","dq":"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBymXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots","qi":"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqqabu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0oYu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8"}erlang-jose-1.10.1/test/jose_SUITE_data/jwk/c.config0000644000232200023220000002607713605433351022452 0ustar debalancedebalance{"c.1.jwk+json", <<"{\"kty\":\"RSA\",\"kid\":\"juliet@capulet.lit\",\"use\":\"enc\",\"n\":\"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRyO125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0XOC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q\",\"e\":\"AQAB\",\"d\":\"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfSNkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9UvqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnuToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsurY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2ahecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ\",\"p\":\"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHfQP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws\",\"q\":\"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6Iedis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYKrYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s\",\"dp\":\"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1wY52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c\",\"dq\":\"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBymXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots\",\"qi\":\"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqqabu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0oYu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8\"}">>}. {"c.2.b64", <<"eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJwMnMiOiIyV0NUY0paMVJ2ZF9DSnVKcmlwUTF3IiwicDJjIjo0MDk2LCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiandrK2pzb24ifQ">>}. {"c.2.jwe+json", <<"{\"alg\":\"PBES2-HS256+A128KW\",\"p2s\":\"2WCTcJZ1Rvd_CJuJripQ1w\",\"p2c\":4096,\"enc\":\"A128CBC-HS256\",\"cty\":\"jwk+json\"}">>}. {"c.3.cek", <<111,27,25,52,66,29,20,78,92,176,56,240,65,208,82,112,161,131,36,55,202,236,185,172,129,23,153,194,195,48,253,182>>}. {"c.4.derivedkey", <<110,171,169,92,129,92,109,117,233,242,116,233,170,14,24,75>>}. {"c.4.salt", <<80,66,69,83,50,45,72,83,50,53,54,43,65,49,50,56,75,87,0,217,96,147,112,150,117,70,247,127,8,155,137,174,42,80,215>>}. {"c.4.txt", <<"Thus from my lips, by yours, my sin is purged.">>}. {"c.5.encryptedkey", <<78,186,151,59,11,141,81,240,213,245,83,211,53,188,134,188,66,125,36,200,222,124,5,103,249,52,117,184,140,81,246,158,161,177,20,33,245,57,59,4>>}. {"c.6.iv", <<97,239,99,214,171,54,216,57,145,72,7,93,34,31,149,156>>}. {"c.7.aad", <<"{\"alg\":\"PBES2-HS256+A128KW\",\"p2s\":\"2WCTcJZ1Rvd_CJuJripQ1w\",\"p2c\":4096,\"enc\":\"A128CBC-HS256\",\"cty\":\"jwk+json\"}">>}. {"c.8.ciphertag", <<208,113,102,132,236,236,67,223,39,53,98,99,32,121,17,236>>}. {"c.8.ciphertxt", <<3,8,65,242,92,107,148,168,197,159,77,139,25,97,42,131,110,199,225,56,61,127,38,64,108,91,247,167,150,98,112,122,99,235,132,50,28,46,56,170,169,89,220,145,38,157,148,224,66,140,8,169,146,117,222,54,242,28,31,11,129,227,226,169,66,117,133,254,140,216,115,203,131,60,60,47,233,132,121,13,35,188,53,19,172,77,59,54,211,158,172,25,60,111,0,80,201,158,160,210,68,55,12,67,136,130,87,216,197,95,62,20,155,205,5,140,27,168,221,65,114,78,157,254,46,206,182,52,135,87,239,3,34,186,126,220,151,17,33,237,57,96,172,183,58,45,248,103,241,142,136,7,53,16,173,181,7,93,92,252,1,53,212,242,8,255,11,239,181,24,148,136,111,24,161,244,23,106,69,157,215,243,189,240,166,169,249,72,38,201,99,223,173,229,9,222,82,79,157,176,248,85,239,121,163,1,31,48,98,206,61,249,104,216,201,227,105,48,194,193,10,36,160,159,241,166,84,54,188,211,243,242,40,46,45,193,193,160,169,101,201,1,73,47,105,142,88,28,42,132,26,61,58,63,142,243,77,26,179,153,166,46,203,208,49,55,229,34,178,4,109,180,204,204,115,1,103,193,5,91,215,214,195,1,110,208,53,144,36,105,12,54,25,129,101,15,183,150,250,147,115,227,58,250,5,128,232,63,15,14,19,141,124,253,142,137,189,135,26,44,240,27,88,132,105,127,6,71,37,41,124,187,165,140,34,200,123,80,228,24,231,176,132,171,138,145,152,116,224,50,141,51,147,91,186,7,246,106,217,148,244,227,244,45,220,121,165,224,148,181,17,181,128,197,101,237,11,169,229,149,199,78,56,15,14,190,91,216,222,247,213,74,40,8,96,20,168,119,96,26,24,52,37,82,127,57,176,147,118,59,7,224,33,117,72,155,29,82,26,215,189,140,119,28,152,118,93,222,194,192,148,115,83,253,216,212,108,88,83,175,172,220,97,79,110,42,223,170,161,34,164,144,193,76,122,92,160,41,178,175,6,35,96,113,96,158,90,129,101,26,45,70,180,189,230,15,5,247,150,209,94,171,26,13,142,212,129,1,176,5,0,112,203,174,185,119,76,233,189,54,172,189,245,223,253,205,12,88,9,126,157,225,90,40,229,191,63,30,160,224,69,3,140,109,70,89,37,213,245,194,210,180,188,63,210,139,221,2,144,200,20,177,216,29,227,242,106,12,135,142,139,144,82,225,162,171,176,108,99,6,43,193,161,116,234,216,1,242,21,124,162,98,205,124,193,38,12,242,90,101,76,204,184,124,58,180,16,240,26,76,195,250,212,191,185,191,97,198,186,73,225,75,14,90,123,121,172,101,50,160,221,141,253,205,126,77,9,87,198,110,104,182,141,120,51,25,232,3,32,80,6,156,8,18,4,135,221,142,25,135,2,129,132,115,227,74,141,28,119,11,141,117,134,198,62,150,254,97,75,197,251,99,89,204,224,226,67,83,175,89,0,81,29,38,207,89,140,255,197,177,164,128,62,116,224,180,109,169,28,2,59,176,130,252,44,178,81,24,181,176,75,44,61,91,12,37,21,255,83,130,197,16,231,60,217,56,131,118,168,202,58,52,84,124,162,185,174,162,226,242,112,68,246,202,16,208,52,154,58,129,80,102,33,171,6,186,177,14,195,88,136,6,0,155,28,100,162,207,162,222,117,248,170,208,114,87,31,57,176,33,57,83,253,12,168,110,194,59,22,86,48,227,196,22,176,218,122,149,21,249,195,178,174,250,20,34,120,60,139,201,99,40,18,177,17,54,54,6,3,222,128,160,88,11,27,0,81,192,36,41,169,146,8,47,64,136,28,64,209,67,135,202,20,234,182,91,204,146,195,187,0,72,77,11,111,152,204,252,177,212,89,33,50,132,184,44,183,186,19,250,69,176,201,102,140,14,143,212,212,160,123,208,185,27,155,68,77,133,198,2,126,155,215,22,91,30,217,176,172,244,156,174,143,75,90,21,102,1,160,59,253,188,88,57,185,197,83,24,22,180,174,47,207,52,1,141,146,119,233,68,228,224,228,193,248,155,202,90,7,213,88,33,108,107,14,86,8,120,250,58,142,35,164,238,221,219,35,123,88,199,192,143,104,83,17,166,243,247,11,166,67,68,204,132,23,110,103,228,14,55,122,88,57,180,178,237,52,130,214,245,102,123,67,73,175,1,127,112,148,94,132,164,197,153,217,87,25,89,93,63,22,66,166,90,251,101,10,145,66,17,124,36,255,165,226,97,16,86,112,154,88,105,253,56,209,229,122,103,51,24,228,190,3,236,48,182,121,176,140,128,117,87,251,224,37,23,248,21,218,85,251,136,84,147,143,144,46,155,183,251,89,86,23,26,237,100,167,32,130,173,237,89,55,110,70,142,127,65,230,208,109,69,19,253,84,130,130,193,92,58,108,150,42,136,249,234,86,241,182,19,117,246,26,181,92,101,155,44,103,235,173,30,140,90,29,183,190,77,53,206,127,5,87,8,187,184,92,4,157,22,18,105,251,39,88,182,181,103,148,233,6,63,70,188,7,101,216,127,77,31,12,233,7,147,106,30,150,77,145,13,205,48,56,245,220,89,252,127,51,180,36,31,55,18,214,230,254,217,197,65,247,27,215,117,247,108,157,121,11,63,150,195,83,6,134,242,41,24,105,204,5,63,192,14,159,113,72,140,128,51,215,80,215,39,149,94,79,128,34,5,129,82,83,121,187,37,146,27,32,177,167,71,9,195,30,199,196,205,252,207,69,8,120,27,190,51,43,75,249,234,167,116,206,203,199,43,108,87,48,155,140,228,210,85,25,161,96,67,8,205,64,39,75,88,44,238,227,16,0,100,93,129,18,4,149,50,68,72,99,35,111,254,27,102,175,108,233,87,181,44,169,18,139,79,208,14,202,192,5,162,222,231,149,24,211,49,120,101,39,206,87,147,204,200,251,104,115,5,127,117,195,79,151,18,224,52,0,245,4,85,255,103,217,0,116,198,80,91,167,192,154,199,197,149,237,51,2,131,30,226,95,105,48,68,135,208,144,120,176,145,157,8,171,80,94,61,92,92,220,157,13,138,51,23,185,124,31,77,1,87,241,43,239,55,122,86,210,48,208,204,112,144,80,147,106,219,47,253,31,134,176,16,135,219,95,17,129,83,236,125,136,112,86,228,252,71,129,218,174,156,236,12,27,159,11,138,252,253,207,31,115,214,118,239,203,16,211,205,99,22,51,163,107,162,246,199,67,127,34,108,197,53,117,58,199,3,190,74,70,190,65,235,175,97,157,215,252,189,245,100,229,248,46,90,126,237,4,159,128,58,7,156,236,69,191,85,240,179,224,249,152,49,195,223,60,78,186,157,155,217,58,105,116,164,217,111,215,150,218,252,84,86,248,140,240,226,61,106,208,95,60,163,6,0,235,253,162,96,62,234,251,249,35,21,7,211,233,86,50,33,203,67,248,60,190,123,48,167,226,90,191,71,56,183,165,17,85,76,238,140,211,168,53,223,194,4,97,149,156,120,137,76,33,229,243,194,208,198,202,139,28,114,46,224,92,254,83,100,134,158,92,70,78,61,62,138,24,173,216,66,198,70,254,47,59,193,53,6,139,19,153,253,28,199,122,160,27,67,234,209,227,139,4,50,7,178,183,89,252,32,128,137,55,52,29,89,12,111,42,181,51,170,132,132,207,170,228,254,178,213,0,136,175,8>>}. {"c.9.jwe+txt", <<"eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJwMnMiOiIyV0NUY0paMVJ2ZF9DSnVKcmlwUTF3IiwicDJjIjo0MDk2LCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiandrK2pzb24ifQ.TrqXOwuNUfDV9VPTNbyGvEJ9JMjefAVn-TR1uIxR9p6hsRQh9Tk7BA.Ye9j1qs22DmRSAddIh-VnA.AwhB8lxrlKjFn02LGWEqg27H4Tg9fyZAbFv3p5ZicHpj64QyHC44qqlZ3JEmnZTgQowIqZJ13jbyHB8LgePiqUJ1hf6M2HPLgzw8L-mEeQ0jvDUTrE07NtOerBk8bwBQyZ6g0kQ3DEOIglfYxV8-FJvNBYwbqN1Bck6d_i7OtjSHV-8DIrp-3JcRIe05YKy3Oi34Z_GOiAc1EK21B11c_AE11PII_wvvtRiUiG8YofQXakWd1_O98Kap-UgmyWPfreUJ3lJPnbD4Ve95owEfMGLOPflo2MnjaTDCwQokoJ_xplQ2vNPz8iguLcHBoKllyQFJL2mOWBwqhBo9Oj-O800as5mmLsvQMTflIrIEbbTMzHMBZ8EFW9fWwwFu0DWQJGkMNhmBZQ-3lvqTc-M6-gWA6D8PDhONfP2Oib2HGizwG1iEaX8GRyUpfLuljCLIe1DkGOewhKuKkZh04DKNM5Nbugf2atmU9OP0Ldx5peCUtRG1gMVl7Qup5ZXHTjgPDr5b2N731UooCGAUqHdgGhg0JVJ_ObCTdjsH4CF1SJsdUhrXvYx3HJh2Xd7CwJRzU_3Y1GxYU6-s3GFPbirfqqEipJDBTHpcoCmyrwYjYHFgnlqBZRotRrS95g8F95bRXqsaDY7UgQGwBQBwy665d0zpvTasvfXf_c0MWAl-neFaKOW_Px6g4EUDjG1GWSXV9cLStLw_0ovdApDIFLHYHePyagyHjouQUuGiq7BsYwYrwaF06tgB8hV8omLNfMEmDPJaZUzMuHw6tBDwGkzD-tS_ub9hxrpJ4UsOWnt5rGUyoN2N_c1-TQlXxm5oto14MxnoAyBQBpwIEgSH3Y4ZhwKBhHPjSo0cdwuNdYbGPpb-YUvF-2NZzODiQ1OvWQBRHSbPWYz_xbGkgD504LRtqRwCO7CC_CyyURi1sEssPVsMJRX_U4LFEOc82TiDdqjKOjRUfKK5rqLi8nBE9soQ0DSaOoFQZiGrBrqxDsNYiAYAmxxkos-i3nX4qtByVx85sCE5U_0MqG7COxZWMOPEFrDaepUV-cOyrvoUIng8i8ljKBKxETY2BgPegKBYCxsAUcAkKamSCC9AiBxA0UOHyhTqtlvMksO7AEhNC2-YzPyx1FkhMoS4LLe6E_pFsMlmjA6P1NSge9C5G5tETYXGAn6b1xZbHtmwrPScro9LWhVmAaA7_bxYObnFUxgWtK4vzzQBjZJ36UTk4OTB-JvKWgfVWCFsaw5WCHj6Oo4jpO7d2yN7WMfAj2hTEabz9wumQ0TMhBduZ-QON3pYObSy7TSC1vVme0NJrwF_cJRehKTFmdlXGVldPxZCplr7ZQqRQhF8JP-l4mEQVnCaWGn9ONHlemczGOS-A-wwtnmwjIB1V_vgJRf4FdpV-4hUk4-QLpu3-1lWFxrtZKcggq3tWTduRo5_QebQbUUT_VSCgsFcOmyWKoj56lbxthN19hq1XGWbLGfrrR6MWh23vk01zn8FVwi7uFwEnRYSafsnWLa1Z5TpBj9GvAdl2H9NHwzpB5NqHpZNkQ3NMDj13Fn8fzO0JB83Etbm_tnFQfcb13X3bJ15Cz-Ww1MGhvIpGGnMBT_ADp9xSIyAM9dQ1yeVXk-AIgWBUlN5uyWSGyCxp0cJwx7HxM38z0UIeBu-MytL-eqndM7LxytsVzCbjOTSVRmhYEMIzUAnS1gs7uMQAGRdgRIElTJESGMjb_4bZq9s6Ve1LKkSi0_QDsrABaLe55UY0zF4ZSfOV5PMyPtocwV_dcNPlxLgNAD1BFX_Z9kAdMZQW6fAmsfFle0zAoMe4l9pMESH0JB4sJGdCKtQXj1cXNydDYozF7l8H00BV_Er7zd6VtIw0MxwkFCTatsv_R-GsBCH218RgVPsfYhwVuT8R4HarpzsDBufC4r8_c8fc9Z278sQ081jFjOja6L2x0N_ImzFNXU6xwO-Ska-QeuvYZ3X_L31ZOX4Llp-7QSfgDoHnOxFv1Xws-D5mDHD3zxOup2b2TppdKTZb9eW2vxUVviM8OI9atBfPKMGAOv9omA-6vv5IxUH0-lWMiHLQ_g8vnswp-Jav0c4t6URVUzujNOoNd_CBGGVnHiJTCHl88LQxsqLHHIu4Fz-U2SGnlxGTj0-ihit2ELGRv4vO8E1BosTmf0cx3qgG0Pq0eOLBDIHsrdZ_CCAiTc0HVkMbyq1M6qEhM-q5P6y1QCIrwg.0HFmhOzsQ98nNWJjIHkR7A">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jws/0000755000232200023220000000000013605433351021035 5ustar debalancedebalanceerlang-jose-1.10.1/test/jose_SUITE_data/jws/a.3.config0000644000232200023220000000202413605433351022603 0ustar debalancedebalance{"a.3.1.b64", <<"eyJhbGciOiJFUzI1NiJ9">>}. {"a.3.1.compact", <<"eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q">>}. {"a.3.1.jwk+json", <<"{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU\",\"y\":\"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0\",\"d\":\"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI\"}">>}. {"a.3.1.jws+json", <<"{\"alg\":\"ES256\"}">>}. {"a.3.1.payload", <<"{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n \"http://example.com/is_root\":true}">>}. {"a.3.1.payload-b64", <<"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ">>}. {"a.3.1.signature-b64", <<"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q">>}. {"a.3.1.signing-input", <<"eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ">>}. erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.3.1.jws+json0000644000232200023220000000001713605433351023245 0ustar debalancedebalance{"alg":"ES256"}erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.2.1.jwk+json0000644000232200023220000000311713605433351023240 0ustar debalancedebalance{"kty":"RSA","n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ","e":"AQAB","d":"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97IjlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYTCBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLhBOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ","p":"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPGBY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc","q":"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc","dp":"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3QCLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0","dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU","qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"}erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.5.config0000644000232200023220000000112713605433351022610 0ustar debalancedebalance{"a.5.b64", <<"eyJhbGciOiJub25lIn0">>}. {"a.5.compact", <<"eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.">>}. {"a.5.jws+json", <<"{\"alg\":\"none\"}">>}. {"a.5.payload", <<"{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n \"http://example.com/is_root\":true}">>}. {"a.5.payload-b64", <<"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ">>}. {"a.5.signing-input", <<"eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ">>}. erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.4.config0000644000232200023220000000201013605433351022577 0ustar debalancedebalance{"a.4.1.b64", <<"eyJhbGciOiJFUzUxMiJ9">>}. {"a.4.1.compact", <<"eyJhbGciOiJFUzUxMiJ9.UGF5bG9hZA.AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn">>}. {"a.4.1.jwk+json", <<"{\"kty\":\"EC\",\"crv\":\"P-521\",\"x\":\"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk\",\"y\":\"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDly79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2\",\"d\":\"AY5pb7A0UFiB3RELSD64fTLOSV_jazdF7fLYyuTw8lOfRhWg6Y6rUrPAxerEzgdRhajnu0ferB0d53vM9mE15j2C\"}">>}. {"a.4.1.jws+json", <<"{\"alg\":\"ES512\"}">>}. {"a.4.1.payload", <<"Payload">>}. {"a.4.1.payload-b64", <<"UGF5bG9hZA">>}. {"a.4.1.signature-b64", <<"AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZqwqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8KpEHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn">>}. {"a.4.1.signing-input", <<"eyJhbGciOiJFUzUxMiJ9.UGF5bG9hZA">>}. erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.1.1.jwk+json0000644000232200023220000000015213605433351023233 0ustar debalancedebalance{"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"}erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.2.1.jws+json0000644000232200023220000000001713605433351023244 0ustar debalancedebalance{"alg":"RS256"}erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.5.jws+json0000644000232200023220000000001613605433351023107 0ustar debalancedebalance{"alg":"none"}erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.1.config0000644000232200023220000000167513605433351022614 0ustar debalancedebalance{"a.1.1.b64", <<"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9">>}. {"a.1.1.compact", <<"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk">>}. {"a.1.1.jwk+json", <<"{\"kty\":\"oct\",\"k\":\"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\"}">>}. {"a.1.1.jws+json", <<"{\"typ\":\"JWT\",\r\n \"alg\":\"HS256\"}">>}. {"a.1.1.payload", <<"{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n \"http://example.com/is_root\":true}">>}. {"a.1.1.payload-b64", <<"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ">>}. {"a.1.1.signature-b64", <<"dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk">>}. {"a.1.1.signing-input", <<"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ">>}. erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.2.config0000644000232200023220000000570313605433351022611 0ustar debalancedebalance{"a.2.1.b64", <<"eyJhbGciOiJSUzI1NiJ9">>}. {"a.2.1.compact", <<"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw">>}. {"a.2.1.jwk+json", <<"{\"kty\":\"RSA\",\"n\":\"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ\",\"e\":\"AQAB\",\"d\":\"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97IjlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYTCBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLhBOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ\",\"p\":\"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPGBY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc\",\"q\":\"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc\",\"dp\":\"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3QCLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0\",\"dq\":\"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU\",\"qi\":\"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U\"}">>}. {"a.2.1.jws+json", <<"{\"alg\":\"RS256\"}">>}. {"a.2.1.payload", <<"{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n \"http://example.com/is_root\":true}">>}. {"a.2.1.payload-b64", <<"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ">>}. {"a.2.1.signature-b64", <<"cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw">>}. {"a.2.1.signing-input", <<"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ">>}. erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.4.1.jws+json0000644000232200023220000000001713605433351023246 0ustar debalancedebalance{"alg":"ES512"}erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.4.1.jwk+json0000644000232200023220000000046713605433351023247 0ustar debalancedebalance{"kty":"EC","crv":"P-521","x":"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk","y":"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDly79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2","d":"AY5pb7A0UFiB3RELSD64fTLOSV_jazdF7fLYyuTw8lOfRhWg6Y6rUrPAxerEzgdRhajnu0ferB0d53vM9mE15j2C"}erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.3.1.jwk+json0000644000232200023220000000026013605433351023235 0ustar debalancedebalance{"kty":"EC","crv":"P-256","x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU","y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0","d":"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI"}erlang-jose-1.10.1/test/jose_SUITE_data/jws/a.1.1.jws+json0000644000232200023220000000003613605433351023244 0ustar debalancedebalance{"typ":"JWT", "alg":"HS256"}erlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/0000755000232200023220000000000013605433351023562 5ustar debalancedebalanceerlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/a.3.config0000644000232200023220000000043713605433351025336 0ustar debalancedebalance{"a.3.jwk+json", <<"{\"crv\":\"Ed25519\",\"kty\":\"OKP\",\"x\":\"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo\"}">>}. {"a.3.thumbprint+hex", <<"90facafea9b1556698540f70c0117a22ea37bd5cf3ed3c47093c1707282b4b89">>}. {"a.3.thumbprint+b64", <<"kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/a.5.config0000644000232200023220000000040713605433351025335 0ustar debalancedebalance{"a.5.sig+compact", <<"eyJhbGciOiJFZERTQSJ9.RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc.hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg">>}. {"a.5.jws+json", <<"{\"alg\":\"EdDSA\"}">>}. {"a.5.txt", <<"Example of Ed25519 signing">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/a.4.config0000644000232200023220000000131713605433351025335 0ustar debalancedebalance{"a.4.jws+json", <<"{\"alg\":\"EdDSA\"}">>}. {"a.4.jws+b64", <<"eyJhbGciOiJFZERTQSJ9">>}. {"a.4.txt", <<"Example of Ed25519 signing">>}. {"a.4.txt+b64", <<"RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc">>}. {"a.4.signing-input", <<"eyJhbGciOiJFZERTQSJ9.RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc">>}. {"a.4.sig+hex", <<"860c98d2297f3060a33f42739672d61b53cf3adefed3d3c672f320dc021b411e9d59b8628dc351e248b88b29468e0e41855b0fb7d83bb15be902bfccb8cd0a02">>}. {"a.4.sig+b64", <<"hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg">>}. {"a.4.sig+compact", <<"eyJhbGciOiJFZERTQSJ9.RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc.hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/a.7.config0000644000232200023220000000232713605433351025342 0ustar debalancedebalance{"a.7.bob-jwk+json", <<"{\"kty\":\"OKP\",\"crv\":\"X448\",\"kid\":\"Dave\",\"x\":\"PreoKbDNIPW8_AtZm2_sz22kYnEHvbDU80W0MCfYuXL8PjT7QjKhPKcG3LV67D2uB73BxnvzNgk\"}">>}. {"a.7.bob-secret+hex", <<"1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d">>}. {"a.7.bob-pk+hex", <<"3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609">>}. {"a.7.epk-secret+hex", <<"9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b">>}. {"a.7.epk-pk+hex", <<"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0">>}. {"a.7.epk-jwk+json", <<"{\"kty\":\"OKP\",\"crv\":\"X448\",\"x\":\"mwj3zDG34-Z9ItWuoSEHSic70rg94Jxj-qc9LCLF2bvINmRyQdlT1AxbEtqIEg1TF3-A5TLEH6A\"}">>}. {"a.7.jwe+json", <<"{\"alg\":\"ECDH-ES+A256KW\",\"epk\":{\"kty\":\"OKP\",\"crv\":\"X448\",\"x\":\"mwj3zDG34-Z9ItWuoSEHSic70rg94Jxj-qc9LCLF2bvINmRyQdlT1AxbEtqIEg1TF3-A5TLEH6A\"},\"enc\":\"A256GCM\",\"kid\":\"Dave\"}">>}. {"a.7.z+hex", <<"07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/a.1.config0000644000232200023220000000025413605433351025331 0ustar debalancedebalance{"a.1.secret", <<"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60">>}. {"a.1.pk", <<"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a">>}. erlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/a.2.jwk+json0000644000232200023220000000011713605433351025623 0ustar debalancedebalance{"kty":"OKP","crv":"Ed25519","x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"}erlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/a.6.config0000644000232200023220000000161313605433351025336 0ustar debalancedebalance{"a.6.bob-jwk+json", <<"{\"kty\":\"OKP\",\"crv\":\"X25519\",\"kid\":\"Bob\",\"x\":\"3p7bfXt9wbTTW2HC7OQ1Nz-DQ8hbeGdNrfx-FG-IK08\"}">>}. {"a.6.bob-secret+hex", <<"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb">>}. {"a.6.bob-pk+hex", <<"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f">>}. {"a.6.epk-secret+hex", <<"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a">>}. {"a.6.epk-pk+hex", <<"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a">>}. {"a.6.epk-jwk+json", <<"{\"kty\":\"OKP\",\"crv\":\"X25519\",\"x\":\"hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo\"}">>}. {"a.6.jwe+json", <<"{\"alg\":\"ECDH-ES+A128KW\",\"epk\":{\"kty\":\"OKP\",\"crv\":\"X25519\",\"x\":\"hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo\"},\"enc\":\"A128GCM\",\"kid\":\"Bob\"}">>}. {"a.6.z+hex", <<"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742">>}.erlang-jose-1.10.1/test/jose_SUITE_data/jose_cfrg_curves/a.1.jwk+json0000644000232200023220000000020113605433351025614 0ustar debalancedebalance{"kty":"OKP","crv":"Ed25519","d":"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A","x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"}erlang-jose-1.10.1/test/jose_SUITE_data/rfc7520/0000755000232200023220000000000013605433351021322 5ustar debalancedebalanceerlang-jose-1.10.1/test/jose_SUITE_data/rfc7520/5.9.config0000644000232200023220000000605713605433351023034 0ustar debalancedebalance{"figure.72", <<89,111,117,32,99,97,110,32,116,114,117,115,116,32,117,115,32,116,111,32,115,116,105,99,107,32,119,105,116,104,32,121,111,117,32,116,104,114,111,117,103,104,32,116,104,105,99,107,32,97,110,100,32,116,104,105,110,226,128,147,116,111,32,116,104,101,32,98,105,116,116,101,114,32,101,110,100,46,32,65,110,100,32,121,111,117,32,99,97,110,32,116,114,117,115,116,32,117,115,32,116,111,32,107,101,101,112,32,97,110,121,32,115,101,99,114,101,116,32,111,102,32,121,111,117,114,115,226,128,147,99,108,111,115,101,114,32,116,104,97,110,32,121,111,117,32,107,101,101,112,32,105,116,32,121,111,117,114,115,101,108,102,46,32,66,117,116,32,121,111,117,32,99,97,110,110,111,116,32,116,114,117,115,116,32,117,115,32,116,111,32,108,101,116,32,121,111,117,32,102,97,99,101,32,116,114,111,117,98,108,101,32,97,108,111,110,101,44,32,97,110,100,32,103,111,32,111,102,102,32,119,105,116,104,111,117,116,32,97,32,119,111,114,100,46,32,87,101,32,97,114,101,32,121,111,117,114,32,102,114,105,101,110,100,115,44,32,70,114,111,100,111,46>>}. {"figure.151", <<"{\"kty\":\"oct\",\"kid\":\"81b20965-8332-43d9-a468-82160ad91ac8\",\"use\":\"enc\",\"alg\":\"A128KW\",\"k\":\"GZy6sIZ6wl9NJOKB-jnmVQ\"}">>}. {"figure.162", <<"bY_BDcIwDEVX-QNU3QEOrIA4pqlDokYxchxVvbEDGzIJbioOSJwc-f___HPjBu8KVFpVtAplVE1-wZo0YjNZo3C7R5v72pV5f5X382VWjYQpqZKAyjziZOr2B7kQPSy6oZIXUnDYbVKN4jNXi2u0yB7t1qSHTjmMODf9QgvrDzfTIQXnyQRuUya4zIWG3vTOdir0v7BRHFYWq3k1k1A_gSDJqtcBF-GZxw8">>}. {"figure.163", <<"hC-MpLZSuwWv8sexS6ydfw">>}. {"figure.164", <<"p9pUq6XHY0jfEZIl">>}. {"figure.165", <<"5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi">>}. {"figure.166", <<"{\"alg\":\"A128KW\",\"kid\":\"81b20965-8332-43d9-a468-82160ad91ac8\",\"enc\":\"A128GCM\",\"zip\":\"DEF\"}">>}. {"figure.167", <<"eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0">>}. {"figure.168", <<"HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw">>}. {"figure.169", <<"VILuUwuIxaLVmh5X-T7kmA">>}. {"figure.170", <<"eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0.5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi.p9pUq6XHY0jfEZIl.HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw.VILuUwuIxaLVmh5X-T7kmA">>}. {"figure.172", <<"{\"protected\":\"eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0\",\"encrypted_key\":\"5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi\",\"iv\":\"p9pUq6XHY0jfEZIl\",\"ciphertext\":\"HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw\",\"tag\":\"VILuUwuIxaLVmh5X-T7kmA\"}">>}.erlang-jose-1.10.1/test/jose_test.exs0000644000232200023220000005577513605433351020073 0ustar debalancedebalancedefmodule JOSETest do use ExUnit.Case, async: false setup_all do JOSE.crypto_fallback(true) :ok end test "JOSE.JWA 128-bit encrypt and decrypt" do key = <<0::128>> cbc_iv = <<0::128>> gcm_iv = <<0::96>> aad = <<>> plain_text = "my plain text that will be encrypted and decrypted" padded_plain_text = :jose_jwa_pkcs7.pad(plain_text) cbc_cipher_text = <<199, 137, 180, 181, 237, 81, 30, 239, 12, 183, 48, 136, 189, 120, 32, 120, 2, 184, 140, 30, 193, 245, 216, 166, 134, 123, 91, 16, 96, 158, 102, 48, 174, 205, 240, 31, 66, 164, 135, 107, 142, 193, 158, 113, 111, 41, 201, 248, 18, 235, 208, 146, 39, 147, 167, 155, 213, 115, 66, 41, 32, 147, 133, 108>> ecb_cipher_text = <<199, 137, 180, 181, 237, 81, 30, 239, 12, 183, 48, 136, 189, 120, 32, 120, 196, 190, 232, 104, 49, 166, 58, 104, 4, 101, 23, 230, 131, 230, 216, 54, 111, 74, 1, 207, 251, 80, 216, 24, 126, 96, 68, 178, 160, 232, 54, 184, 174, 111, 184, 35, 145, 216, 208, 74, 42, 19, 166, 82, 247, 178, 75, 249>> gcm_cipher_text = <<110, 241, 250, 190, 12, 215, 202, 252, 211, 92, 167, 193, 5, 146, 138, 16, 150, 225, 138, 220, 32, 39, 53, 3, 149, 152, 169, 154, 250, 232, 179, 153, 80, 118, 116, 69, 110, 18, 250, 190, 0, 237, 211, 207, 162, 234, 219, 148, 172, 41, 172, 23, 31, 128, 39, 115, 117, 112, 178, 178, 199, 205, 134, 252>> gcm_cipher_tag = <<51, 155, 66, 18, 126, 201, 118, 185, 242, 41, 175, 75, 96, 213, 29, 68>> assert cbc_cipher_text == JOSE.JWA.block_encrypt({:aes_cbc, 128}, key, cbc_iv, padded_plain_text) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_cbc, 128}, key, cbc_iv, cbc_cipher_text)) assert ecb_cipher_text == JOSE.JWA.block_encrypt({:aes_ecb, 128}, key, padded_plain_text) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_ecb, 128}, key, ecb_cipher_text)) assert {gcm_cipher_text, gcm_cipher_tag} == JOSE.JWA.block_encrypt({:aes_gcm, 128}, key, gcm_iv, {aad, padded_plain_text}) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_gcm, 128}, key, gcm_iv, {aad, gcm_cipher_text, gcm_cipher_tag})) end test "JOSE.JWA 192-bit encrypt and decrypt" do key = <<0::192>> cbc_iv = <<0::128>> gcm_iv = <<0::96>> aad = <<>> plain_text = "my plain text that will be encrypted and decrypted" padded_plain_text = :jose_jwa_pkcs7.pad(plain_text) cbc_cipher_text = <<49, 252, 5, 74, 231, 203, 35, 84, 241, 143, 161, 11, 238, 168, 150, 220, 5, 186, 188, 246, 39, 46, 14, 237, 8, 193, 241, 107, 82, 192, 36, 19, 53, 7, 75, 14, 27, 5, 84, 179, 141, 162, 74, 154, 7, 86, 106, 203, 149, 140, 92, 130, 21, 168, 122, 3, 174, 155, 120, 197, 130, 55, 103, 223>> ecb_cipher_text = <<49, 252, 5, 74, 231, 203, 35, 84, 241, 143, 161, 11, 238, 168, 150, 220, 199, 197, 40, 176, 120, 24, 25, 198, 250, 225, 235, 25, 140, 32, 110, 32, 11, 103, 244, 196, 171, 249, 227, 108, 87, 189, 94, 52, 92, 58, 79, 128, 169, 219, 180, 118, 180, 153, 232, 208, 144, 0, 5, 212, 7, 192, 23, 103>> gcm_cipher_text = <<245, 158, 4, 12, 107, 145, 151, 47, 60, 82, 27, 59, 240, 144, 130, 104, 75, 64, 179, 145, 11, 89, 130, 71, 188, 137, 237, 74, 85, 90, 73, 161, 141, 222, 114, 166, 237, 131, 108, 12, 222, 82, 132, 7, 152, 42, 81, 37, 183, 62, 208, 42, 184, 124, 230, 10, 12, 131, 73, 76, 18, 61, 3, 18>> gcm_cipher_tag = <<35, 252, 154, 36, 245, 70, 214, 141, 72, 99, 106, 35, 226, 195, 77, 212>> assert cbc_cipher_text == JOSE.JWA.block_encrypt({:aes_cbc, 192}, key, cbc_iv, padded_plain_text) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_cbc, 192}, key, cbc_iv, cbc_cipher_text)) assert ecb_cipher_text == JOSE.JWA.block_encrypt({:aes_ecb, 192}, key, padded_plain_text) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_ecb, 192}, key, ecb_cipher_text)) assert {gcm_cipher_text, gcm_cipher_tag} == JOSE.JWA.block_encrypt({:aes_gcm, 192}, key, gcm_iv, {aad, padded_plain_text}) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_gcm, 192}, key, gcm_iv, {aad, gcm_cipher_text, gcm_cipher_tag})) end test "JOSE.JWA 256-bit encrypt and decrypt" do key = <<0::256>> cbc_iv = <<0::128>> gcm_iv = <<0::96>> aad = <<>> plain_text = "my plain text that will be encrypted and decrypted" padded_plain_text = :jose_jwa_pkcs7.pad(plain_text) cbc_cipher_text = <<203, 134, 178, 199, 240, 85, 211, 255, 152, 87, 193, 89, 160, 129, 80, 189, 223, 27, 211, 79, 247, 100, 28, 81, 198, 122, 151, 141, 179, 241, 149, 10, 252, 151, 150, 73, 95, 129, 227, 179, 158, 239, 118, 253, 99, 84, 37, 102, 255, 147, 113, 55, 174, 214, 3, 204, 67, 163, 185, 56, 180, 124, 27, 211>> ecb_cipher_text = <<203, 134, 178, 199, 240, 85, 211, 255, 152, 87, 193, 89, 160, 129, 80, 189, 59, 31, 176, 85, 123, 202, 110, 75, 65, 52, 218, 70, 130, 255, 90, 56, 44, 137, 185, 81, 14, 5, 40, 131, 196, 105, 44, 121, 10, 106, 53, 147, 77, 203, 1, 167, 110, 119, 19, 238, 140, 17, 112, 102, 230, 171, 149, 48>> gcm_cipher_text = <<163, 222, 96, 77, 33, 1, 2, 0, 39, 58, 160, 171, 206, 211, 233, 112, 19, 20, 35, 189, 94, 202, 70, 84, 179, 199, 213, 235, 27, 101, 71, 247, 173, 62, 212, 76, 109, 43, 143, 31, 97, 140, 60, 71, 53, 117, 70, 131, 34, 37, 197, 239, 143, 181, 113, 62, 111, 114, 19, 237, 165, 2, 52, 17>> gcm_cipher_tag = <<62, 158, 38, 76, 169, 81, 223, 217, 172, 83, 155, 21, 226, 51, 65, 230>> assert cbc_cipher_text == JOSE.JWA.block_encrypt({:aes_cbc, 256}, key, cbc_iv, padded_plain_text) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_cbc, 256}, key, cbc_iv, cbc_cipher_text)) assert ecb_cipher_text == JOSE.JWA.block_encrypt({:aes_ecb, 256}, key, padded_plain_text) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_ecb, 256}, key, ecb_cipher_text)) assert {gcm_cipher_text, gcm_cipher_tag} == JOSE.JWA.block_encrypt({:aes_gcm, 256}, key, gcm_iv, {aad, padded_plain_text}) assert plain_text == :jose_jwa_pkcs7.unpad(JOSE.JWA.block_decrypt({:aes_gcm, 256}, key, gcm_iv, {aad, gcm_cipher_text, gcm_cipher_tag})) end test "JOSE.JWE decode and encode" do map = %{"alg" => "dir", "enc" => "A128GCM"} binary = JOSE.encode(map) jwe = JOSE.JWE.from_map(map) assert map == :erlang.element(2, JOSE.JWE.to_map(jwe)) assert binary == :erlang.element(2, JOSE.JWE.to_binary(jwe)) assert jwe == JOSE.JWE.from_binary(binary) assert jwe == JOSE.JWE.from(jwe) # # jiffy # JOSE.json_module(:jiffy) # assert :jose_json_jiffy == JOSE.json_module() # assert map == :erlang.element(2, JOSE.JWE.to_map(jwe)) # assert binary == :erlang.element(2, JOSE.JWE.to_binary(jwe)) # assert jwe == JOSE.JWE.from_binary(binary) # assert jwe == JOSE.JWE.from(jwe) # jsone JOSE.json_module(:jsone) assert :jose_json_jsone == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWE.to_map(jwe)) assert binary == :erlang.element(2, JOSE.JWE.to_binary(jwe)) assert jwe == JOSE.JWE.from_binary(binary) assert jwe == JOSE.JWE.from(jwe) # jsx JOSE.json_module(:jsx) assert :jose_json_jsx == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWE.to_map(jwe)) assert binary == :erlang.element(2, JOSE.JWE.to_binary(jwe)) assert jwe == JOSE.JWE.from_binary(binary) assert jwe == JOSE.JWE.from(jwe) # ojson JOSE.json_module(:ojson) assert :jose_json_ojson == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWE.to_map(jwe)) assert binary == :erlang.element(2, JOSE.JWE.to_binary(jwe)) assert jwe == JOSE.JWE.from_binary(binary) assert jwe == JOSE.JWE.from(jwe) # Poison JOSE.json_module(Poison) assert :lists.member(JOSE.json_module(), [ :jose_json_poison, :jose_json_poison_compat_encoder, :jose_json_poison_lexical_encoder ]) assert map == :erlang.element(2, JOSE.JWE.to_map(jwe)) assert binary == :erlang.element(2, JOSE.JWE.to_binary(jwe)) assert jwe == JOSE.JWE.from_binary(binary) assert jwe == JOSE.JWE.from(jwe) # Jason JOSE.json_module(Jason) assert :jose_json_jason == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWE.to_map(jwe)) assert binary == :erlang.element(2, JOSE.JWE.to_binary(jwe)) assert jwe == JOSE.JWE.from_binary(binary) assert jwe == JOSE.JWE.from(jwe) end test "JOSE.JWK decode and encode" do map = %{ "crv" => "P-256", "d" => "aJhYDBNS-5yrH97PAExzWNLlJGqJwFGZmv7iJvdG4p0", "kty" => "EC", "x" => "LksdLpZN3ijcn_TBfRK-_tgmvws0c5_V5k0bg14RLhU", "y" => "ukc-JOEAWhW664SY5Q29xHlAVEDlrQwYF3-vQ_cdi1s" } password = "password" binary = JOSE.encode(map) jwk = JOSE.JWK.from_map(map) assert map == :erlang.element(2, JOSE.JWK.to_map(jwk)) assert binary == :erlang.element(2, JOSE.JWK.to_binary(jwk)) assert jwk == JOSE.JWK.from_binary(binary) assert jwk == JOSE.JWK.from(jwk) assert jwk == JOSE.JWK.from_pem(JOSE.JWK.to_pem(jwk)) assert jwk == :erlang.element(2, JOSE.JWK.from_binary(password, JOSE.JWK.to_binary(password, jwk))) assert jwk == :erlang.element(2, JOSE.JWK.from_map(password, JOSE.JWK.to_map(password, jwk))) assert jwk == JOSE.JWK.from_pem(password, JOSE.JWK.to_pem(password, jwk)) # # jiffy # JOSE.json_module(:jiffy) # assert :jose_json_jiffy == JOSE.json_module() # assert map == :erlang.element(2, JOSE.JWK.to_map(jwk)) # assert binary == :erlang.element(2, JOSE.JWK.to_binary(jwk)) # assert jwk == JOSE.JWK.from_binary(binary) # assert jwk == JOSE.JWK.from(jwk) # assert jwk == JOSE.JWK.from_pem(JOSE.JWK.to_pem(jwk)) # assert jwk == :erlang.element(2, JOSE.JWK.from_binary(password, JOSE.JWK.to_binary(password, jwk))) # assert jwk == :erlang.element(2, JOSE.JWK.from_map(password, JOSE.JWK.to_map(password, jwk))) # assert jwk == JOSE.JWK.from_pem(password, JOSE.JWK.to_pem(password, jwk)) # jsone JOSE.json_module(:jsone) assert :jose_json_jsone == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWK.to_map(jwk)) assert binary == :erlang.element(2, JOSE.JWK.to_binary(jwk)) assert jwk == JOSE.JWK.from_binary(binary) assert jwk == JOSE.JWK.from(jwk) assert jwk == JOSE.JWK.from_pem(JOSE.JWK.to_pem(jwk)) assert jwk == :erlang.element(2, JOSE.JWK.from_binary(password, JOSE.JWK.to_binary(password, jwk))) assert jwk == :erlang.element(2, JOSE.JWK.from_map(password, JOSE.JWK.to_map(password, jwk))) assert jwk == JOSE.JWK.from_pem(password, JOSE.JWK.to_pem(password, jwk)) # jsx JOSE.json_module(:jsx) assert :jose_json_jsx == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWK.to_map(jwk)) assert binary == :erlang.element(2, JOSE.JWK.to_binary(jwk)) assert jwk == JOSE.JWK.from_binary(binary) assert jwk == JOSE.JWK.from(jwk) assert jwk == JOSE.JWK.from_pem(JOSE.JWK.to_pem(jwk)) assert jwk == :erlang.element(2, JOSE.JWK.from_binary(password, JOSE.JWK.to_binary(password, jwk))) assert jwk == :erlang.element(2, JOSE.JWK.from_map(password, JOSE.JWK.to_map(password, jwk))) assert jwk == JOSE.JWK.from_pem(password, JOSE.JWK.to_pem(password, jwk)) # ojson JOSE.json_module(:ojson) assert :jose_json_ojson == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWK.to_map(jwk)) assert binary == :erlang.element(2, JOSE.JWK.to_binary(jwk)) assert jwk == JOSE.JWK.from_binary(binary) assert jwk == JOSE.JWK.from(jwk) assert jwk == JOSE.JWK.from_pem(JOSE.JWK.to_pem(jwk)) assert jwk == :erlang.element(2, JOSE.JWK.from_binary(password, JOSE.JWK.to_binary(password, jwk))) assert jwk == :erlang.element(2, JOSE.JWK.from_map(password, JOSE.JWK.to_map(password, jwk))) assert jwk == JOSE.JWK.from_pem(password, JOSE.JWK.to_pem(password, jwk)) # Poison JOSE.json_module(Poison) assert :lists.member(JOSE.json_module(), [ :jose_json_poison, :jose_json_poison_compat_encoder, :jose_json_poison_lexical_encoder ]) assert map == :erlang.element(2, JOSE.JWK.to_map(jwk)) assert binary == :erlang.element(2, JOSE.JWK.to_binary(jwk)) assert jwk == JOSE.JWK.from_binary(binary) assert jwk == JOSE.JWK.from(jwk) assert jwk == JOSE.JWK.from_pem(JOSE.JWK.to_pem(jwk)) assert jwk == :erlang.element(2, JOSE.JWK.from_binary(password, JOSE.JWK.to_binary(password, jwk))) assert jwk == :erlang.element(2, JOSE.JWK.from_map(password, JOSE.JWK.to_map(password, jwk))) assert jwk == JOSE.JWK.from_pem(password, JOSE.JWK.to_pem(password, jwk)) # Jason JOSE.json_module(Jason) assert :jose_json_jason == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWK.to_map(jwk)) assert binary == :erlang.element(2, JOSE.JWK.to_binary(jwk)) assert jwk == JOSE.JWK.from_binary(binary) assert jwk == JOSE.JWK.from(jwk) assert jwk == JOSE.JWK.from_pem(JOSE.JWK.to_pem(jwk)) assert jwk == :erlang.element(2, JOSE.JWK.from_binary(password, JOSE.JWK.to_binary(password, jwk))) assert jwk == :erlang.element(2, JOSE.JWK.from_map(password, JOSE.JWK.to_map(password, jwk))) assert jwk == JOSE.JWK.from_pem(password, JOSE.JWK.to_pem(password, jwk)) end test "JOSE.JWS decode and encode" do map = %{"alg" => "HS256"} binary = JOSE.encode(map) jws = JOSE.JWS.from_map(map) assert map == :erlang.element(2, JOSE.JWS.to_map(jws)) assert binary == :erlang.element(2, JOSE.JWS.to_binary(jws)) assert jws == JOSE.JWS.from_binary(binary) assert jws == JOSE.JWS.from(jws) # # jiffy # JOSE.json_module(:jiffy) # assert :jose_json_jiffy == JOSE.json_module() # assert map == :erlang.element(2, JOSE.JWS.to_map(jws)) # assert binary == :erlang.element(2, JOSE.JWS.to_binary(jws)) # assert jws == JOSE.JWS.from_binary(binary) # assert jws == JOSE.JWS.from(jws) # jsone JOSE.json_module(:jsone) assert :jose_json_jsone == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWS.to_map(jws)) assert binary == :erlang.element(2, JOSE.JWS.to_binary(jws)) assert jws == JOSE.JWS.from_binary(binary) assert jws == JOSE.JWS.from(jws) # jsx JOSE.json_module(:jsx) assert :jose_json_jsx == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWS.to_map(jws)) assert binary == :erlang.element(2, JOSE.JWS.to_binary(jws)) assert jws == JOSE.JWS.from_binary(binary) assert jws == JOSE.JWS.from(jws) # ojson JOSE.json_module(:ojson) assert :jose_json_ojson == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWS.to_map(jws)) assert binary == :erlang.element(2, JOSE.JWS.to_binary(jws)) assert jws == JOSE.JWS.from_binary(binary) assert jws == JOSE.JWS.from(jws) # Poison JOSE.json_module(Poison) assert :lists.member(JOSE.json_module(), [ :jose_json_poison, :jose_json_poison_compat_encoder, :jose_json_poison_lexical_encoder ]) assert map == :erlang.element(2, JOSE.JWS.to_map(jws)) assert binary == :erlang.element(2, JOSE.JWS.to_binary(jws)) assert jws == JOSE.JWS.from_binary(binary) assert jws == JOSE.JWS.from(jws) # Jason JOSE.json_module(Jason) assert :jose_json_jason == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWS.to_map(jws)) assert binary == :erlang.element(2, JOSE.JWS.to_binary(jws)) assert jws == JOSE.JWS.from_binary(binary) assert jws == JOSE.JWS.from(jws) end test "JOSE.JWT decode and encode" do map = %{"test" => true} binary = JOSE.encode(map) jwt = JOSE.JWT.from_map(map) assert map == :erlang.element(2, JOSE.JWT.to_map(jwt)) assert binary == :erlang.element(2, JOSE.JWT.to_binary(jwt)) assert jwt == JOSE.JWT.from_binary(binary) assert jwt == JOSE.JWT.from(jwt) # # jiffy # JOSE.json_module(:jiffy) # assert :jose_json_jiffy == JOSE.json_module() # assert map == :erlang.element(2, JOSE.JWT.to_map(jwt)) # assert binary == :erlang.element(2, JOSE.JWT.to_binary(jwt)) # assert jwt == JOSE.JWT.from_binary(binary) # assert jwt == JOSE.JWT.from(jwt) # jsone JOSE.json_module(:jsone) assert :jose_json_jsone == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWT.to_map(jwt)) assert binary == :erlang.element(2, JOSE.JWT.to_binary(jwt)) assert jwt == JOSE.JWT.from_binary(binary) assert jwt == JOSE.JWT.from(jwt) # jsx JOSE.json_module(:jsx) assert :jose_json_jsx == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWT.to_map(jwt)) assert binary == :erlang.element(2, JOSE.JWT.to_binary(jwt)) assert jwt == JOSE.JWT.from_binary(binary) assert jwt == JOSE.JWT.from(jwt) # ojson JOSE.json_module(:ojson) assert :jose_json_ojson == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWT.to_map(jwt)) assert binary == :erlang.element(2, JOSE.JWT.to_binary(jwt)) assert jwt == JOSE.JWT.from_binary(binary) assert jwt == JOSE.JWT.from(jwt) # Poison JOSE.json_module(Poison) assert :lists.member(JOSE.json_module(), [ :jose_json_poison, :jose_json_poison_compat_encoder, :jose_json_poison_lexical_encoder ]) assert map == :erlang.element(2, JOSE.JWT.to_map(jwt)) assert binary == :erlang.element(2, JOSE.JWT.to_binary(jwt)) assert jwt == JOSE.JWT.from_binary(binary) assert jwt == JOSE.JWT.from(jwt) # Jason JOSE.json_module(Jason) assert :jose_json_jason == JOSE.json_module() assert map == :erlang.element(2, JOSE.JWT.to_map(jwt)) assert binary == :erlang.element(2, JOSE.JWT.to_binary(jwt)) assert jwt == JOSE.JWT.from_binary(binary) assert jwt == JOSE.JWT.from(jwt) end test "unsecured signing/verifying" do JOSE.unsecured_signing(true) jwk = JOSE.JWK.generate_key(16) jws = %{"alg" => "HS256"} jws_unsecure = %{"alg" => "none"} jwt = JOSE.JWT.from_map(%{"test" => true}) {_, token} = JOSE.JWS.compact(JOSE.JWT.sign(jwk, jws, jwt)) {_, token_unsecure} = JOSE.JWS.compact(JOSE.JWT.sign(jwk, jws_unsecure, jwt)) assert :erlang.element(1, JOSE.JWT.verify(jwk, token)) == true assert :erlang.element(1, JOSE.JWT.verify(jwk, token_unsecure)) == true JOSE.unsecured_signing(false) assert :erlang.element(1, JOSE.JWT.verify(jwk, token)) == true assert :erlang.element(1, JOSE.JWT.verify(jwk, token_unsecure)) == false end test "verify strict" do JOSE.unsecured_signing(true) jwk = JOSE.JWK.generate_key(16) jws = %{"alg" => "HS256"} jws_unsecure = %{"alg" => "none"} jwt = JOSE.JWT.from_map(%{"test" => true}) {_, token} = JOSE.JWS.compact(JOSE.JWT.sign(jwk, jws, jwt)) {_, token_unsecure} = JOSE.JWS.compact(JOSE.JWT.sign(jwk, jws_unsecure, jwt)) assert :erlang.element(1, JOSE.JWT.verify_strict(jwk, ["HS256"], token)) == true assert :erlang.element(1, JOSE.JWT.verify_strict(jwk, ["HS256"], token_unsecure)) == false JOSE.unsecured_signing(false) assert :erlang.element(1, JOSE.JWT.verify_strict(jwk, ["HS256"], token)) == true assert :erlang.element(1, JOSE.JWT.verify_strict(jwk, ["HS256"], token_unsecure)) == false end test "JSON test vectors" do vectors = [ {%{}, "{}"}, {[], "[]"}, {"", "\"\""}, {1, "1"}, {[1, 2, 3], "[1,2,3]"}, {%{"c" => 3, "b" => 2, "a" => [1, 2, 3]}, "{\"a\":[1,2,3],\"b\":2,\"c\":3}"}, {%{"a" => %{"z" => 1, "y" => 2, "x" => 3}, "b" => 4}, "{\"a\":{\"x\":3,\"y\":2,\"z\":1},\"b\":4}"}, {true, "true"}, {false, "false"} ] for {term, json} <- vectors do # assert :jose_json_jiffy.encode(term) == json # assert :jose_json_jiffy.decode(json) == term assert :jose_json_jsone.encode(term) == json assert :jose_json_jsone.decode(json) == term assert :jose_json_jsx.encode(term) == json assert :jose_json_jsx.decode(json) == term assert :jose_json_poison_compat_encoder.encode(term) == json assert :jose_json_poison_compat_encoder.decode(json) == term assert :jose_json_poison_lexical_encoder.encode(term) == json assert :jose_json_poison_lexical_encoder.decode(json) == term assert :jose_json_jason.encode(term) == json assert :jose_json_jason.decode(json) == term end end # See https://github.com/ueberauth/guardian/issues/152#issuecomment-221270029 test "sign and verify with incompatible key types is not allowed" do jwk_oct16 = JOSE.JWK.generate_key({:oct, 16}) jwk_ec256 = JOSE.JWK.generate_key({:ec, "P-256"}) jwk_ec521 = JOSE.JWK.generate_key({:ec, "P-521"}) jws_hs256 = JOSE.JWS.from(%{"alg" => "HS256"}) jws_es256 = JOSE.JWS.from(%{"alg" => "ES256"}) jwt = JOSE.JWT.from(%{"test" => true}) assert_raise ErlangError, "Erlang error: {:not_supported, [:ES256]}", fn -> JOSE.JWT.sign(jwk_oct16, jws_es256, jwt) end assert_raise ErlangError, "Erlang error: {:not_supported, [\"P-256\", :HS256]}", fn -> JOSE.JWT.sign(jwk_ec256, jws_hs256, jwt) end assert_raise ErlangError, "Erlang error: {:not_supported, [\"P-521\", :ES256]}", fn -> JOSE.JWT.sign(jwk_ec521, jws_es256, jwt) end signed_hs256 = JOSE.JWT.sign(jwk_oct16, jws_hs256, jwt) |> JOSE.JWS.compact() |> elem(1) signed_es256 = JOSE.JWT.sign(jwk_ec256, jws_es256, jwt) |> JOSE.JWS.compact() |> elem(1) assert(JOSE.JWT.verify_strict(jwk_oct16, ["HS256"], signed_hs256) |> elem(0)) assert(JOSE.JWT.verify_strict(jwk_ec256, ["ES256"], signed_es256) |> elem(0)) refute(JOSE.JWT.verify_strict(jwk_ec256, ["HS256"], signed_hs256) |> elem(0)) refute(JOSE.JWT.verify_strict(jwk_oct16, ["ES256"], signed_es256) |> elem(0)) refute(JOSE.JWT.verify(jwk_ec256, signed_hs256) |> elem(0)) refute(JOSE.JWT.verify(jwk_oct16, signed_es256) |> elem(0)) {kty_module, kty} = jwk_oct16.kty bad_signed_input = JOSE.JWS.signing_input(JOSE.JWT.to_binary(jwt) |> elem(1), jws_es256) bad_signature = kty_module.sign(bad_signed_input, :HS256, kty) |> :jose_base64url.encode() bad_signed_hs256 = bad_signed_input <> "." <> bad_signature refute(JOSE.JWT.verify_strict(jwk_oct16, ["HS256"], bad_signed_hs256) |> elem(0)) refute(JOSE.JWT.verify_strict(jwk_ec256, ["ES256"], bad_signed_hs256) |> elem(0)) refute(JOSE.JWT.verify(jwk_oct16, bad_signed_hs256) |> elem(0)) refute(JOSE.JWT.verify(jwk_ec256, bad_signed_hs256) |> elem(0)) end # See https://github.com/potatosalad/erlang-jose/issues/22 test "handles invalid signed data without raising exception" do jwk = %{ "kty" => "oct", "k" => :jose_base64url.encode("symmetric key") } assert({:error, _} = JOSE.JWT.verify(jwk, "invalid")) assert({:error, _} = JOSE.JWT.verify_strict(jwk, [], "invalid")) end # See https://github.com/potatosalad/erlang-jose/issues/23 test "handles nil signed data" do jwk = %{ "kty" => "oct", "k" => :jose_base64url.encode("symmetric key") } assert({:error, _} = JOSE.JWT.verify(jwk, nil)) assert({:error, _} = JOSE.JWT.verify_strict(jwk, [], nil)) end end erlang-jose-1.10.1/test/cavp_SUITE_data/0000755000232200023220000000000013605433351020223 5ustar debalancedebalanceerlang-jose-1.10.1/test/cavp_SUITE_data/hex.erl0000644000232200023220000000314413605433351021515 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 12 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(hex). %% API -export([bin_to_hex/1]). -export([hex_to_bin/1]). -define(HEX_TO_INT(C), case C of $0 -> 16#0; $1 -> 16#1; $2 -> 16#2; $3 -> 16#3; $4 -> 16#4; $5 -> 16#5; $6 -> 16#6; $7 -> 16#7; $8 -> 16#8; $9 -> 16#9; $a -> 16#A; $b -> 16#B; $c -> 16#C; $d -> 16#D; $e -> 16#E; $f -> 16#F; $A -> 16#A; $B -> 16#B; $C -> 16#C; $D -> 16#D; $E -> 16#E; $F -> 16#F end). -define(INT_TO_HEX(C), case C of 16#0 -> $0; 16#1 -> $1; 16#2 -> $2; 16#3 -> $3; 16#4 -> $4; 16#5 -> $5; 16#6 -> $6; 16#7 -> $7; 16#8 -> $8; 16#9 -> $9; 16#A -> $a; 16#B -> $b; 16#C -> $c; 16#D -> $d; 16#E -> $e; 16#F -> $f end). %%==================================================================== %% API functions %%==================================================================== bin_to_hex(Bin) -> << << (?INT_TO_HEX(V bsr 4)), (?INT_TO_HEX(V band 16#F)) >> || << V >> <= Bin >>. hex_to_bin(Hex) -> << << ((?HEX_TO_INT(X) bsl 4) + ?HEX_TO_INT(Y)) >> || << X, Y >> <= Hex >>. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/test/cavp_SUITE_data/fetch.erl0000644000232200023220000000434213605433351022023 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc Based on core_http_get.erl %%% See [https://github.com/ninenines/erlang.mk/blob/0eb54a71605a955df14c5df793ebe676c86259f9/core/core.mk] %%% @end %%% Created : 13 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(fetch). %% API -export([fetch/2]). %%==================================================================== %% API functions %%==================================================================== fetch(URL = "ftp" ++ _, OutputFile) -> ssl:start(), inets:start(), << "ftp://", HostPath/binary >> = list_to_binary(URL), [Host | Paths] = binary:split(HostPath, << $/ >>, [global]), [File | RevPath] = lists:reverse(Paths), Path = lists:reverse(RevPath), HostString = binary_to_list(Host), FileString = binary_to_list(File), PathString = lists:flatten([[binary_to_list(P), $/] || P <- Path]), case ftp:open(HostString) of {ok, Pid} -> case ftp:user(Pid, "anonymous", "") of ok -> case ftp:type(Pid, binary) of ok -> case ftp:cd(Pid, PathString) of ok -> case ftp:recv_bin(Pid, FileString) of {ok, Body} -> _ = (catch ftp:close(Pid)), file:write_file(OutputFile, Body); RecvError -> _ = (catch ftp:close(Pid)), RecvError end; CdError -> _ = (catch ftp:close(Pid)), CdError end; TypeError -> _ = (catch ftp:close(Pid)), TypeError end; UserError -> _ = (catch ftp:close(Pid)), UserError end; OpenError -> OpenError end; fetch(URL = "http" ++ _, File) -> ssl:start(), inets:start(), case httpc:request(get, {URL, []}, [{autoredirect, true}], []) of {ok, {{_, 200, _}, _, Body}} -> file:write_file(File, Body); Error -> Error end. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/test/cavp_SUITE_data/fips_testvector.erl0000644000232200023220000001375113605433351024161 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 12 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(fips_testvector). %% API -export([from_binary/1]). -export([from_file/1]). -export([to_binary/1]). -export([to_file/2]). %%==================================================================== %% API functions %%==================================================================== from_binary(Binary) -> Lines = binary:split(Binary, [<< $\n >>, << $\r >>], [global, trim]), parse_lines(Lines, []). from_file(File) -> case file:read_file(File) of {ok, Binary} -> from_binary(Binary); ReadError -> ReadError end. to_binary(Vectors) when is_list(Vectors) -> << << (case Vector of {flag, Flag} -> << $[, Flag/binary, $], $\n >>; {option, {Key, Val}} -> << $[, Key/binary, $\s, $=, $\s, Val/binary, $], $\n >>; {token, Token} -> << Token/binary, $\n >>; {vector, {Key, Val}, hex} -> << Key/binary, $\s, $=, $\s, (hex:bin_to_hex(Val))/binary, $\n >>; {vector, {Key, Val}, int} -> << Key/binary, $\s, $=, $\s, (integer_to_binary(Val))/binary, $\n >>; {vector, {Key, Val}, raw} -> << Key/binary, $\s, $=, $\s, Val/binary, $\n >> end)/binary >> || Vector <- Vectors >>. to_file(File, State={_, _, _}) -> Binary = to_binary(State), file:write_file(File, Binary). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private parse_lines([], Acc) -> lists:reverse(Acc); parse_lines([Line | Lines], Acc) -> case parse_line(Line) of skip -> parse_lines(Lines, Acc); Term -> parse_lines(Lines, [Term | Acc]) end. %% @private parse_line(<< $#, _/binary >>) -> skip; parse_line(<< $\s, Rest/binary >>) -> parse_line(Rest); parse_line(<< $\t, Rest/binary >>) -> parse_line(Rest); parse_line(<< $[, Rest/binary >>) -> parse_option(Rest); parse_line(<<>>) -> skip; parse_line(Rest) -> parse_vector(Rest). %% @private parse_option(Rest) -> case binary:match(Rest, << $] >>) of {OptionEndPos, 1} -> case binary:match(Rest, << $= >>) of {EqualPos, 1} when EqualPos < OptionEndPos -> Key = parse_option_key(binary:part(Rest, 0, EqualPos), <<>>), Val = parse_option_val(binary:part(Rest, EqualPos + 1, OptionEndPos - EqualPos - 1), <<>>), {option, {Key, Val}}; _ -> Flag = binary:part(Rest, 0, OptionEndPos), {flag, Flag} end; _ -> erlang:error({badarg, [Rest]}) end. %% @private parse_option_key(<< $\s, Rest/binary >>, Key) -> parse_option_key(Rest, Key); parse_option_key(<< $\t, Rest/binary >>, Key) -> parse_option_key(Rest, Key); parse_option_key(<< C, Rest/binary >>, Key) -> parse_option_key(Rest, << Key/binary, C >>); parse_option_key(<<>>, Key) -> Key. %% @private parse_option_val(<< $\s, Rest/binary >>, Val) -> parse_option_val(Rest, Val); parse_option_val(<< $\t, Rest/binary >>, Val) -> parse_option_val(Rest, Val); parse_option_val(<< C, Rest/binary >>, Val) -> parse_option_val(Rest, << Val/binary, C >>); parse_option_val(<<>>, Val) -> Val. %% @private parse_vector(<< C, Rest/binary >>) when (C >= $A andalso C =< $Z) orelse (C >= $a andalso C =< $z) orelse (C >= $0 andalso C =< $9) -> parse_vector_key(Rest, << C >>); parse_vector(Rest) -> erlang:error({badarg, [Rest]}). %% @private parse_vector_key(<< $=, Rest/binary >>, Key) -> parse_vector_val(Rest, Key, <<>>, true); parse_vector_key(<< $\s, Rest/binary >>, Key) -> parse_vector_key(Rest, Key); parse_vector_key(<< $\t, Rest/binary >>, Key) -> parse_vector_key(Rest, Key); parse_vector_key(<< C, Rest/binary >>, Key) when (C >= $A andalso C =< $Z) orelse (C >= $a andalso C =< $z) orelse (C >= $0 andalso C =< $9) -> parse_vector_key(Rest, << Key/binary, C >>); parse_vector_key(<<>>, Key) -> {token, Key}; parse_vector_key(Rest, Key) -> erlang:error({badarg, [Rest, Key]}). %% @private parse_vector_val(<< $#, _/binary >>, Key = << C, O, U, N, T >>, Bin, true) when (C =:= $C orelse C =:= $c) andalso (O =:= $O orelse O =:= $o) andalso (U =:= $U orelse U =:= $u) andalso (N =:= $N orelse N =:= $n) andalso (T =:= $T orelse T =:= $t) -> Val = binary_to_integer(Bin), {vector, {Key, Val}, int}; parse_vector_val(<< $#, _/binary >>, Key, Hex, true) -> Val = hex:hex_to_bin(Hex), {vector, {Key, Val}, hex}; parse_vector_val(<< $#, _/binary >>, Key, Val, false) -> {vector, {Key, Val}, raw}; parse_vector_val(<< $\s, Rest/binary >>, Key, Val, true) -> parse_vector_val(Rest, Key, Val, true); parse_vector_val(<< $\t, Rest/binary >>, Key, Val, true) -> parse_vector_val(Rest, Key, Val, true); parse_vector_val(<< C, Rest/binary >>, Key, Val, true) when (C >= $A andalso C =< $F) orelse (C >= $a andalso C =< $f) orelse (C >= $0 andalso C =< $9) -> parse_vector_val(Rest, Key, << Val/binary, C >>, true); parse_vector_val(<< C, Rest/binary >>, Key, Val, _Hex) -> parse_vector_val(Rest, Key, << Val/binary, C >>, false); parse_vector_val(<<>>, Key = << C, O, U, N, T >>, Bin, true) when (C =:= $C orelse C =:= $c) andalso (O =:= $O orelse O =:= $o) andalso (U =:= $U orelse U =:= $u) andalso (N =:= $N orelse N =:= $n) andalso (T =:= $T orelse T =:= $t) -> Val = binary_to_integer(Bin), {vector, {Key, Val}, int}; parse_vector_val(<<>>, Key = << L, E, N >>, Bin, true) when (L =:= $L orelse L =:= $l) andalso (E =:= $E orelse E =:= $e) andalso (N =:= $N orelse N =:= $n) -> Val = binary_to_integer(Bin), {vector, {Key, Val}, int}; parse_vector_val(<<>>, Key, Hex, true) -> Val = hex:hex_to_bin(Hex), {vector, {Key, Val}, hex}; parse_vector_val(<<>>, Key, Val, false) -> {vector, {Key, Val}, raw}; parse_vector_val(Rest, Key, Val, Hex) -> erlang:error({badarg, [Rest, Key, Val, Hex]}). erlang-jose-1.10.1/test/cavp_SUITE_data/emc_testvector.erl0000644000232200023220000001144413605433351023761 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc %%% %%% @end %%% Created : 12 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(emc_testvector). %% API -export([from_binary/1]). -export([from_file/1]). -export([to_binary/1]). -export([to_file/2]). %%==================================================================== %% API functions %%==================================================================== from_binary(Binary) -> Lines = [Line || Line <- binary:split(Binary, [<< $\n >>, << $\r >>], [global, trim]), Line =/= <<>>], parse_lines(Lines, []). from_file(File) -> case file:read_file(File) of {ok, Binary} -> from_binary(Binary); ReadError -> ReadError end. to_binary(Vectors) when is_list(Vectors) -> << << (case Vector of divider -> << $\n, "# =============================================\n", $\n >>; {example, Example} -> ExampleLen = byte_size(Example), Bar = binary:copy(<<"=">>, ExampleLen), << $\n, "# ", Bar/binary, $\n, "# ", Example/binary, $\n, "# ", Bar/binary, $\n, $\n >>; {component, Component} -> ComponentLen = byte_size(Component), Bar = binary:copy(<<"-">>, ComponentLen), << $\n, "# ", Bar/binary, $\n, "# ", Component/binary, $\n, "# ", Bar/binary, $\n, $\n >>; {vector, {Key, Val}} -> Hex = hex:bin_to_hex(Val), HexLines = to_hex_lines(Hex, <<>>, []), HexBlocks = << << HexLine/binary, $\n >> || HexLine <- HexLines >>, << "# ", Key/binary, $:, $\n, HexBlocks/binary, $\n >> end)/binary >> || Vector <- Vectors >>. to_file(File, State={_, _, _}) -> Binary = to_binary(State), file:write_file(File, Binary). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private parse_lines([], Acc) -> lists:reverse(Acc); parse_lines([ << "# =======", _/binary >>, << "# Example", Example/binary >>, << "# =======", _/binary >> | Lines ], Acc) -> parse_lines(Lines, [{example, << "Example", Example/binary >>} | Acc]); parse_lines([ << "# ----", _/binary >>, << "# ", Component/binary >>, << "# ----", _/binary >> | Lines ], Acc) -> parse_lines(Lines, [{component, Component} | Acc]); parse_lines([ << " ----", _/binary >>, << "# ", Component/binary >>, << " ----", _/binary >> | Lines ], Acc) -> parse_lines(Lines, [{component, Component} | Acc]); parse_lines([<<"# =============================================">> | Lines], Acc) -> parse_lines(Lines, [divider | Acc]); parse_lines([<< "# ", Key/binary >> | Lines], Acc) when length(Acc) > 0 -> case parse_key(Key) of skip -> parse_lines(Lines, Acc); NewKey -> parse_vector(Lines, NewKey, <<>>, Acc) end; parse_lines([_Line | Lines], Acc) -> parse_lines(Lines, Acc). %% @private parse_key(Key) -> case binary:match(Key, << $: >>) of {Pos, 1} -> binary:part(Key, 0, Pos); nomatch -> skip end. %% @private parse_vector(Lines = [<< $#, _/binary >> | _], Key, Hex, Acc) -> Val = hex:hex_to_bin(Hex), parse_lines(Lines, [{vector, {Key, Val}} | Acc]); parse_vector(Lines = [<< "# ----", _/binary >> | _], Key, Hex, Acc) -> Val = hex:hex_to_bin(Hex), parse_lines(Lines, [{vector, {Key, Val}} | Acc]); parse_vector(Lines = [<< " ----", _/binary >> | _], Key, Hex, Acc) -> Val = hex:hex_to_bin(Hex), parse_lines(Lines, [{vector, {Key, Val}} | Acc]); parse_vector([HexLine | Lines], Key, Hex, Acc) -> case parse_vector_hexline(HexLine, Hex) of {ok, NewHex} -> Val = hex:hex_to_bin(NewHex), parse_lines([HexLine | Lines], [{vector, {Key, Val}} | Acc]); {next, NewHex} -> parse_vector(Lines, Key, NewHex, Acc) end. %% @private parse_vector_hexline(<< $\s, Rest/binary >>, Hex) -> parse_vector_hexline(Rest, Hex); parse_vector_hexline(<< C, Rest/binary >>, Hex) when (C >= $A andalso C =< $Z) orelse (C >= $a andalso C =< $z) orelse (C >= $0 andalso C =< $9) -> parse_vector_hexline(Rest, << Hex/binary, C >>); parse_vector_hexline(<<>>, Hex) -> {next, Hex}; parse_vector_hexline(Rest, Hex) -> erlang:error({badarg, [Rest, Hex]}). %% @private to_hex_lines(Rest, Line, Lines) when byte_size(Line) >= 48 -> to_hex_lines(Rest, <<>>, [Line | Lines]); to_hex_lines(<< A, B, Rest/binary >>, Line, Lines) -> to_hex_lines(Rest, << Line/binary, A, B, $\s >>, Lines); to_hex_lines(<<>>, <<>>, Lines) -> lists:reverse(Lines); to_hex_lines(<<>>, Line, Lines) -> lists:reverse([Line | Lines]). erlang-jose-1.10.1/test/jose_jwa_aes_SUITE.erl0000644000232200023220000006262513605433351021451 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet %%%------------------------------------------------------------------- %%% @author Andrew Bennett %%% @copyright 2014-2015, Andrew Bennett %%% @doc Advanced Encryption Standard (AES) %%% Cipher Block Chaining (CBC), as defined in NIST.800-38A %%% Electronic Codebook (ECB), as defined in NIST.800-38A %%% Galois/Counter Mode (GCM) and GMAC, as defined in NIST.800-38D %%% See NIST.800-38A: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf %%% See NIST.800-38D: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf %%% See http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf %%% See https://github.com/erlang/otp/blob/OTP-18.0/lib/crypto/test/crypto_SUITE.erl %%% @end %%% Created : 10 Aug 2015 by Andrew Bennett %%%------------------------------------------------------------------- -module(jose_jwa_aes_SUITE). -include_lib("common_test/include/ct.hrl"). -include("jose.hrl"). %% Plain Text used in NIST example vectors -define(NIST_PLAIN_TEXT, hexstr2bin( "6bc1bee22e409f96e93d7e117393172a" "ae2d8a571e03ac9c9eb76fac45af8e51" "30c81c46a35ce411e5fbc1191a0a52ef" "f69f2445df4f9b17ad2b417be66c3710")). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([aead/0]). -export([aead/1]). -export([block/0]). -export([block/1]). all() -> [ {group, aes_cbc128}, {group, aes_cbc192}, {group, aes_cbc256}, {group, aes_ecb128}, {group, aes_ecb192}, {group, aes_ecb256}, {group, aes_gcm128}, {group, aes_gcm192}, {group, aes_gcm256} ]. groups() -> [ {aes_cbc128, [], [block]}, {aes_cbc192, [], [block]}, {aes_cbc256, [], [block]}, {aes_ecb128, [], [block]}, {aes_ecb192, [], [block]}, {aes_ecb256, [], [block]}, {aes_gcm128, [], [aead]}, {aes_gcm192, [], [aead]}, {aes_gcm256, [], [aead]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), Config. end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(Group, Config) -> jose_ct:start(Group, group_config(Group, Config)). end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== aead() -> [{doc, "Test AEAD ciphers"}]. aead(Config) when is_list(Config) -> AEADs = lazy_eval(proplists:get_value(aead, Config)), lists:foreach(fun aead_cipher/1, AEADs). block() -> [{doc, "Test block ciphers"}]. block(Config) when is_list(Config) -> Blocks = proplists:get_value(block, Config), lists:foreach(fun block_cipher/1, Blocks). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag}) -> Plain = iolist_to_binary(PlainText), case jose_jwa_aes:block_encrypt(Type, Key, IV, {AAD, Plain}) of {CipherText, CipherTag} -> ok; Other0 -> ct:fail({{jose_jwa_aes, block_encrypt, [Plain, PlainText]}, {expected, {CipherText, CipherTag}}, {got, Other0}}) end, case jose_jwa_aes:block_decrypt(Type, Key, IV, {AAD, CipherText, CipherTag}) of Plain -> ok; Other1 -> ct:fail({{jose_jwa_aes, block_decrypt, [CipherText]}, {expected, Plain}, {got, Other1}}) end. %% @private block_cipher({Type, Key, PlainText}) -> Plain = iolist_to_binary(PlainText), CipherText = jose_jwa_aes:block_encrypt(Type, Key, PlainText), case jose_jwa_aes:block_decrypt(Type, Key, CipherText) of Plain -> ok; Other -> ct:fail({{jose_jwa_aes, block_decrypt, [Type, Key, CipherText]}, {expected, Plain}, {got, Other}}) end; block_cipher({Type={aes_ecb, _}, Key, PlainText, CipherText}) -> Plain = iolist_to_binary(PlainText), case jose_jwa_aes:block_encrypt(Type, Key, Plain) of CipherText -> ok; Other0 -> ct:fail({{jose_jwa_aes, block_encrypt, [Type, Key, Plain]}, {expected, CipherText}, {got, Other0}}) end, case jose_jwa_aes:block_decrypt(Type, Key, CipherText) of Plain -> ok; Other1 -> ct:fail({{jose_jwa_aes, block_decrypt, [Type, Key, CipherText]}, {expected, Plain}, {got, Other1}}) end; block_cipher({Type, Key, IV, PlainText}) -> Plain = iolist_to_binary(PlainText), CipherText = jose_jwa_aes:block_encrypt(Type, Key, IV, PlainText), case jose_jwa_aes:block_decrypt(Type, Key, IV, CipherText) of Plain -> ok; Other -> ct:fail({{jose_jwa_aes, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other}}) end; block_cipher({Type, Key, IV, PlainText, CipherText}) -> Plain = iolist_to_binary(PlainText), case jose_jwa_aes:block_encrypt(Type, Key, IV, Plain) of CipherText -> ok; Other0 -> ct:fail({{jose_jwa_aes, block_encrypt, [Plain, PlainText]}, {expected, CipherText}, {got, Other0}}) end, case jose_jwa_aes:block_decrypt(Type, Key, IV, CipherText) of Plain -> ok; Other1 -> ct:fail({{jose_jwa_aes, block_decrypt, [CipherText]}, {expected, Plain}, {got, Other1}}) end. %% @private group_config(aes_cbc128, Config) -> Block = aes_cbc128(), [{block, Block} | Config]; group_config(aes_cbc192, Config) -> Block = aes_cbc192(), [{block, Block} | Config]; group_config(aes_cbc256, Config) -> Block = aes_cbc256(), [{block, Block} | Config]; group_config(aes_ecb128, Config) -> Block = aes_ecb128(), [{block, Block} | Config]; group_config(aes_ecb192, Config) -> Block = aes_ecb192(), [{block, Block} | Config]; group_config(aes_ecb256, Config) -> Block = aes_ecb256(), [{block, Block} | Config]; group_config(aes_gcm128, Config) -> AEAD = aes_gcm128(), [{aead, AEAD} | Config]; group_config(aes_gcm192, Config) -> AEAD = aes_gcm192(), [{aead, AEAD} | Config]; group_config(aes_gcm256, Config) -> AEAD = aes_gcm256(), [{aead, AEAD} | Config]. %% @private hexstr2bin(S) -> list_to_binary(hexstr2list(S)). %% @private hexstr2list([X,Y|T]) -> [mkint(X)*16 + mkint(Y) | hexstr2list(T)]; hexstr2list([]) -> []. %% Building huge terms (like long_msg/0) in init_per_group seems to cause %% test_server crash with 'no_answer_from_tc_supervisor' sometimes on some %% machines. Therefore lazy evaluation when test case has started. lazy_eval(F) when is_function(F) -> F(); lazy_eval(Lst) when is_list(Lst) -> lists:map(fun lazy_eval/1, Lst); lazy_eval(Tpl) when is_tuple(Tpl) -> list_to_tuple(lists:map(fun lazy_eval/1, tuple_to_list(Tpl))); lazy_eval(Term) -> Term. %% @private mkint(C) when $0 =< C, C =< $9 -> C - $0; mkint(C) when $A =< C, C =< $F -> C - $A + 10; mkint(C) when $a =< C, C =< $f -> C - $a + 10. %% @private %% See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf aes_cbc128() -> [ {{aes_cbc, 128}, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), hexstr2bin("000102030405060708090a0b0c0d0e0f"), hexstr2bin("6bc1bee22e409f96e93d7e117393172a")}, {{aes_cbc, 128}, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), hexstr2bin("7649ABAC8119B246CEE98E9B12E9197D"), hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")}, {{aes_cbc, 128}, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), hexstr2bin("5086CB9B507219EE95DB113A917678B2"), hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")}, {{aes_cbc, 128}, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), hexstr2bin("73BED6B8E3C1743B7116E69E22229516"), hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}, %% F.2.1 CBC-AES128.Encrypt %% F.2.2 CBC-AES128.Decrypt {{aes_cbc, 128}, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), hexstr2bin("000102030405060708090a0b0c0d0e0f"), ?NIST_PLAIN_TEXT, hexstr2bin("7649abac8119b246cee98e9b12e9197d" "5086cb9b507219ee95db113a917678b2" "73bed6b8e3c1743b7116e69e22229516" "3ff1caa1681fac09120eca307586e1a7")} ]. %% @private %% See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf aes_cbc192() -> [ %% F.2.3 CBC-AES192.Encrypt %% F.2.4 CBC-AES192.Decrypt {{aes_cbc, 192}, hexstr2bin("8e73b0f7da0e6452c810f32b809079e5" "62f8ead2522c6b7b"), hexstr2bin("000102030405060708090a0b0c0d0e0f"), ?NIST_PLAIN_TEXT, hexstr2bin("4f021db243bc633d7178183a9fa071e8" "b4d9ada9ad7dedf4e5e738763f69145a" "571b242012fb7ae07fa9baac3df102e0" "08b0e27988598881d920a9e64f5615cd")} ]. %% @private %% See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf aes_cbc256() -> [ {{aes_cbc, 256}, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), hexstr2bin("000102030405060708090A0B0C0D0E0F"), hexstr2bin("6bc1bee22e409f96e93d7e117393172a")}, {{aes_cbc, 256}, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), hexstr2bin("F58C4C04D6E5F1BA779EABFB5F7BFBD6"), hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")}, {{aes_cbc, 256}, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), hexstr2bin("9CFC4E967EDB808D679F777BC6702C7D"), hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")}, {{aes_cbc, 256}, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), hexstr2bin("39F23369A9D9BACFA530E26304231461"), hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}, %% F.2.5 CBC-AES256.Encrypt %% F.2.6 CBC-AES256.Decrypt {{aes_cbc, 256}, hexstr2bin("603deb1015ca71be2b73aef0857d7781" "1f352c073b6108d72d9810a30914dff4"), hexstr2bin("000102030405060708090a0b0c0d0e0f"), ?NIST_PLAIN_TEXT, hexstr2bin("f58c4c04d6e5f1ba779eabfb5f7bfbd6" "9cfc4e967edb808d679f777bc6702c7d" "39f23369a9d9bacfa530e26304231461" "b2eb05e2c39be9fcda6c19078c6a9d1b")} ]. %% @private %% See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf aes_ecb128() -> [ {{aes_ecb, 128}, <<"YELLOW SUBMARINE">>, <<"YELLOW SUBMARINE">>}, {{aes_ecb, 128}, <<"0000000000000000">>, <<"0000000000000000">>}, {{aes_ecb, 128}, <<"FFFFFFFFFFFFFFFF">>, <<"FFFFFFFFFFFFFFFF">>}, {{aes_ecb, 128}, <<"3000000000000000">>, <<"1000000000000001">>}, {{aes_ecb, 128}, <<"1111111111111111">>, <<"1111111111111111">>}, {{aes_ecb, 128}, <<"0123456789ABCDEF">>, <<"1111111111111111">>}, {{aes_ecb, 128}, <<"0000000000000000">>, <<"0000000000000000">>}, {{aes_ecb, 128}, <<"FEDCBA9876543210">>, <<"0123456789ABCDEF">>}, {{aes_ecb, 128}, <<"7CA110454A1A6E57">>, <<"01A1D6D039776742">>}, {{aes_ecb, 128}, <<"0131D9619DC1376E">>, <<"5CD54CA83DEF57DA">>}, {{aes_ecb, 128}, <<"07A1133E4A0B2686">>, <<"0248D43806F67172">>}, {{aes_ecb, 128}, <<"3849674C2602319E">>, <<"51454B582DDF440A">>}, {{aes_ecb, 128}, <<"04B915BA43FEB5B6">>, <<"42FD443059577FA2">>}, {{aes_ecb, 128}, <<"0113B970FD34F2CE">>, <<"059B5E0851CF143A">>}, {{aes_ecb, 128}, <<"0170F175468FB5E6">>, <<"0756D8E0774761D2">>}, {{aes_ecb, 128}, <<"43297FAD38E373FE">>, <<"762514B829BF486A">>}, {{aes_ecb, 128}, <<"07A7137045DA2A16">>, <<"3BDD119049372802">>}, {{aes_ecb, 128}, <<"04689104C2FD3B2F">>, <<"26955F6835AF609A">>}, {{aes_ecb, 128}, <<"37D06BB516CB7546">>, <<"164D5E404F275232">>}, {{aes_ecb, 128}, <<"1F08260D1AC2465E">>, <<"6B056E18759F5CCA">>}, {{aes_ecb, 128}, <<"584023641ABA6176">>, <<"004BD6EF09176062">>}, {{aes_ecb, 128}, <<"025816164629B007">>, <<"480D39006EE762F2">>}, {{aes_ecb, 128}, <<"49793EBC79B3258F">>, <<"437540C8698F3CFA">>}, {{aes_ecb, 128}, <<"018310DC409B26D6">>, <<"1D9D5C5018F728C2">>}, {{aes_ecb, 128}, <<"1C587F1C13924FEF">>, <<"305532286D6F295A">>}, {{aes_ecb, 128}, <<"0101010101010101">>, <<"0123456789ABCDEF">>}, {{aes_ecb, 128}, <<"1F1F1F1F0E0E0E0E">>, <<"0123456789ABCDEF">>}, {{aes_ecb, 128}, <<"E0FEE0FEF1FEF1FE">>, <<"0123456789ABCDEF">>}, {{aes_ecb, 128}, <<"0000000000000000">>, <<"FFFFFFFFFFFFFFFF">>}, {{aes_ecb, 128}, <<"FFFFFFFFFFFFFFFF">>, <<"0000000000000000">>}, {{aes_ecb, 128}, <<"0123456789ABCDEF">>, <<"0000000000000000">>}, {{aes_ecb, 128}, <<"FEDCBA9876543210">>, <<"FFFFFFFFFFFFFFFF">>}, %% F.1.1 ECB-AES128.Encrypt %% F.1.2 ECB-AES128.Decrypt {{aes_ecb, 128}, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), ?NIST_PLAIN_TEXT, hexstr2bin("3ad77bb40d7a3660a89ecaf32466ef97" "f5d3d58503b9699de785895a96fdbaaf" "43b1cd7f598ece23881b00e3ed030688" "7b0c785e27e8ad3f8223207104725dd4")} ]. %% @private %% See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf aes_ecb192() -> [ %% F.1.3 ECB-AES192.Encrypt %% F.1.4 ECB-AES192.Decrypt {{aes_ecb, 192}, hexstr2bin("8e73b0f7da0e6452c810f32b809079e5" "62f8ead2522c6b7b"), ?NIST_PLAIN_TEXT, hexstr2bin("bd334f1d6e45f25ff712a214571fa5cc" "974104846d0ad3ad7734ecb3ecee4eef" "ef7afd2270e2e60adce0ba2face6444e" "9a4b41ba738d6c72fb16691603c18e0e")} ]. %% @private %% See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf aes_ecb256() -> [ %% F.1.5 ECB-AES256.Encrypt %% F.1.6 ECB-AES256.Decrypt {{aes_ecb, 256}, hexstr2bin("603deb1015ca71be2b73aef0857d7781" "1f352c073b6108d72d9810a30914dff4"), ?NIST_PLAIN_TEXT, hexstr2bin("f3eed1bdb5d2a03c064b5a7e3db181f8" "591ccb10d410ed26dc5ba74a31362870" "b6ed21b99ca6f4f9f153e7b1beafed1d" "23304b7a39f9f3ff067d8d8f9e24ecc7")} ]. %% AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf aes_gcm128() -> [ %% Test Case 1 {{aes_gcm, 128}, hexstr2bin("00000000000000000000000000000000"), %% Key hexstr2bin(""), %% PlainText hexstr2bin("000000000000000000000000"), %% IV hexstr2bin(""), %% AAD hexstr2bin(""), %% CipherText hexstr2bin("58e2fccefa7e3061367f1d57a4e7455a")}, %% CipherTag %% Test Case 2 {{aes_gcm, 128}, hexstr2bin("00000000000000000000000000000000"), %% Key hexstr2bin("00000000000000000000000000000000"), %% PlainText hexstr2bin("000000000000000000000000"), %% IV hexstr2bin(""), %% AAD hexstr2bin("0388dace60b6a392f328c2b971b2fe78"), %% CipherText hexstr2bin("ab6e47d42cec13bdf53a67b21257bddf")}, %% CipherTag %% Test Case 3 {{aes_gcm, 128}, hexstr2bin("feffe9928665731c6d6a8f9467308308"), %% Key hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b391aafd255"), hexstr2bin("cafebabefacedbaddecaf888"), %% IV hexstr2bin(""), %% AAD hexstr2bin("42831ec2217774244b7221b784d0d49c" %% CipherText "e3aa212f2c02a4e035c17e2329aca12e" "21d514b25466931c7d8f6a5aac84aa05" "1ba30b396a0aac973d58e091473f5985"), hexstr2bin("4d5c2af327cd64a62cf35abd2ba6fab4")}, %% CipherTag %% Test Case 4 {{aes_gcm, 128}, hexstr2bin("feffe9928665731c6d6a8f9467308308"), %% Key hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("cafebabefacedbaddecaf888"), %% IV hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("42831ec2217774244b7221b784d0d49c" %% CipherText "e3aa212f2c02a4e035c17e2329aca12e" "21d514b25466931c7d8f6a5aac84aa05" "1ba30b396a0aac973d58e091"), hexstr2bin("5bc94fbc3221a5db94fae95ae7121a47")}, %% CipherTag %% Test Case 5 {{aes_gcm, 128}, hexstr2bin("feffe9928665731c6d6a8f9467308308"), %% Key hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("cafebabefacedbad"), %% IV hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("61353b4c2806934a777ff51fa22a4755" %% CipherText "699b2a714fcdc6f83766e5f97b6c7423" "73806900e49f24b22b097544d4896b42" "4989b5e1ebac0f07c23f4598"), hexstr2bin("3612d2e79e3b0785561be14aaca2fccb")}, %% CipherTag %% Test Case 6 {{aes_gcm, 128}, hexstr2bin("feffe9928665731c6d6a8f9467308308"), %% Key hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("9313225df88406e555909c5aff5269aa" %% IV "6a7a9538534f7da1e4c303d2a318a728" "c3c0c95156809539fcf0e2429a6b5254" "16aedbf5a0de6a57a637b39b"), hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("8ce24998625615b603a033aca13fb894" %% CipherText "be9112a5c3a211a8ba262a3cca7e2ca7" "01e4a9a4fba43c90ccdcb281d48c7c6f" "d62875d2aca417034c34aee5"), hexstr2bin("619cc5aefffe0bfa462af43c1699d050")} %% CipherTag ]. %% AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf aes_gcm192() -> [ %% Test Case 7 {{aes_gcm, 192}, hexstr2bin("00000000000000000000000000000000" %% Key "0000000000000000"), hexstr2bin(""), %% PlainText hexstr2bin("000000000000000000000000"), %% IV hexstr2bin(""), %% AAD hexstr2bin(""), %% CipherText hexstr2bin("cd33b28ac773f74ba00ed1f312572435")}, %% CipherTag %% Test Case 8 {{aes_gcm, 192}, hexstr2bin("00000000000000000000000000000000" %% Key "0000000000000000"), hexstr2bin("00000000000000000000000000000000"), %% PlainText hexstr2bin("000000000000000000000000"), %% IV hexstr2bin(""), %% AAD hexstr2bin("98e7247c07f0fe411c267e4384b0f600"), %% CipherText hexstr2bin("2ff58d80033927ab8ef4d4587514f0fb")}, %% CipherTag %% Test Case 9 {{aes_gcm, 192}, hexstr2bin("feffe9928665731c6d6a8f9467308308" %% Key "feffe9928665731c"), hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b391aafd255"), hexstr2bin("cafebabefacedbaddecaf888"), %% IV hexstr2bin(""), %% ADD hexstr2bin("3980ca0b3c00e841eb06fac4872a2757" %% CipherText "859e1ceaa6efd984628593b40ca1e19c" "7d773d00c144c525ac619d18c84a3f47" "18e2448b2fe324d9ccda2710acade256"), hexstr2bin("9924a7c8587336bfb118024db8674a14")}, %% CipherTag %% Test Case 10 {{aes_gcm, 192}, hexstr2bin("feffe9928665731c6d6a8f9467308308" %% Key "feffe9928665731c"), hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("cafebabefacedbaddecaf888"), %% IV hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("3980ca0b3c00e841eb06fac4872a2757" %% CipherText "859e1ceaa6efd984628593b40ca1e19c" "7d773d00c144c525ac619d18c84a3f47" "18e2448b2fe324d9ccda2710"), hexstr2bin("2519498e80f1478f37ba55bd6d27618c")}, %% CipherTag %% Test Case 11 {{aes_gcm, 192}, hexstr2bin("feffe9928665731c6d6a8f9467308308" %% Key "feffe9928665731c"), hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("cafebabefacedbad"), %% IV hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("0f10f599ae14a154ed24b36e25324db8" %% CipherText "c566632ef2bbb34f8347280fc4507057" "fddc29df9a471f75c66541d4d4dad1c9" "e93a19a58e8b473fa0f062f7"), hexstr2bin("65dcc57fcf623a24094fcca40d3533f8")}, %% CipherTag %% Test Case 12 {{aes_gcm, 192}, hexstr2bin("feffe9928665731c6d6a8f9467308308" %% Key "feffe9928665731c"), hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("9313225df88406e555909c5aff5269aa" %% IV "6a7a9538534f7da1e4c303d2a318a728" "c3c0c95156809539fcf0e2429a6b5254" "16aedbf5a0de6a57a637b39b"), hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("d27e88681ce3243c4830165a8fdcf9ff" %% CipherText "1de9a1d8e6b447ef6ef7b79828666e45" "81e79012af34ddd9e2f037589b292db3" "e67c036745fa22e7e9b7373b"), hexstr2bin("dcf566ff291c25bbb8568fc3d376a6d9")} %% CipherTag ]. %% AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf aes_gcm256() -> [ %% Test Case 13 {{aes_gcm, 256}, hexstr2bin("00000000000000000000000000000000" %% Key "00000000000000000000000000000000"), hexstr2bin(""), %% PlainText hexstr2bin("000000000000000000000000"), %% IV hexstr2bin(""), %% AAD hexstr2bin(""), %% CipherText hexstr2bin("530f8afbc74536b9a963b4f1c4cb738b")}, %% CipherTag %% Test Case 14 {{aes_gcm, 256}, hexstr2bin("00000000000000000000000000000000" %% Key "00000000000000000000000000000000"), hexstr2bin("00000000000000000000000000000000"), %% PlainText hexstr2bin("000000000000000000000000"), %% IV hexstr2bin(""), %% AAD hexstr2bin("cea7403d4d606b6e074ec5d3baf39d18"), %% CipherText hexstr2bin("d0d1c8a799996bf0265b98b5d48ab919")}, %% CipherTag %% Test Case 15 {{aes_gcm, 256}, hexstr2bin("feffe9928665731c6d6a8f9467308308" %% Key "feffe9928665731c6d6a8f9467308308"), hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b391aafd255"), hexstr2bin("cafebabefacedbaddecaf888"), %% IV hexstr2bin(""), %% AAD hexstr2bin("522dc1f099567d07f47f37a32a84427d" %% CipherText "643a8cdcbfe5c0c97598a2bd2555d1aa" "8cb08e48590dbb3da7b08b1056828838" "c5f61e6393ba7a0abcc9f662898015ad"), hexstr2bin("b094dac5d93471bdec1a502270e3cc6c")}, %% CipherTag %% Test Case 16 {{aes_gcm, 256}, hexstr2bin("feffe9928665731c6d6a8f9467308308" %% Key "feffe9928665731c6d6a8f9467308308"), hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("cafebabefacedbaddecaf888"), %% IV hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("522dc1f099567d07f47f37a32a84427d" %% CipherText "643a8cdcbfe5c0c97598a2bd2555d1aa" "8cb08e48590dbb3da7b08b1056828838" "c5f61e6393ba7a0abcc9f662"), hexstr2bin("76fc6ece0f4e1768cddf8853bb2d551b")}, %% CipherTag %% Test Case 17 {{aes_gcm, 256}, hexstr2bin("feffe9928665731c6d6a8f9467308308" %% Key "feffe9928665731c6d6a8f9467308308"), hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("cafebabefacedbad"), %% IV hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("c3762df1ca787d32ae47c13bf19844cb" %% CipherText "af1ae14d0b976afac52ff7d79bba9de0" "feb582d33934a4f0954cc2363bc73f78" "62ac430e64abe499f47c9b1f"), hexstr2bin("3a337dbf46a792c45e454913fe2ea8f2")}, %% CipherTag %% Test Case 18 {{aes_gcm, 256}, hexstr2bin("feffe9928665731c6d6a8f9467308308" %% Key "feffe9928665731c6d6a8f9467308308"), hexstr2bin("d9313225f88406e5a55909c5aff5269a" %% PlainText "86a7a9531534f7da2e4c303d8a318a72" "1c3c0c95956809532fcf0e2449a6b525" "b16aedf5aa0de657ba637b39"), hexstr2bin("9313225df88406e555909c5aff5269aa" %% IV "6a7a9538534f7da1e4c303d2a318a728" "c3c0c95156809539fcf0e2429a6b5254" "16aedbf5a0de6a57a637b39b"), hexstr2bin("feedfacedeadbeeffeedfacedeadbeef" %% AAD "abaddad2"), hexstr2bin("5a8def2f0c9e53f1f75d7853659e2a20" %% CipherText "eeb2b22aafde6419a058ab4f6f746bf4" "0fc0c3b780f244452da3ebf1c5d82cde" "a2418997200ef82e44ae7e3f"), hexstr2bin("a44a8266ee1c8eb0c8b5d4cf5ae9f19a")} %% CipherTag ]. erlang-jose-1.10.1/test/jose_public_key.hrl0000777000232200023220000000000013605433351026715 2../include/jose_public_key.hrlustar debalancedebalanceerlang-jose-1.10.1/test/jose_jwk_SUITE.erl0000644000232200023220000002316213605433351020624 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_SUITE). -include_lib("common_test/include/ct.hrl"). -include("jose.hrl"). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([encrypt_and_decrypt/1]). -export([kty_ec_from_der_and_to_der/1]). -export([kty_ec_from_map_and_to_map/1]). -export([kty_ec_from_pem_and_to_pem/1]). -export([kty_ec_box_encrypt_and_box_decrypt/1]). -export([kty_ec_sign_and_verify/1]). -export([kty_oct_from_map_and_to_map/1]). -export([kty_oct_block_encrypt_and_block_decrypt/1]). -export([kty_oct_sign_and_verify/1]). -export([kty_okp_ed25519_from_der_and_to_der/1]). -export([kty_okp_ed25519_from_map_and_to_map/1]). -export([kty_okp_ed25519_from_pem_and_to_pem/1]). -export([kty_okp_ed25519_sign_and_verify/1]). -export([kty_okp_ed25519ph_from_map_and_to_map/1]). -export([kty_okp_ed25519ph_sign_and_verify/1]). -export([kty_okp_ed448_from_der_and_to_der/1]). -export([kty_okp_ed448_from_map_and_to_map/1]). -export([kty_okp_ed448_from_pem_and_to_pem/1]). -export([kty_okp_ed448_sign_and_verify/1]). -export([kty_okp_ed448ph_from_map_and_to_map/1]). -export([kty_okp_ed448ph_sign_and_verify/1]). -export([kty_okp_x25519_from_der_and_to_der/1]). -export([kty_okp_x25519_from_map_and_to_map/1]). -export([kty_okp_x25519_from_pem_and_to_pem/1]). -export([kty_okp_x25519_box_encrypt_and_box_decrypt/1]). -export([kty_okp_x448_from_der_and_to_der/1]). -export([kty_okp_x448_from_map_and_to_map/1]). -export([kty_okp_x448_from_pem_and_to_pem/1]). -export([kty_okp_x448_box_encrypt_and_box_decrypt/1]). -export([kty_rsa_convert_sfm_to_crt/1]). -export([kty_rsa_from_der_and_to_der/1]). -export([kty_rsa_from_map_and_to_map/1]). -export([kty_rsa_from_pem_and_to_pem/1]). -export([kty_rsa_block_encrypt_and_block_decrypt/1]). -export([kty_rsa_sign_and_verify/1]). -export([set_from_map_and_to_map/1]). all() -> [ {group, jose_jwk}, {group, jose_jwk_kty_ec}, {group, jose_jwk_kty_oct}, {group, jose_jwk_kty_okp_ed25519}, {group, jose_jwk_kty_okp_ed25519ph}, {group, jose_jwk_kty_okp_ed448}, {group, jose_jwk_kty_okp_ed448ph}, {group, jose_jwk_kty_okp_x25519}, {group, jose_jwk_kty_okp_x448}, {group, jose_jwk_kty_rsa}, {group, jose_jwk_set} ]. groups() -> [ {jose_jwk, [parallel], [ encrypt_and_decrypt ]}, {jose_jwk_kty_ec, [parallel], [ kty_ec_from_der_and_to_der, kty_ec_from_map_and_to_map, kty_ec_from_pem_and_to_pem, kty_ec_box_encrypt_and_box_decrypt, kty_ec_sign_and_verify ]}, {jose_jwk_kty_oct, [parallel], [ kty_oct_from_map_and_to_map, kty_oct_block_encrypt_and_block_decrypt, kty_oct_sign_and_verify ]}, {jose_jwk_kty_okp_ed25519, [parallel], [ kty_okp_ed25519_from_der_and_to_der, kty_okp_ed25519_from_map_and_to_map, kty_okp_ed25519_from_pem_and_to_pem, kty_okp_ed25519_sign_and_verify ]}, {jose_jwk_kty_okp_ed25519ph, [parallel], [ kty_okp_ed25519ph_from_map_and_to_map, kty_okp_ed25519ph_sign_and_verify ]}, {jose_jwk_kty_okp_ed448, [parallel], [ kty_okp_ed448_from_der_and_to_der, kty_okp_ed448_from_map_and_to_map, kty_okp_ed448_from_pem_and_to_pem, kty_okp_ed448_sign_and_verify ]}, {jose_jwk_kty_okp_ed448ph, [parallel], [ kty_okp_ed448ph_from_map_and_to_map, kty_okp_ed448ph_sign_and_verify ]}, {jose_jwk_kty_okp_x25519, [parallel], [ kty_okp_x25519_from_der_and_to_der, kty_okp_x25519_from_map_and_to_map, kty_okp_x25519_from_pem_and_to_pem, kty_okp_x25519_box_encrypt_and_box_decrypt ]}, {jose_jwk_kty_okp_x448, [parallel], [ kty_okp_x448_from_der_and_to_der, kty_okp_x448_from_map_and_to_map, kty_okp_x448_from_pem_and_to_pem, kty_okp_x448_box_encrypt_and_box_decrypt ]}, {jose_jwk_kty_rsa, [parallel], [ kty_rsa_convert_sfm_to_crt, kty_rsa_from_der_and_to_der, kty_rsa_from_map_and_to_map, kty_rsa_from_pem_and_to_pem, kty_rsa_block_encrypt_and_block_decrypt, kty_rsa_sign_and_verify ]}, {jose_jwk_set, [parallel], [ set_from_map_and_to_map ]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), ct_property_test:init_per_suite(Config). end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(Group, Config) -> jose_ct:start(Group, Config). end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== encrypt_and_decrypt(Config) -> ct_property_test:quickcheck( jose_jwk_props:prop_encrypt_and_decrypt(), Config). kty_ec_from_der_and_to_der(Config) -> ct_property_test:quickcheck( jose_jwk_kty_ec_props:prop_from_der_and_to_der(), Config). kty_ec_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_ec_props:prop_from_map_and_to_map(), Config). kty_ec_from_pem_and_to_pem(Config) -> ct_property_test:quickcheck( jose_jwk_kty_ec_props:prop_from_pem_and_to_pem(), Config). kty_ec_box_encrypt_and_box_decrypt(Config) -> ct_property_test:quickcheck( jose_jwk_kty_ec_props:prop_box_encrypt_and_box_decrypt(), Config). kty_ec_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwk_kty_ec_props:prop_sign_and_verify(), Config). kty_oct_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_oct_props:prop_from_map_and_to_map(), Config). kty_oct_block_encrypt_and_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwk_kty_oct_props:prop_block_encrypt_and_block_decrypt(), Config). kty_oct_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwk_kty_oct_props:prop_sign_and_verify(), Config). kty_okp_ed25519_from_der_and_to_der(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed25519_props:prop_from_der_and_to_der(), Config). kty_okp_ed25519_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed25519_props:prop_from_map_and_to_map(), Config). kty_okp_ed25519_from_pem_and_to_pem(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed25519_props:prop_from_pem_and_to_pem(), Config). kty_okp_ed25519_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed25519_props:prop_sign_and_verify(), Config). kty_okp_ed25519ph_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed25519ph_props:prop_from_map_and_to_map(), Config). kty_okp_ed25519ph_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed25519ph_props:prop_sign_and_verify(), Config). kty_okp_ed448_from_der_and_to_der(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed448_props:prop_from_der_and_to_der(), Config). kty_okp_ed448_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed448_props:prop_from_map_and_to_map(), Config). kty_okp_ed448_from_pem_and_to_pem(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed448_props:prop_from_pem_and_to_pem(), Config). kty_okp_ed448_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed448_props:prop_sign_and_verify(), Config). kty_okp_ed448ph_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed448ph_props:prop_from_map_and_to_map(), Config). kty_okp_ed448ph_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_ed448ph_props:prop_sign_and_verify(), Config). kty_okp_x25519_from_der_and_to_der(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_x25519_props:prop_from_der_and_to_der(), Config). kty_okp_x25519_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_x25519_props:prop_from_map_and_to_map(), Config). kty_okp_x25519_from_pem_and_to_pem(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_x25519_props:prop_from_pem_and_to_pem(), Config). kty_okp_x25519_box_encrypt_and_box_decrypt(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_x25519_props:prop_box_encrypt_and_box_decrypt(), Config). kty_okp_x448_from_der_and_to_der(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_x448_props:prop_from_der_and_to_der(), Config). kty_okp_x448_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_x448_props:prop_from_map_and_to_map(), Config). kty_okp_x448_from_pem_and_to_pem(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_x448_props:prop_from_pem_and_to_pem(), Config). kty_okp_x448_box_encrypt_and_box_decrypt(Config) -> ct_property_test:quickcheck( jose_jwk_kty_okp_x448_props:prop_box_encrypt_and_box_decrypt(), Config). kty_rsa_convert_sfm_to_crt(Config) -> ct_property_test:quickcheck( jose_jwk_kty_rsa_props:prop_convert_sfm_to_crt(), Config). kty_rsa_from_der_and_to_der(Config) -> ct_property_test:quickcheck( jose_jwk_kty_rsa_props:prop_from_der_and_to_der(), Config). kty_rsa_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_kty_rsa_props:prop_from_map_and_to_map(), Config). kty_rsa_from_pem_and_to_pem(Config) -> ct_property_test:quickcheck( jose_jwk_kty_rsa_props:prop_from_pem_and_to_pem(), Config). kty_rsa_block_encrypt_and_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwk_kty_rsa_props:prop_block_encrypt_and_block_decrypt(), Config). kty_rsa_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwk_kty_rsa_props:prop_sign_and_verify(), Config). set_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwk_set_props:prop_from_map_and_to_map(), Config). erlang-jose-1.10.1/test/test_helper.exs0000644000232200023220000000071513605433351020372 0ustar debalancedebalanceExUnit.start() defmodule JOSETestHelper do def gen_ec(curve_id) do :public_key.generate_key({:namedCurve, :pubkey_cert_records.namedCurves(curve_id)}) end def gen_hmac do :crypto.strong_rand_bytes(:rand.uniform(64, 256)) end def gen_private_key(:ecdsa) do private_key = gen_ec(:secp256r1) {private_key, bin_private_key(private_key)} end def bin_private_key(private_key), do: :http_signature_private_key.encode(private_key) end erlang-jose-1.10.1/test/jose_SUITE.erl0000644000232200023220000010260413605433351017750 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_SUITE). -include_lib("common_test/include/ct.hrl"). -include("jose_public_key.hrl"). -include_lib("public_key/include/public_key.hrl"). -include("jose.hrl"). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([jose_cfrg_curves_a_1/1]). -export([jose_cfrg_curves_a_2/1]). -export([jose_cfrg_curves_a_3/1]). -export([jose_cfrg_curves_a_4/1]). -export([jose_cfrg_curves_a_5/1]). -export([jose_cfrg_curves_a_6/1]). -export([jose_cfrg_curves_a_7/1]). -export([jose_ecdh_1pu_a/1]). -export([jwe_a_1/1]). -export([jwe_a_2/1]). -export([jwe_a_3/1]). -export([jwk_c/1]). -export([jwk_rsa_multi/1]). -export([jws_a_1/1]). -export([jws_a_2/1]). -export([jws_a_3/1]). -export([jws_a_4/1]). -export([jws_a_5/1]). -export([rfc7520_5_9/1]). %% Macros. -define(tv_ok(T, M, F, A, E), case erlang:apply(M, F, A) of E -> ok; T -> ct:fail({{M, F, A}, {expected, E}, {got, T}}) end). all() -> [ {group, jose_cfrg_curves}, {group, jose_ecdh_1pu}, {group, jose_jwe}, {group, jose_jwk}, {group, jose_jws}, {group, rfc7520} ]. groups() -> [ {jose_cfrg_curves, [parallel], [ jose_cfrg_curves_a_1, jose_cfrg_curves_a_2, jose_cfrg_curves_a_3, jose_cfrg_curves_a_4, jose_cfrg_curves_a_5, jose_cfrg_curves_a_6, jose_cfrg_curves_a_7 ]}, {jose_ecdh_1pu, [parallel], [ jose_ecdh_1pu_a ]}, {jose_jwe, [parallel], [ jwe_a_1, jwe_a_2, jwe_a_3 ]}, {jose_jwk, [parallel], [ jwk_c, jwk_rsa_multi ]}, {jose_jws, [parallel], [ jws_a_1, jws_a_2, jws_a_3, jws_a_4, jws_a_5 ]}, {rfc7520, [parallel], [ rfc7520_5_9 ]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), Config. end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(G=jose_cfrg_curves, Config) -> {ok, A1} = file:consult(data_file("jose_cfrg_curves/a.1.config", Config)), {ok, A3} = file:consult(data_file("jose_cfrg_curves/a.3.config", Config)), {ok, A4} = file:consult(data_file("jose_cfrg_curves/a.4.config", Config)), {ok, A5} = file:consult(data_file("jose_cfrg_curves/a.5.config", Config)), {ok, A6} = file:consult(data_file("jose_cfrg_curves/a.6.config", Config)), {ok, A7} = file:consult(data_file("jose_cfrg_curves/a.7.config", Config)), [{jose_cfrg_curves_a_1, A1}, {jose_cfrg_curves_a_3, A3}, {jose_cfrg_curves_a_4, A4}, {jose_cfrg_curves_a_5, A5}, {jose_cfrg_curves_a_6, A6}, {jose_cfrg_curves_a_7, A7} | jose_ct:start(G, Config)]; init_per_group(G=jose_ecdh_1pu, Config) -> {ok, A} = file:consult(data_file("jose_ecdh_1pu/a.config", Config)), [{jose_ecdh_1pu_a, A} | jose_ct:start(G, Config)]; init_per_group(G=jose_jwe, Config) -> {ok, A1} = file:consult(data_file("jwe/a.1.config", Config)), {ok, A2} = file:consult(data_file("jwe/a.2.config", Config)), {ok, A3} = file:consult(data_file("jwe/a.3.config", Config)), [{jwe_a_1, A1}, {jwe_a_2, A2}, {jwe_a_3, A3} | jose_ct:start(G, Config)]; init_per_group(G=jose_jwk, Config) -> {ok, C} = file:consult(data_file("jwk/c.config", Config)), [{jwk_c, C} | jose_ct:start(G, Config)]; init_per_group(G=jose_jws, Config) -> {ok, A1} = file:consult(data_file("jws/a.1.config", Config)), {ok, A2} = file:consult(data_file("jws/a.2.config", Config)), {ok, A3} = file:consult(data_file("jws/a.3.config", Config)), {ok, A4} = file:consult(data_file("jws/a.4.config", Config)), {ok, A5} = file:consult(data_file("jws/a.5.config", Config)), [{jws_a_1, A1}, {jws_a_2, A2}, {jws_a_3, A3}, {jws_a_4, A4}, {jws_a_5, A5} | jose_ct:start(G, Config)]; init_per_group(G=rfc7520, Config) -> {ok, V_5_9} = file:consult(data_file("rfc7520/5.9.config", Config)), [{rfc7520_5_9, V_5_9} | jose_ct:start(G, Config)]; init_per_group(Group, Config) -> jose_ct:start(Group, Config). end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== % CFRG ECDH and signatures in JOSE % A.1. Ed25519 private key % [https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-00#appendix-A.1] jose_cfrg_curves_a_1(Config) -> C = ?config(jose_cfrg_curves_a_1, Config), % A.1 A_1_JWK = jose_jwk:from_file(data_file("jose_cfrg_curves/a.1.jwk+json", Config)), A_1_Secret = hex:hex_to_bin(?config("a.1.secret", C)), A_1_PK = hex:hex_to_bin(?config("a.1.pk", C)), % A_1_SK = << A_1_Secret/binary, A_1_PK/binary >>, {_, #'jose_EdDSA25519PrivateKey'{ publicKey=#'jose_EdDSA25519PublicKey'{publicKey=A_1_PK}, privateKey=A_1_Secret }} = jose_jwk:to_key(A_1_JWK), {_, #'jose_EdDSA25519PublicKey'{publicKey=A_1_PK}} = jose_jwk:to_public_key(A_1_JWK), ok. % CFRG ECDH and signatures in JOSE % A.2. Ed25519 public key % [https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-00#appendix-A.2] jose_cfrg_curves_a_2(Config) -> % A.1 A_1_JWK = jose_jwk:from_file(data_file("jose_cfrg_curves/a.1.jwk+json", Config)), % A.2 A_2_JWK = jose_jwk:from_file(data_file("jose_cfrg_curves/a.2.jwk+json", Config)), A_2_JWK = jose_jwk:to_public(A_1_JWK), ok. % CFRG ECDH and signatures in JOSE % A.3. JWK thumbprint canonicalization % [https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-00#appendix-A.3] jose_cfrg_curves_a_3(Config) -> C = ?config(jose_cfrg_curves_a_3, Config), % A.1 A_1_JWK = jose_jwk:from_file(data_file("jose_cfrg_curves/a.1.jwk+json", Config)), % A.2 A_2_JWK = jose_jwk:from_file(data_file("jose_cfrg_curves/a.2.jwk+json", Config)), % A.3 A_3_JWK = jose_jwk:from_binary(?config("a.3.jwk+json", C)), A_3_THUMBPRINT_HEX = ?config("a.3.thumbprint+hex", C), A_3_THUMBPRINT = jose_jwa_base64url:encode(hex:hex_to_bin(A_3_THUMBPRINT_HEX)), A_3_THUMBPRINT = ?config("a.3.thumbprint+b64", C), A_3_THUMBPRINT = jose_jwk:thumbprint(A_1_JWK), A_3_THUMBPRINT = jose_jwk:thumbprint(A_2_JWK), A_3_THUMBPRINT = jose_jwk:thumbprint(A_3_JWK), ok. % CFRG ECDH and signatures in JOSE % A.4. Ed25519 Signing % [https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-00#appendix-A.4] jose_cfrg_curves_a_4(Config) -> C = ?config(jose_cfrg_curves_a_4, Config), % A.1 A_1_JWK = jose_jwk:from_file(data_file("jose_cfrg_curves/a.1.jwk+json", Config)), % A.4 A_4_PROTECTED = ?config("a.4.jws+json", C), A_4_JWS = jose_jws:from_binary(A_4_PROTECTED), A_4_JWS_B64 = ?config("a.4.jws+b64", C), A_4_TXT = ?config("a.4.txt", C), A_4_TXT_B64 = ?config("a.4.txt+b64", C), A_4_SIGNINGINPUT = ?config("a.4.signing-input", C), A_4_SIG = hex:hex_to_bin(?config("a.4.sig+hex", C)), A_4_SIG_B64 = ?config("a.4.sig+b64", C), A_4_SIG_COMPACT = ?config("a.4.sig+compact", C), A_4_TXT_B64 = jose_jwa_base64url:encode(A_4_TXT), A_4_SIGNINGINPUT = << A_4_JWS_B64/binary, $., A_4_TXT_B64/binary >>, A_4_SIGNINGINPUT = jose_jws:signing_input(A_4_TXT, A_4_JWS), %% Forcing the Protected header to be A_4_PROTECTED A_4_MAP=#{ <<"signature">> := A_4_SIG_B64 } = force_sign(A_1_JWK, A_4_TXT, A_4_PROTECTED, A_4_JWS), A_4_SIG = jose_jwa_base64url:decode(A_4_SIG_B64), {_, A_4_SIG_COMPACT} = jose_jws:compact(A_4_MAP), ok. % CFRG ECDH and signatures in JOSE % A.5. Ed25519 Validation % [https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-00#appendix-A.5] jose_cfrg_curves_a_5(Config) -> C = ?config(jose_cfrg_curves_a_5, Config), % A.1 A_1_JWK = jose_jwk:from_file(data_file("jose_cfrg_curves/a.1.jwk+json", Config)), % A.2 A_2_JWK = jose_jwk:from_file(data_file("jose_cfrg_curves/a.2.jwk+json", Config)), % A.4 A_5_SIG_COMPACT = ?config("a.5.sig+compact", C), A_5_JWS = jose_jws:from_binary(?config("a.5.jws+json", C)), A_5_PAYLOAD_DATA = ?config("a.5.txt", C), {true, A_5_PAYLOAD_DATA, A_5_JWS} = jose_jws:verify(A_1_JWK, A_5_SIG_COMPACT), {true, A_5_PAYLOAD_DATA, A_5_JWS} = jose_jws:verify(A_2_JWK, A_5_SIG_COMPACT), ok. % CFRG ECDH and signatures in JOSE % A.6. ECDH-ES with X25519 % [https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-00#appendix-A.6] jose_cfrg_curves_a_6(Config) -> C = ?config(jose_cfrg_curves_a_6, Config), % A.6 A_6_BOB_JWK = jose_jwk:from_binary(?config("a.6.bob-jwk+json", C)), A_6_BOB_Secret = hex:hex_to_bin(?config("a.6.bob-secret+hex", C)), A_6_BOB_PK = hex:hex_to_bin(?config("a.6.bob-pk+hex", C)), A_6_EPK_Secret = hex:hex_to_bin(?config("a.6.epk-secret+hex", C)), A_6_EPK_PK = hex:hex_to_bin(?config("a.6.epk-pk+hex", C)), A_6_EPK_JWK = jose_jwk:from_binary(?config("a.6.epk-jwk+json", C)), A_6_PROTECTED = ?config("a.6.jwe+json", C), A_6_JWE = jose_jwe:from_binary(A_6_PROTECTED), A_6_Z = hex:hex_to_bin(?config("a.6.z+hex", C)), A_6_BOB_SK = << A_6_BOB_Secret/binary, A_6_BOB_PK/binary >>, A_6_EPK_SK = << A_6_EPK_Secret/binary, A_6_EPK_PK/binary >>, A_6_BOB_S_JWK = jose_jwk:from_okp({'X25519', A_6_BOB_SK}), A_6_EPK_S_JWK = jose_jwk:from_okp({'X25519', A_6_EPK_SK}), {_, #'jose_X25519PrivateKey'{ publicKey=#'jose_X25519PublicKey'{publicKey=A_6_BOB_PK}, privateKey=A_6_BOB_Secret }} = jose_jwk:to_key(A_6_BOB_S_JWK), {_, #'jose_X25519PublicKey'{publicKey=A_6_BOB_PK}} = jose_jwk:to_public_key(A_6_BOB_S_JWK), {_, #'jose_X25519PublicKey'{publicKey=A_6_BOB_PK}} = jose_jwk:to_key(A_6_BOB_JWK), {_, #'jose_X25519PrivateKey'{ publicKey=#'jose_X25519PublicKey'{publicKey=A_6_EPK_PK}, privateKey=A_6_EPK_Secret }} = jose_jwk:to_key(A_6_EPK_S_JWK), {_, #'jose_X25519PublicKey'{publicKey=A_6_EPK_PK}} = jose_jwk:to_public_key(A_6_EPK_S_JWK), {_, #'jose_X25519PublicKey'{publicKey=A_6_EPK_PK}} = jose_jwk:to_key(A_6_EPK_JWK), A_6_Z = jose_jwk:shared_secret(A_6_BOB_JWK, A_6_EPK_S_JWK), A_6_Z = jose_jwk:shared_secret(A_6_EPK_JWK, A_6_BOB_S_JWK), A_6_TEXT = <<"Example of X25519 encryption">>, {_, A_6_ENC_MAP} = jose_jwe:block_encrypt({A_6_BOB_JWK, A_6_EPK_S_JWK}, A_6_TEXT, A_6_JWE), {_, A_6_ENC_COMPACT} = jose_jwe:compact(A_6_ENC_MAP), {A_6_TEXT, A_6_JWE} = jose_jwe:block_decrypt(A_6_BOB_S_JWK, A_6_ENC_MAP), {A_6_TEXT, A_6_JWE} = jose_jwe:block_decrypt(A_6_BOB_S_JWK, A_6_ENC_COMPACT), ok. % CFRG ECDH and signatures in JOSE % A.7. ECDH-ES with X448 % [https://tools.ietf.org/html/draft-ietf-jose-cfrg-curves-00#appendix-A.7] jose_cfrg_curves_a_7(Config) -> C = ?config(jose_cfrg_curves_a_7, Config), % A.7 A_7_BOB_JWK = jose_jwk:from_binary(?config("a.7.bob-jwk+json", C)), A_7_BOB_Secret = hex:hex_to_bin(?config("a.7.bob-secret+hex", C)), A_7_BOB_PK = hex:hex_to_bin(?config("a.7.bob-pk+hex", C)), A_7_EPK_Secret = hex:hex_to_bin(?config("a.7.epk-secret+hex", C)), A_7_EPK_PK = hex:hex_to_bin(?config("a.7.epk-pk+hex", C)), A_7_EPK_JWK = jose_jwk:from_binary(?config("a.7.epk-jwk+json", C)), A_7_PROTECTED = ?config("a.7.jwe+json", C), A_7_JWE = jose_jwe:from_binary(A_7_PROTECTED), A_7_Z = hex:hex_to_bin(?config("a.7.z+hex", C)), A_7_BOB_SK = << A_7_BOB_Secret/binary, A_7_BOB_PK/binary >>, A_7_EPK_SK = << A_7_EPK_Secret/binary, A_7_EPK_PK/binary >>, A_7_BOB_S_JWK = jose_jwk:from_okp({'X448', A_7_BOB_SK}), A_7_EPK_S_JWK = jose_jwk:from_okp({'X448', A_7_EPK_SK}), {_, #'jose_X448PrivateKey'{ publicKey=#'jose_X448PublicKey'{publicKey=A_7_BOB_PK}, privateKey=A_7_BOB_Secret }} = jose_jwk:to_key(A_7_BOB_S_JWK), {_, #'jose_X448PublicKey'{publicKey=A_7_BOB_PK}} = jose_jwk:to_public_key(A_7_BOB_S_JWK), {_, #'jose_X448PublicKey'{publicKey=A_7_BOB_PK}} = jose_jwk:to_key(A_7_BOB_JWK), {_, #'jose_X448PrivateKey'{ publicKey=#'jose_X448PublicKey'{publicKey=A_7_EPK_PK}, privateKey=A_7_EPK_Secret }} = jose_jwk:to_key(A_7_EPK_S_JWK), {_, #'jose_X448PublicKey'{publicKey=A_7_EPK_PK}} = jose_jwk:to_public_key(A_7_EPK_S_JWK), {_, #'jose_X448PublicKey'{publicKey=A_7_EPK_PK}} = jose_jwk:to_key(A_7_EPK_JWK), A_7_Z = jose_jwk:shared_secret(A_7_BOB_JWK, A_7_EPK_S_JWK), A_7_Z = jose_jwk:shared_secret(A_7_EPK_JWK, A_7_BOB_S_JWK), A_7_TEXT = <<"Example of X448 encryption">>, {_, A_7_ENC_MAP} = jose_jwe:block_encrypt({A_7_BOB_JWK, A_7_EPK_S_JWK}, A_7_TEXT, A_7_JWE), {_, A_7_ENC_COMPACT} = jose_jwe:compact(A_7_ENC_MAP), {A_7_TEXT, A_7_JWE} = jose_jwe:block_decrypt(A_7_BOB_S_JWK, A_7_ENC_MAP), {A_7_TEXT, A_7_JWE} = jose_jwe:block_decrypt(A_7_BOB_S_JWK, A_7_ENC_COMPACT), ok. % Public Key Authenticated Encryption for JOSE: ECDH-1PU % A. Example ECDH-1PU Key Agreement Computation with A256GCM % [https://tools.ietf.org/html/draft-madden-jose-ecdh-1pu-02#appendix-A] jose_ecdh_1pu_a(Config) -> C = ?config(jose_ecdh_1pu_a, Config), A_USSK_JWK = jose_jwk:from_binary(?config("a.ussk.jwk+json", C)), A_VSSK_JWK = jose_jwk:from_binary(?config("a.vssk.jwk+json", C)), A_UESK_JWK = jose_jwk:from_binary(?config("a.uesk.jwk+json", C)), A_JWE = jose_jwe:from_binary(?config("a.jwe+json", C)), A_ZE = hex:hex_to_bin(?config("a.ze+hex", C)), A_ZS = hex:hex_to_bin(?config("a.zs+hex", C)), A_Z = hex:hex_to_bin(?config("a.z+hex", C)), A_CEK = hex:hex_to_bin(?config("a.cek+hex", C)), A_ZE = jose_jwk:shared_secret(A_VSSK_JWK, A_UESK_JWK), A_ZS = jose_jwk:shared_secret(A_VSSK_JWK, A_USSK_JWK), A_ZS = jose_jwk:shared_secret(A_USSK_JWK, A_VSSK_JWK), A_Z = <>, {A_CEK, _} = jose_jwe:next_cek({A_VSSK_JWK, A_USSK_JWK, A_UESK_JWK}, A_JWE), A_CEK = jose_jwe:key_decrypt({A_USSK_JWK, A_VSSK_JWK, A_UESK_JWK}, <<>>, A_JWE), ok. % JSON Web Encryption (JWE) % A.1. Example JWE using RSAES-OAEP and AES GCM % [https://tools.ietf.org/html/rfc7516#appendix-A.1] jwe_a_1(Config) -> C = ?config(jwe_a_1, Config), % A.1 A_1_TXT = ?config("a.1.txt", C), % A.1.1 A_1_1_JWE_DATA = ?config("a.1.1.jwe+json", C), A_1_1_JWE_MAP = jose:decode(A_1_1_JWE_DATA), A_1_1_JWE = jose_jwe:from_binary(A_1_1_JWE_DATA), {_, A_1_1_JWE_MAP} = jose_jwe:to_map(A_1_1_JWE), A_1_1_JWE_DATA_B64 = ?config("a.1.1.jwe+json.b64", C), A_1_1_JWE_DATA_B64 = jose_jwa_base64url:encode(element(2, jose_jwe:to_binary(A_1_1_JWE))), % A.1.2 A_1_2_CEK = ?config("a.1.2.cek", C), % A.1.3 A_1_3_JWK_DATA = ?config("a.1.3.jwk+json", C), A_1_3_JWK_MAP = jose:decode(A_1_3_JWK_DATA), A_1_3_JWK = jose_jwk:from_binary(A_1_3_JWK_DATA), {_, A_1_3_JWK_MAP} = jose_jwk:to_map(A_1_3_JWK), A_1_3_CEK_ENCRYPTED = ?config("a.1.3.cek.encrypted", C), A_1_3_CEK_ENCRYPTED_B64 = ?config("a.1.3.cek.encrypted.b64", C), A_1_3_CEK_ENCRYPTED_B64 = jose_jwa_base64url:encode(A_1_3_CEK_ENCRYPTED), % A.1.4 A_1_4_IV = ?config("a.1.4.iv", C), A_1_4_IV_B64 = ?config("a.1.4.iv.b64", C), A_1_4_IV_B64 = jose_jwa_base64url:encode(A_1_4_IV), % A.1.5 A_1_5_AAD = ?config("a.1.5.aad", C), A_1_1_JWE_DATA_B64 = A_1_5_AAD, % A.1.6 A_1_6_CIPHER = ?config("a.1.6.txt.cipher", C), A_1_6_TAG = ?config("a.1.6.txt.tag", C), A_1_6_CIPHER_B64 = ?config("a.1.6.txt.cipher.b64", C), A_1_6_TAG_B64 = ?config("a.1.6.txt.tag.b64", C), A_1_6_CIPHER = jose_jwa_base64url:decode(A_1_6_CIPHER_B64), A_1_6_TAG = jose_jwa_base64url:decode(A_1_6_TAG_B64), % A.1.7 A_1_7_COMPACT = ?config("a.1.7.jwe+compact", C), {A_1_TXT, A_1_1_JWE} = jose_jwe:block_decrypt(A_1_3_JWK, A_1_7_COMPACT), % Roundtrip test A_1_7_MAP = jose_jwe:block_encrypt(A_1_3_JWK, A_1_TXT, A_1_2_CEK, A_1_4_IV, A_1_1_JWE), {A_1_TXT, A_1_1_JWE} = jose_jwe:block_decrypt(A_1_3_JWK, A_1_7_MAP), ok. % JSON Web Encryption (JWE) % A.2. Example JWE using RSAES-PKCS1-v1_5 and AES_128_CBC_HMAC_SHA_256 % [https://tools.ietf.org/html/rfc7516#appendix-A.2] jwe_a_2(Config) -> C = ?config(jwe_a_2, Config), % A.2 A_2_TXT = ?config("a.2.txt", C), % A.2.1 A_2_1_JWE_DATA = ?config("a.2.1.jwe+json", C), A_2_1_JWE_MAP = jose:decode(A_2_1_JWE_DATA), A_2_1_JWE = jose_jwe:from_binary(A_2_1_JWE_DATA), {_, A_2_1_JWE_MAP} = jose_jwe:to_map(A_2_1_JWE), A_2_1_JWE_DATA_B64 = ?config("a.2.1.jwe+json.b64", C), A_2_1_JWE_DATA_B64 = jose_jwa_base64url:encode(element(2, jose_jwe:to_binary(A_2_1_JWE))), % A.2.2 A_2_2_CEK = ?config("a.2.2.cek", C), % A.2.3 A_2_3_JWK_DATA = ?config("a.2.3.jwk+json", C), A_2_3_JWK_MAP = jose:decode(A_2_3_JWK_DATA), A_2_3_JWK = jose_jwk:from_binary(A_2_3_JWK_DATA), {_, A_2_3_JWK_MAP} = jose_jwk:to_map(A_2_3_JWK), A_2_3_CEK_ENCRYPTED = ?config("a.2.3.cek.encrypted", C), A_2_3_CEK_ENCRYPTED_B64 = ?config("a.2.3.cek.encrypted.b64", C), A_2_3_CEK_ENCRYPTED_B64 = jose_jwa_base64url:encode(A_2_3_CEK_ENCRYPTED), % A.2.4 A_2_4_IV = ?config("a.2.4.iv", C), A_2_4_IV_B64 = ?config("a.2.4.iv.b64", C), A_2_4_IV_B64 = jose_jwa_base64url:encode(A_2_4_IV), % A.2.5 A_2_5_AAD = ?config("a.2.5.aad", C), A_2_1_JWE_DATA_B64 = A_2_5_AAD, % A.2.6 A_2_6_CIPHER = ?config("a.2.6.txt.cipher", C), A_2_6_TAG = ?config("a.2.6.txt.tag", C), A_2_6_CIPHER_B64 = ?config("a.2.6.txt.cipher.b64", C), A_2_6_TAG_B64 = ?config("a.2.6.txt.tag.b64", C), A_2_6_CIPHER = jose_jwa_base64url:decode(A_2_6_CIPHER_B64), A_2_6_TAG = jose_jwa_base64url:decode(A_2_6_TAG_B64), % A.2.7 A_2_7_COMPACT = ?config("a.2.7.jwe+compact", C), {A_2_TXT, A_2_1_JWE} = jose_jwe:block_decrypt(A_2_3_JWK, A_2_7_COMPACT), % Roundtrip test A_2_7_MAP = jose_jwe:block_encrypt(A_2_3_JWK, A_2_TXT, A_2_2_CEK, A_2_4_IV, A_2_1_JWE), {A_2_TXT, A_2_1_JWE} = jose_jwe:block_decrypt(A_2_3_JWK, A_2_7_MAP), ok. % JSON Web Encryption (JWE) % A.3. Example JWE Using AES Key Wrap and AES_128_CBC_HMAC_SHA_256 % [https://tools.ietf.org/html/rfc7516#appendix-A.3] jwe_a_3(Config) -> C = ?config(jwe_a_3, Config), % A.3 A_3_TXT = ?config("a.3.txt", C), % A.3.1 A_3_1_JWE_DATA = ?config("a.3.1.jwe+json", C), A_3_1_JWE_MAP = jose:decode(A_3_1_JWE_DATA), A_3_1_JWE = jose_jwe:from_binary(A_3_1_JWE_DATA), {_, A_3_1_JWE_MAP} = jose_jwe:to_map(A_3_1_JWE), A_3_1_JWE_DATA_B64 = ?config("a.3.1.jwe+json.b64", C), A_3_1_JWE_DATA_B64 = jose_jwa_base64url:encode(element(2, jose_jwe:to_binary(A_3_1_JWE))), % A.3.2 A_3_2_CEK = ?config("a.3.2.cek", C), % A.3.3 A_3_3_JWK_DATA = ?config("a.3.3.jwk+json", C), A_3_3_JWK_MAP = jose:decode(A_3_3_JWK_DATA), A_3_3_JWK = jose_jwk:from_binary(A_3_3_JWK_DATA), {_, A_3_3_JWK_MAP} = jose_jwk:to_map(A_3_3_JWK), A_3_3_CEK_ENCRYPTED = ?config("a.3.3.cek.encrypted", C), A_3_3_CEK_ENCRYPTED_B64 = ?config("a.3.3.cek.encrypted.b64", C), A_3_3_CEK_ENCRYPTED_B64 = jose_jwa_base64url:encode(A_3_3_CEK_ENCRYPTED), % A.3.4 A_3_4_IV = ?config("a.3.4.iv", C), A_3_4_IV_B64 = ?config("a.3.4.iv.b64", C), A_3_4_IV_B64 = jose_jwa_base64url:encode(A_3_4_IV), % A.3.5 A_3_5_AAD = ?config("a.3.5.aad", C), A_3_1_JWE_DATA_B64 = A_3_5_AAD, % A.3.6 A_3_6_CIPHER = ?config("a.3.6.txt.cipher", C), A_3_6_TAG = ?config("a.3.6.txt.tag", C), A_3_6_CIPHER_B64 = ?config("a.3.6.txt.cipher.b64", C), A_3_6_TAG_B64 = ?config("a.3.6.txt.tag.b64", C), A_3_6_CIPHER = jose_jwa_base64url:decode(A_3_6_CIPHER_B64), A_3_6_TAG = jose_jwa_base64url:decode(A_3_6_TAG_B64), % A.3.7 A_3_7_COMPACT = ?config("a.3.7.jwe+compact", C), {A_3_TXT, A_3_1_JWE} = jose_jwe:block_decrypt(A_3_3_JWK, A_3_7_COMPACT), % Roundtrip test A_3_7_MAP = jose_jwe:block_encrypt(A_3_3_JWK, A_3_TXT, A_3_2_CEK, A_3_4_IV, A_3_1_JWE), {A_3_TXT, A_3_1_JWE} = jose_jwe:block_decrypt(A_3_3_JWK, A_3_7_MAP), ok. % JSON Web Key (JWK) % Appendix C. Example Encrypted RSA Private Key % [https://tools.ietf.org/html/rfc7517#appendix-C] jwk_c(Config) -> C = ?config(jwk_c, Config), % C.1 C_1_JSON_DATA = ?config("c.1.jwk+json", C), C_1_JSON = jose:decode(C_1_JSON_DATA), C_1_JWK = jose_jwk:from_file(data_file("jwk/c.1.jwk+json", Config)), {_, C_1_JSON} = jose_jwk:to_map(C_1_JWK), % C.2 C_2_JSON_DATA = ?config("c.2.jwe+json", C), C_2_JSON = jose:decode(C_2_JSON_DATA), C_2_JWE = jose_jwe:from_file(data_file("jwk/c.2.jwe+json", Config)), {_, C_2_JSON} = jose_jwe:to_map(C_2_JWE), C_2_B64_DATA = ?config("c.2.b64", C), C_2_B64_DATA = jose_jwa_base64url:encode(C_2_JSON_DATA), % C.3 C_3_CEK = ?config("c.3.cek", C), % C.4 C_4_TXT = ?config("c.4.txt", C), C_4_SALT = ?config("c.4.salt", C), C_4_SALT = << (maps:get(<<"alg">>, C_2_JSON))/binary, 0, (jose_jwa_base64url:decode(maps:get(<<"p2s">>, C_2_JSON)))/binary >>, C_4_DKEY = ?config("c.4.derivedkey", C), {ok, C_4_DKEY} = jose_jwa_pkcs5:pbkdf2({hmac, sha256}, C_4_TXT, C_4_SALT, maps:get(<<"p2c">>, C_2_JSON), 16), % C.5 C_5_EKEY = ?config("c.5.encryptedkey", C), {C_5_EKEY, _} = jose_jwe:key_encrypt(C_4_TXT, C_3_CEK, C_2_JWE), % C.6 C_6_IV = ?config("c.6.iv", C), % C.7 C_7_AAD = ?config("c.7.aad", C), C_7_AAD = C_2_JSON_DATA, % C.8 C_8_CIPHER_TXT = ?config("c.8.ciphertxt", C), C_8_CIPHER_TAG = ?config("c.8.ciphertag", C), %% Forcing the AAD data to be C_7_AAD C_8_ENC_MAP=#{ <<"ciphertext">> := C_8_CIPHER_TXT_B64, <<"tag">> := C_8_CIPHER_TAG_B64 } = force_block_encrypt(C_4_TXT, C_1_JSON_DATA, C_3_CEK, C_6_IV, C_7_AAD, C_2_JWE), C_8_CIPHER_TXT = jose_jwa_base64url:decode(C_8_CIPHER_TXT_B64), C_8_CIPHER_TAG = jose_jwa_base64url:decode(C_8_CIPHER_TAG_B64), % C.9 C_9_DATA = ?config("c.9.jwe+txt", C), {_, C_9_DATA} = jose_jwe:compact(C_8_ENC_MAP), %% Make sure decryption also works {C_1_JSON_DATA, _} = jose_jwe:block_decrypt(C_4_TXT, C_9_DATA), %% Encrypt and Decrypt {_, C_1_JWK} = jose_jwk:from_map(C_4_TXT, jose_jwk:to_map(C_4_TXT, C_2_JWE, C_1_JWK)), ok. jwk_rsa_multi(Config) -> JWK = jose_jwk:from_pem_file(data_file("rsa-multi.pem", Config)), PlainText = <<"I've Got a Lovely Bunch of Coconuts">>, Encrypted = jose_jwk:block_encrypt(PlainText, JWK), CompactEncrypted = jose_jwe:compact(Encrypted), {PlainText, _} = jose_jwk:block_decrypt(Encrypted, JWK), {PlainText, _} = jose_jwk:block_decrypt(CompactEncrypted, JWK), Message = <<"Secret Message">>, Signed = jose_jwk:sign(Message, JWK), CompactSigned = jose_jws:compact(Signed), {true, Message, _} = jose_jwk:verify(Signed, JWK), {true, Message, _} = jose_jwk:verify(CompactSigned, JWK), {_, Map} = jose_jwk:to_map(JWK), JWK = jose_jwk:from_map(Map), Password = <<"My Passphrase">>, PEM = element(2, jose_jwk:to_pem(JWK)), EncryptedPEM = element(2, jose_jwk:to_pem(Password, JWK)), JWK = jose_jwk:from_pem(PEM), JWK = jose_jwk:from_pem(Password, EncryptedPEM), JWK = jose_jwk:from_pem(jose_jwk:to_pem(JWK)), JWK = jose_jwk:from_pem(Password, jose_jwk:to_pem(Password, JWK)), {_, JWK} = jose_jwk:from_binary(Password, jose_jwk:to_binary(Password, JWK)), {_, JWK} = jose_jwk:from_binary(Password, jose_jwe:compact(jose_jwk:to_map(Password, JWK))), ok. % JSON Web Signature (JWS) % Appendix A.1. Example JWS Using HMAC SHA-256 % [https://tools.ietf.org/html/rfc7515#appendix-A.1] jws_a_1(Config) -> C = ?config(jws_a_1, Config), % A.1.1 A_1_1_JSON_DATA = ?config("a.1.1.jws+json", C), A_1_1_JSON = jose:decode(A_1_1_JSON_DATA), A_1_1_JWS = jose_jws:from_file(data_file("jws/a.1.1.jws+json", Config)), {_, A_1_1_JSON} = jose_jws:to_map(A_1_1_JWS), A_1_1_B64_DATA = ?config("a.1.1.b64", C), A_1_1_B64_DATA = jose_jwa_base64url:encode(A_1_1_JSON_DATA), A_1_1_PAYLOAD_DATA = ?config("a.1.1.payload", C), A_1_1_B64_PAYLOAD_DATA = ?config("a.1.1.payload-b64", C), A_1_1_B64_PAYLOAD_DATA = jose_jwa_base64url:encode(A_1_1_PAYLOAD_DATA), A_1_1_SIGNING_INPUT_DATA = ?config("a.1.1.signing-input", C), A_1_1_SIGNING_INPUT_DATA = << A_1_1_B64_DATA/binary, $., A_1_1_B64_PAYLOAD_DATA/binary >>, A_1_1_JWK = jose_jwk:from_file(data_file("jws/a.1.1.jwk+json", Config)), A_1_1_B64_SIGNATURE_DATA = ?config("a.1.1.signature-b64", C), %% Forcing the Protected header to be A_1_1_JSON_DATA A_1_1_MAP=#{ <<"signature">> := A_1_1_B64_SIGNATURE_DATA } = force_sign(A_1_1_JWK, A_1_1_PAYLOAD_DATA, A_1_1_JSON_DATA, A_1_1_JWS), A_1_1_COMPACT_DATA = ?config("a.1.1.compact", C), {_, A_1_1_COMPACT_DATA} = jose_jws:compact(A_1_1_MAP), % A.1.2 {true, A_1_1_PAYLOAD_DATA, A_1_1_JWS} = jose_jws:verify(A_1_1_JWK, A_1_1_MAP), {true, A_1_1_PAYLOAD_DATA, A_1_1_JWS} = jose_jws:verify(A_1_1_JWK, A_1_1_COMPACT_DATA), %% Sign and Verify {true, A_1_1_PAYLOAD_DATA, A_1_1_JWS} = jose_jwk:verify(jose_jwk:sign(A_1_1_PAYLOAD_DATA, A_1_1_JWS, A_1_1_JWK), A_1_1_JWK), ok. % JSON Web Signature (JWS) % Appendix A.2. Example JWS Using RSASSA-PKCS1-v1_5 SHA-256 % [https://tools.ietf.org/html/rfc7515#appendix-A.2] jws_a_2(Config) -> C = ?config(jws_a_2, Config), % A.2.1 A_2_1_JSON_DATA = ?config("a.2.1.jws+json", C), A_2_1_JSON = jose:decode(A_2_1_JSON_DATA), A_2_1_JWS = jose_jws:from_file(data_file("jws/a.2.1.jws+json", Config)), {_, A_2_1_JSON} = jose_jws:to_map(A_2_1_JWS), A_2_1_B64_DATA = ?config("a.2.1.b64", C), A_2_1_B64_DATA = jose_jwa_base64url:encode(A_2_1_JSON_DATA), A_2_1_PAYLOAD_DATA = ?config("a.2.1.payload", C), A_2_1_B64_PAYLOAD_DATA = ?config("a.2.1.payload-b64", C), A_2_1_B64_PAYLOAD_DATA = jose_jwa_base64url:encode(A_2_1_PAYLOAD_DATA), A_2_1_SIGNING_INPUT_DATA = ?config("a.2.1.signing-input", C), A_2_1_SIGNING_INPUT_DATA = << A_2_1_B64_DATA/binary, $., A_2_1_B64_PAYLOAD_DATA/binary >>, A_2_1_JWK = jose_jwk:from_file(data_file("jws/a.2.1.jwk+json", Config)), A_2_1_B64_SIGNATURE_DATA = ?config("a.2.1.signature-b64", C), %% Forcing the Protected header to be A_2_1_JSON_DATA A_2_1_MAP=#{ <<"signature">> := A_2_1_B64_SIGNATURE_DATA } = force_sign(A_2_1_JWK, A_2_1_PAYLOAD_DATA, A_2_1_JSON_DATA, A_2_1_JWS), A_2_1_COMPACT_DATA = ?config("a.2.1.compact", C), {_, A_2_1_COMPACT_DATA} = jose_jws:compact(A_2_1_MAP), % A.2.2 {true, A_2_1_PAYLOAD_DATA, A_2_1_JWS} = jose_jws:verify(A_2_1_JWK, A_2_1_MAP), {true, A_2_1_PAYLOAD_DATA, A_2_1_JWS} = jose_jws:verify(A_2_1_JWK, A_2_1_COMPACT_DATA), %% Sign and Verify {true, A_2_1_PAYLOAD_DATA, A_2_1_JWS} = jose_jwk:verify(jose_jwk:sign(A_2_1_PAYLOAD_DATA, A_2_1_JWS, A_2_1_JWK), A_2_1_JWK), ok. % JSON Web Signature (JWS) % Appendix A.3. Example JWS Using ECDSA P-256 SHA-256 % https://tools.ietf.org/html/rfc7515#appendix-A.3 jws_a_3(Config) -> C = ?config(jws_a_3, Config), % A.3.1 A_3_1_JSON_DATA = ?config("a.3.1.jws+json", C), A_3_1_JSON = jose:decode(A_3_1_JSON_DATA), A_3_1_JWS = jose_jws:from_file(data_file("jws/a.3.1.jws+json", Config)), {_, A_3_1_JSON} = jose_jws:to_map(A_3_1_JWS), A_3_1_B64_DATA = ?config("a.3.1.b64", C), A_3_1_B64_DATA = jose_jwa_base64url:encode(A_3_1_JSON_DATA), A_3_1_PAYLOAD_DATA = ?config("a.3.1.payload", C), A_3_1_B64_PAYLOAD_DATA = ?config("a.3.1.payload-b64", C), A_3_1_B64_PAYLOAD_DATA = jose_jwa_base64url:encode(A_3_1_PAYLOAD_DATA), A_3_1_SIGNING_INPUT_DATA = ?config("a.3.1.signing-input", C), A_3_1_SIGNING_INPUT_DATA = << A_3_1_B64_DATA/binary, $., A_3_1_B64_PAYLOAD_DATA/binary >>, A_3_1_JWK = jose_jwk:from_file(data_file("jws/a.3.1.jwk+json", Config)), A_3_1_B64_SIGNATURE_DATA = ?config("a.3.1.signature-b64", C), %% Forcing the Protected header to be A_3_1_JSON_DATA A_3_1_MAP=#{ <<"signature">> := A_3_1_B64_SIGNATURE_DATA_ALT } = force_sign(A_3_1_JWK, A_3_1_PAYLOAD_DATA, A_3_1_JSON_DATA, A_3_1_JWS), %% ECDSA produces non-matching signatures true = (A_3_1_B64_SIGNATURE_DATA =/= A_3_1_B64_SIGNATURE_DATA_ALT), A_3_1_COMPACT_DATA = ?config("a.3.1.compact", C), {_, A_3_1_COMPACT_DATA} = jose_jws:compact(A_3_1_MAP#{ <<"signature">> => A_3_1_B64_SIGNATURE_DATA }), % A.3.2 {true, A_3_1_PAYLOAD_DATA, A_3_1_JWS} = jose_jws:verify(A_3_1_JWK, A_3_1_MAP), {true, A_3_1_PAYLOAD_DATA, A_3_1_JWS} = jose_jws:verify(A_3_1_JWK, A_3_1_COMPACT_DATA), %% Sign and Verify {true, A_3_1_PAYLOAD_DATA, A_3_1_JWS} = jose_jwk:verify(jose_jwk:sign(A_3_1_PAYLOAD_DATA, A_3_1_JWS, A_3_1_JWK), A_3_1_JWK), ok. % JSON Web Signature (JWS) % Appendix A.4. Example JWS Using ECDSA P-521 SHA-512 % https://tools.ietf.org/html/rfc7515#appendix-A.4 jws_a_4(Config) -> C = ?config(jws_a_4, Config), % A.4.1 A_4_1_JSON_DATA = ?config("a.4.1.jws+json", C), A_4_1_JSON = jose:decode(A_4_1_JSON_DATA), A_4_1_JWS = jose_jws:from_file(data_file("jws/a.4.1.jws+json", Config)), {_, A_4_1_JSON} = jose_jws:to_map(A_4_1_JWS), A_4_1_B64_DATA = ?config("a.4.1.b64", C), A_4_1_B64_DATA = jose_jwa_base64url:encode(A_4_1_JSON_DATA), A_4_1_PAYLOAD_DATA = ?config("a.4.1.payload", C), A_4_1_B64_PAYLOAD_DATA = ?config("a.4.1.payload-b64", C), A_4_1_B64_PAYLOAD_DATA = jose_jwa_base64url:encode(A_4_1_PAYLOAD_DATA), A_4_1_SIGNING_INPUT_DATA = ?config("a.4.1.signing-input", C), A_4_1_SIGNING_INPUT_DATA = << A_4_1_B64_DATA/binary, $., A_4_1_B64_PAYLOAD_DATA/binary >>, A_4_1_JWK = jose_jwk:from_file(data_file("jws/a.4.1.jwk+json", Config)), A_4_1_B64_SIGNATURE_DATA = ?config("a.4.1.signature-b64", C), %% Forcing the Protected header to be A_4_1_JSON_DATA A_4_1_MAP=#{ <<"signature">> := A_4_1_B64_SIGNATURE_DATA_ALT } = force_sign(A_4_1_JWK, A_4_1_PAYLOAD_DATA, A_4_1_JSON_DATA, A_4_1_JWS), %% ECDSA produces non-matching signatures true = (A_4_1_B64_SIGNATURE_DATA =/= A_4_1_B64_SIGNATURE_DATA_ALT), A_4_1_COMPACT_DATA = ?config("a.4.1.compact", C), {_, A_4_1_COMPACT_DATA} = jose_jws:compact(A_4_1_MAP#{ <<"signature">> => A_4_1_B64_SIGNATURE_DATA }), % A.4.2 {true, A_4_1_PAYLOAD_DATA, A_4_1_JWS} = jose_jws:verify(A_4_1_JWK, A_4_1_MAP), {true, A_4_1_PAYLOAD_DATA, A_4_1_JWS} = jose_jws:verify(A_4_1_JWK, A_4_1_COMPACT_DATA), %% Sign and Verify {true, A_4_1_PAYLOAD_DATA, A_4_1_JWS} = jose_jwk:verify(jose_jwk:sign(A_4_1_PAYLOAD_DATA, A_4_1_JWS, A_4_1_JWK), A_4_1_JWK), ok. % JSON Web Signature (JWS) % Appendix A.5. Example Unsecured JWS % https://tools.ietf.org/html/rfc7515#appendix-A.5 jws_a_5(Config) -> C = ?config(jws_a_5, Config), % A.5 A_5_JSON_DATA = ?config("a.5.jws+json", C), A_5_JSON = jose:decode(A_5_JSON_DATA), A_5_JWS = jose_jws:from_file(data_file("jws/a.5.jws+json", Config)), {_, A_5_JSON} = jose_jws:to_map(A_5_JWS), A_5_B64_DATA = ?config("a.5.b64", C), A_5_B64_DATA = jose_jwa_base64url:encode(A_5_JSON_DATA), A_5_PAYLOAD_DATA = ?config("a.5.payload", C), A_5_B64_PAYLOAD_DATA = ?config("a.5.payload-b64", C), A_5_B64_PAYLOAD_DATA = jose_jwa_base64url:encode(A_5_PAYLOAD_DATA), A_5_SIGNING_INPUT_DATA = ?config("a.5.signing-input", C), A_5_SIGNING_INPUT_DATA = << A_5_B64_DATA/binary, $., A_5_B64_PAYLOAD_DATA/binary >>, %% Forcing the Protected header to be A_5_JSON_DATA A_5_MAP=#{ <<"signature">> := <<>> } = force_sign(none, A_5_PAYLOAD_DATA, A_5_JSON_DATA, A_5_JWS), A_5_COMPACT_DATA = ?config("a.5.compact", C), {_, A_5_COMPACT_DATA} = jose_jws:compact(A_5_MAP), {true, A_5_PAYLOAD_DATA, A_5_JWS} = jose_jws:verify(none, A_5_MAP), {true, A_5_PAYLOAD_DATA, A_5_JWS} = jose_jws:verify(none, A_5_COMPACT_DATA), %% Sign and Verify {true, A_5_PAYLOAD_DATA, A_5_JWS} = jose_jws:verify(none, jose_jws:sign(none, A_5_PAYLOAD_DATA, A_5_JWS)), ok. % Examples of Protecting Content Using JSON Object Signing and Encryption (JOSE) % 5.9. Compressed Content % https://tools.ietf.org/html/rfc7520#section-5.9 rfc7520_5_9(Config) -> C = ?config(rfc7520_5_9, Config), % 5.9.1 V_5_9_1_PLAIN_TEXT = ?config("figure.72", C), V_5_9_1_JWK = jose_jwk:from_binary(?config("figure.151", C)), % 5.9.2 V_5_9_2_COMPRESSED_PLAIN_TEXT = ?config("figure.162", C), V_5_9_1_PLAIN_TEXT = jose_jwe_zip:uncompress(jose_jwa_base64url:decode(V_5_9_2_COMPRESSED_PLAIN_TEXT), zlib), V_5_9_2_COMPRESSED_PLAIN_TEXT = jose_jwa_base64url:encode(jose_jwe_zip:compress(V_5_9_1_PLAIN_TEXT, zlib)), V_5_9_2_CEK = ?config("figure.163", C), V_5_9_2_IV = ?config("figure.164", C), % 5.9.3 V_5_9_3_ENCRYPTED_KEY = ?config("figure.165", C), {ALG, _} = jose_jwe_alg_aes_kw:from_map(#{<<"alg">> => <<"A128KW">>}), V_5_9_3_ENCRYPTED_KEY = jose_jwa_base64url:encode(element(1, jose_jwe_alg_aes_kw:key_encrypt(V_5_9_1_JWK, jose_jwa_base64url:decode(V_5_9_2_CEK), ALG))), V_5_9_2_CEK = jose_jwa_base64url:encode(jose_jwe_alg_aes_kw:key_decrypt(V_5_9_1_JWK, {undefined, undefined, jose_jwa_base64url:decode(V_5_9_3_ENCRYPTED_KEY)}, ALG)), % 5.9.4 V_5_9_4_JWE = jose_jwe:from_binary(?config("figure.166", C)), V_5_9_4_JWE_PROTECTED = ?config("figure.167", C), V_5_9_4_JWE = jose_jwe:from_binary(jose_jwa_base64url:decode(V_5_9_4_JWE_PROTECTED)), V_5_9_4_CIPHER_TEXT = ?config("figure.168", C), V_5_9_4_CIPHER_TAG = ?config("figure.169", C), % 5.9.5 V_5_9_5_JWE_COMPACT = ?config("figure.170", C), V_5_9_5_JWE_MAP = jose:decode(?config("figure.172", C)), V_5_9_4_CIPHER_TEXT = maps:get(<<"ciphertext">>, V_5_9_5_JWE_MAP), V_5_9_4_CIPHER_TAG = maps:get(<<"tag">>, V_5_9_5_JWE_MAP), {V_5_9_1_PLAIN_TEXT, V_5_9_4_JWE} = jose_jwe:block_decrypt(V_5_9_1_JWK, V_5_9_5_JWE_COMPACT), {V_5_9_1_PLAIN_TEXT, V_5_9_4_JWE} = jose_jwe:block_decrypt(V_5_9_1_JWK, V_5_9_5_JWE_MAP), % Roundtrip test {_, CIPHER_TEXT} = jose_jwe:compact(jose_jwe:block_encrypt(V_5_9_1_JWK, V_5_9_1_PLAIN_TEXT, jose_jwa_base64url:decode(V_5_9_2_CEK), jose_jwa_base64url:decode(V_5_9_2_IV), V_5_9_4_JWE)), {V_5_9_1_PLAIN_TEXT, V_5_9_4_JWE} = jose_jwe:block_decrypt(V_5_9_1_JWK, CIPHER_TEXT), ok. %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- %% @private force_block_encrypt(Key, PlainText, CEK, IV, OverrideProtected, JWE=#jose_jwe{alg={ALGModule, ALG}, enc={ENCModule, ENC}}) -> {EncryptedKey, _} = ALGModule:key_encrypt(Key, CEK, ALG), Protected = jose_jwa_base64url:encode(OverrideProtected), {CipherText, CipherTag} = ENCModule:block_encrypt({Protected, maybe_compress(PlainText, JWE)}, CEK, IV, ENC), #{ <<"protected">> => Protected, <<"encrypted_key">> => jose_jwa_base64url:encode(EncryptedKey), <<"iv">> => jose_jwa_base64url:encode(IV), <<"ciphertext">> => jose_jwa_base64url:encode(CipherText), <<"tag">> => jose_jwa_base64url:encode(CipherTag) }. %% @private force_sign(Key, PlainText, OverrideProtected, #jose_jws{alg={ALGModule, ALG}}) -> Protected = jose_jwa_base64url:encode(OverrideProtected), Payload = jose_jwa_base64url:encode(PlainText), Message = << Protected/binary, $., Payload/binary >>, Signature = jose_jwa_base64url:encode(ALGModule:sign(Key, Message, ALG)), #{ <<"payload">> => Payload, <<"protected">> => Protected, <<"signature">> => Signature }. %% @private data_file(File, Config) -> filename:join([?config(data_dir, Config), File]). %% @private maybe_compress(PlainText, #jose_jwe{zip={Module, ZIP}}) -> Module:compress(PlainText, ZIP); maybe_compress(PlainText, _) -> PlainText. erlang-jose-1.10.1/test/property_test/0000755000232200023220000000000013605433351020253 5ustar debalancedebalanceerlang-jose-1.10.1/test/property_test/jose_jwk_set_props.erl0000644000232200023220000000450013605433351024667 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_set_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). modulus_size() -> integer(1024, 1280). % integer(256, 8192) | pos_integer(). exponent_size() -> return(65537). % pos_integer(). rsa_keypair(ModulusSize) -> ?LET(ExponentSize, exponent_size(), begin case public_key:generate_key({rsa, ModulusSize, ExponentSize}) of PrivateKey=#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent} -> {PrivateKey, #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}} end end). ec_curve() -> oneof([ secp256r1, secp384r1, secp521r1 ]). ec_keypair(CurveId) -> ECPrivateKey = #'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0} = public_key:generate_key({namedCurve, pubkey_cert_records:namedCurves(CurveId)}), Octets = case Octets0 of {_, Octets1} -> Octets1; _ -> Octets0 end, ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, {ECPrivateKey, ECPublicKey}. jwk_ec() -> ?LET(CurveId, ec_curve(), begin {PrivateKey, PublicKey} = ec_keypair(CurveId), oneof([jose_jwk:from_key(PrivateKey), jose_jwk:from_key(PublicKey)]) end). jwk_hmac() -> ?LET(Key, binary(), jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) })). jwk_rsa() -> ?LET({_ModulusSize, {PrivateKey, PublicKey}}, ?LET(ModulusSize, modulus_size(), {ModulusSize, rsa_keypair(ModulusSize)}), oneof([jose_jwk:from_key(PrivateKey), jose_jwk:from_key(PublicKey)])). jwk() -> oneof([ jwk_ec(), jwk_hmac(), jwk_rsa() ]). jwk_set_map() -> ?LET(JWKs, list(jwk()), begin {JWKs, #{ <<"keys">> => [element(2, jose_jwk:to_map(JWK)) || JWK <- JWKs] }} end). prop_from_map_and_to_map() -> ?FORALL({_JWKs, JWKSetMap}, ?LET({{JWKs, JWKSetMap}, Extras}, {jwk_set_map(), binary_map()}, {JWKs, maps:merge(Extras, JWKSetMap)}), begin JWKSet = jose_jwk:from_map(JWKSetMap), JWKSetMap =:= element(2, jose_jwk:to_map(JWKSet)) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_okp_ed448_props.erl0000644000232200023220000000772213605433351026475 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_okp_ed448_props). -include("jose_public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). ed448_secret() -> binary(57). ed448_keypair(Secret) -> {PK, << S:57/binary, _:57/binary >>} = jose_curve448:eddsa_keypair(Secret), PublicKey = #'jose_EdDSA448PublicKey'{publicKey=PK}, SecretKey = #'jose_EdDSA448PrivateKey'{publicKey=PublicKey, privateKey=S}, {SecretKey, PublicKey}. jwk_map() -> ?LET({AliceSecret, BobSecret}, {ed448_secret(), ed448_secret()}, begin AliceKeys = {AlicePrivateKey, _} = ed448_keypair(AliceSecret), BobKeys = ed448_keypair(BobSecret), AlicePrivateJWK = jose_jwk:from_key(AlicePrivateKey), {_, AlicePrivateJWKMap} = jose_jwk:to_map(AlicePrivateJWK), Keys = {AliceKeys, BobKeys}, {Keys, AlicePrivateJWKMap} end). jwk_gen() -> ?LET({Keys, AlicePrivateJWKMap}, jwk_map(), {Keys, jose_jwk:from_map(AlicePrivateJWKMap)}). prop_from_der_and_to_der() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivateDER = element(2, jose_jwk:to_der(AlicePrivateJWK)), EncryptedAlicePrivateDER = element(2, jose_jwk:to_der(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicDER = element(2, jose_jwk:to_der(AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_der(AlicePrivateDER) andalso AlicePrivateJWK =:= jose_jwk:from_der(Password, EncryptedAlicePrivateDER) andalso AlicePublicJWK =:= jose_jwk:from_der(AlicePublicDER) end). prop_from_map_and_to_map() -> ?FORALL({{{AlicePrivateKey, AlicePublicKey}, _}, AlicePrivateJWKMap}, ?LET({{Keys, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Keys, maps:merge(Extras, JWKMap)}), begin AlicePrivateJWK = jose_jwk:from_map(AlicePrivateJWKMap), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicJWKMap = element(2, jose_jwk:to_map(AlicePublicJWK)), AlicePublicThumbprint = jose_jwk:thumbprint(AlicePublicJWK), AlicePrivateJWKMap =:= element(2, jose_jwk:to_map(AlicePrivateJWK)) andalso AlicePrivateKey =:= element(2, jose_jwk:to_key(AlicePrivateJWK)) andalso AlicePublicKey =:= element(2, jose_jwk:to_public_key(AlicePrivateJWK)) andalso AlicePublicJWKMap =:= element(2, jose_jwk:to_public_map(AlicePrivateJWK)) andalso AlicePublicThumbprint =:= jose_jwk:thumbprint(AlicePrivateJWK) end). prop_from_pem_and_to_pem() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivatePEM = element(2, jose_jwk:to_pem(AlicePrivateJWK)), EncryptedAlicePrivatePEM = element(2, jose_jwk:to_pem(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicPEM = element(2, jose_jwk:to_pem(AlicePublicJWK)), EncryptedAlicePublicPEM = element(2, jose_jwk:to_pem(Password, AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_pem(AlicePrivatePEM) andalso AlicePrivateJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePrivatePEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(AlicePublicPEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePublicPEM) end). prop_sign_and_verify() -> ?FORALL({_Keys, JWK, Message}, ?LET({Keys, JWK}, jwk_gen(), {Keys, JWK, binary()}), begin Signed = jose_jwk:sign(Message, JWK), CompactSigned = jose_jws:compact(Signed), Verified = {_, _, JWS} = jose_jwk:verify(Signed, JWK), {true, Message, JWS} =:= Verified andalso {true, Message, JWS} =:= jose_jwk:verify(CompactSigned, JWK) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_okp_ed25519ph_props.erl0000644000232200023220000000447613605433351027176 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_okp_ed25519ph_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). ed25519ph_secret() -> binary(32). ed25519ph_keypair(Secret) -> {PK, SK} = jose_curve25519:eddsa_keypair(Secret), {SK, PK}. jwk_map() -> ?LET({AliceSecret, BobSecret}, {ed25519ph_secret(), ed25519ph_secret()}, begin AliceKeys = {AlicePrivateKey, _} = ed25519ph_keypair(AliceSecret), BobKeys = ed25519ph_keypair(BobSecret), AlicePrivateJWK = jose_jwk:from_okp({'Ed25519ph', AlicePrivateKey}), {_, AlicePrivateJWKMap} = jose_jwk:to_map(AlicePrivateJWK), Keys = {AliceKeys, BobKeys}, {Keys, AlicePrivateJWKMap} end). jwk_gen() -> ?LET({Keys, AlicePrivateJWKMap}, jwk_map(), {Keys, jose_jwk:from_map(AlicePrivateJWKMap)}). prop_from_map_and_to_map() -> ?FORALL({{{AlicePrivateKey, AlicePublicKey}, _}, AlicePrivateJWKMap}, ?LET({{Keys, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Keys, maps:merge(Extras, JWKMap)}), begin AlicePrivateJWK = jose_jwk:from_map(AlicePrivateJWKMap), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicJWKMap = element(2, jose_jwk:to_map(AlicePublicJWK)), AlicePublicThumbprint = jose_jwk:thumbprint(AlicePublicJWK), AlicePrivateJWKMap =:= element(2, jose_jwk:to_map(AlicePrivateJWK)) andalso AlicePrivateKey =:= element(2, jose_jwk:to_key(AlicePrivateJWK)) andalso AlicePublicKey =:= element(2, jose_jwk:to_public_key(AlicePrivateJWK)) andalso AlicePublicJWKMap =:= element(2, jose_jwk:to_public_map(AlicePrivateJWK)) andalso AlicePublicThumbprint =:= jose_jwk:thumbprint(AlicePrivateJWK) end). prop_sign_and_verify() -> ?FORALL({_Keys, JWK, Message}, ?LET({Keys, JWK}, jwk_gen(), {Keys, JWK, binary()}), begin Signed = jose_jwk:sign(Message, JWK), CompactSigned = jose_jws:compact(Signed), Verified = {_, _, JWS} = jose_jwk:verify(Signed, JWK), {true, Message, JWS} =:= Verified andalso {true, Message, JWS} =:= jose_jwk:verify(CompactSigned, JWK) end). erlang-jose-1.10.1/test/property_test/jose_jwe_alg_pbes2_props.erl0000644000232200023220000000356513605433351025736 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_alg_pbes2_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> oneof([ <<"PBES2-HS256+A128GCMKW">>, <<"PBES2-HS384+A192GCMKW">>, <<"PBES2-HS512+A256GCMKW">>, <<"PBES2-HS256+A128KW">>, <<"PBES2-HS384+A192KW">>, <<"PBES2-HS512+A256KW">>, <<"PBES2-HS512+C20PKW">>, <<"PBES2-HS512+XC20PKW">> ]). alg_map() -> ?LET({ALG, P2C, P2S}, {alg(), integer(1, 256), binary()}, #{ <<"alg">> => ALG, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }). enc() -> oneof([ <<"A128GCM">>, <<"A192GCM">>, <<"A256GCM">> ]). jwk_jwe_maps() -> ?LET({ALGMap, ENC, Password}, {alg_map(), enc(), binary()}, begin JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Password) }, JWEMap = maps:merge(#{ <<"enc">> => ENC }, ALGMap), {Password, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_Key, _JWKMap, JWEMap}, Extras}, {jwk_jwe_maps(), binary_map()}, maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_key_encrypt_and_key_decrypt() -> ?FORALL({_Key, JWK, JWE}, ?LET({Key, JWK, JWE}, jwk_jwe_gen(), {Key, oneof([Key, JWK]), JWE}), begin {DecKey, DecJWE} = jose_jwe:next_cek(JWK, JWE), {EncKey, EncJWE} = jose_jwe:key_encrypt(JWK, DecKey, DecJWE), DecKey =:= jose_jwe:key_decrypt(JWK, EncKey, EncJWE) end). erlang-jose-1.10.1/test/property_test/jose_jwe_enc_c20p_props.erl0000644000232200023220000000276413605433351025471 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_enc_c20p_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). enc() -> return(<<"C20P">>). jwk_jwe_maps() -> ?LET(ENC, enc(), begin JWEMap = #{ <<"alg">> => <<"dir">>, <<"enc">> => ENC }, Key = element(2, jose_jwk:to_oct(jose_jwe:generate_key(JWEMap))), JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, {Key, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_Key, _JWKMap, JWEMap}, Extras}, {jwk_jwe_maps(), binary_map()}, maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_block_encrypt_and_block_decrypt() -> ?FORALL({CEK, IV, JWK, JWE, PlainText}, ?LET({CEK, JWK, JWE}, jwk_jwe_gen(), {CEK, jose_jwe:next_iv(JWE), JWK, JWE, binary()}), begin Encrypted = jose_jwe:block_encrypt(JWK, PlainText, CEK, IV, JWE), CompactEncrypted = jose_jwe:compact(Encrypted), PlainText =:= element(1, jose_jwe:block_decrypt(JWK, CompactEncrypted)) end). erlang-jose-1.10.1/test/property_test/jose_jwe_alg_ecdh_1pu_props.erl0000644000232200023220000000727313605433351026413 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_alg_ecdh_1pu_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> oneof([ <<"ECDH-1PU">>, <<"ECDH-1PU+A128GCMKW">>, <<"ECDH-1PU+A192GCMKW">>, <<"ECDH-1PU+A256GCMKW">>, <<"ECDH-1PU+A128KW">>, <<"ECDH-1PU+A192KW">>, <<"ECDH-1PU+A256KW">>, <<"ECDH-1PU+C20PKW">>, <<"ECDH-1PU+XC20PKW">> ]). alg_map() -> ?LET({ALG, APU, APV}, {alg(), binary(), binary()}, #{ <<"alg">> => ALG, <<"apu">> => jose_jwa_base64url:encode(APU), <<"apv">> => jose_jwa_base64url:encode(APV) }). ec_curve() -> oneof([ secp256r1, secp384r1, secp521r1, x25519, x448 ]). % ec_curve() -> % ?SUCHTHAT(CurveId, % oneof(crypto:ec_curves()), % begin % try pubkey_cert_records:namedCurves(CurveId) of % Curve when is_tuple(Curve) -> % true; % _ -> % false % catch % _:_ -> % false % end % end). % ec_keypair() -> % ?LET(CurveId, % ec_curve(), % ec_keypair(CurveId)). ec_keypair(x25519) -> SecretJWK = jose_jwk:generate_key({okp, 'X25519'}), {_, SecretKey} = jose_jwk:to_key(SecretJWK), {_, PublicKey} = jose_jwk:to_public_key(SecretJWK), {SecretKey, PublicKey}; ec_keypair(x448) -> SecretJWK = jose_jwk:generate_key({okp, 'X448'}), {_, SecretKey} = jose_jwk:to_key(SecretJWK), {_, PublicKey} = jose_jwk:to_public_key(SecretJWK), {SecretKey, PublicKey}; ec_keypair(CurveId) -> ECPrivateKey = #'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0} = public_key:generate_key({namedCurve, pubkey_cert_records:namedCurves(CurveId)}), Octets = case Octets0 of {_, Octets1} -> Octets1; _ -> Octets0 end, ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, {ECPrivateKey, ECPublicKey}. enc() -> oneof([ <<"A128GCM">>, <<"A192GCM">>, <<"A256GCM">>, <<"C20P">>, <<"XC20P">> ]). jwk_jwe_maps() -> ?LET({ALGMap, ENC, {VStaticSecret, VStaticPublic}, {UStaticSecret, UStaticPublic}, {UEphemeralSecret, UEphemeralPublic}}, ?LET(CurveId, ec_curve(), {alg_map(), enc(), ec_keypair(CurveId), ec_keypair(CurveId), ec_keypair(CurveId)}), begin VStaticSecretKey = jose_jwk:from_key(VStaticSecret), VStaticPublicKey = jose_jwk:from_key(VStaticPublic), UStaticSecretKey = jose_jwk:from_key(UStaticSecret), UStaticPublicKey = jose_jwk:from_key(UStaticPublic), UEphemeralSecretKey = jose_jwk:from_key(UEphemeralSecret), UEphemeralPublicKey = jose_jwk:from_key(UEphemeralPublic), {_, UEphemeralPublicKeyMap} = jose_jwk:to_public_map(UEphemeralPublicKey), VBox = {UStaticPublicKey, VStaticSecretKey}, UBox = {VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey}, JWKs = {VBox, UBox}, JWEMap = maps:merge(#{ <<"enc">> => ENC, <<"epk">> => UEphemeralPublicKeyMap }, ALGMap), {JWKs, JWEMap} end). jwk_jwe_gen() -> ?LET({JWKs, JWEMap}, jwk_jwe_maps(), {JWKs, jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_JWKs, JWEMap}, Extras}, {jwk_jwe_maps(), binary_map()}, maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_key_encrypt_and_key_decrypt() -> ?FORALL({{VBox, UBox}, JWE}, jwk_jwe_gen(), begin {DecKey, DecJWE} = jose_jwe:next_cek(UBox, JWE), {EncKey, EncJWE} = jose_jwe:key_encrypt(UBox, DecKey, DecJWE), DecKey =:= jose_jwe:key_decrypt(VBox, EncKey, EncJWE) end). erlang-jose-1.10.1/test/property_test/jose_jwa_aes_props.erl0000644000232200023220000000725413605433351024643 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_aes_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). block_size() -> oneof([128, 192, 256]). cbc_iv() -> binary(16). gcm_iv() -> binary(12). cbc_block_encryptor_gen() -> ?LET({Bits, IV, PlainText}, {block_size(), cbc_iv(), binary()}, {Bits, binary(Bits div 8), IV, jose_jwa_pkcs7:pad(PlainText)}). ecb_block_encryptor_gen() -> ?LET({Bits, PlainText}, {block_size(), binary()}, {Bits, binary(Bits div 8), jose_jwa_pkcs7:pad(PlainText)}). gcm_block_encryptor_gen() -> ?LET({Bits, IV, AAD, PlainText}, {block_size(), gcm_iv(), binary(), binary()}, {Bits, binary(Bits div 8), IV, AAD, jose_jwa_pkcs7:pad(PlainText)}). prop_cbc_block_encrypt_and_cbc_block_decrypt() -> ?FORALL({Bits, Key, IV, PlainText}, cbc_block_encryptor_gen(), begin CipherText = jose_jwa_aes:block_encrypt({aes_cbc, Bits}, Key, IV, PlainText), PlainText =:= jose_jwa_aes:block_decrypt({aes_cbc, Bits}, Key, IV, CipherText) end). prop_cbc_block_encrypt_and_jwa_block_decrypt() -> ?FORALL({Bits, Key, IV, PlainText}, cbc_block_encryptor_gen(), begin Cipher = aes_cbc, CipherText = jose_jwa_aes:block_encrypt({Cipher, Bits}, Key, IV, PlainText), PlainText =:= jose_jwa:block_decrypt({Cipher, Bits}, Key, IV, CipherText) end). prop_jwa_block_encrypt_and_cbc_block_decrypt() -> ?FORALL({Bits, Key, IV, PlainText}, cbc_block_encryptor_gen(), begin Cipher = aes_cbc, CipherText = jose_jwa:block_encrypt({Cipher, Bits}, Key, IV, PlainText), PlainText =:= jose_jwa_aes:block_decrypt({Cipher, Bits}, Key, IV, CipherText) end). prop_jwa_block_encrypt_and_ecb_block_decrypt() -> ?FORALL({Bits, Key, PlainText}, ecb_block_encryptor_gen(), begin Cipher = aes_ecb, CipherText = << << (jose_jwa:block_encrypt({Cipher, Bits}, Key, Block))/binary >> || << Block:16/binary >> <= PlainText >>, PlainText =:= jose_jwa_aes:block_decrypt({aes_ecb, Bits}, Key, CipherText) end). prop_jwa_block_encrypt_and_gcm_block_decrypt() -> ?FORALL({Bits, Key, IV, AAD, PlainText}, gcm_block_encryptor_gen(), begin Cipher = aes_gcm, {CipherText, CipherTag} = jose_jwa:block_encrypt({Cipher, Bits}, Key, IV, {AAD, PlainText}), PlainText =:= jose_jwa_aes:block_decrypt({aes_gcm, Bits}, Key, IV, {AAD, CipherText, CipherTag}) end). prop_ecb_block_encrypt_and_ecb_block_decrypt() -> ?FORALL({Bits, Key, PlainText}, ecb_block_encryptor_gen(), begin CipherText = jose_jwa_aes:block_encrypt({aes_ecb, Bits}, Key, PlainText), PlainText =:= jose_jwa_aes:block_decrypt({aes_ecb, Bits}, Key, CipherText) end). prop_ecb_block_encrypt_and_jwa_block_decrypt() -> ?FORALL({Bits, Key, PlainText}, ecb_block_encryptor_gen(), begin CipherText = jose_jwa_aes:block_encrypt({aes_ecb, Bits}, Key, PlainText), Cipher = aes_ecb, PlainText =:= << << (jose_jwa:block_decrypt({Cipher, Bits}, Key, Block))/binary >> || << Block:16/binary >> <= CipherText >> end). prop_gcm_block_encrypt_and_gcm_block_decrypt() -> ?FORALL({Bits, Key, IV, AAD, PlainText}, gcm_block_encryptor_gen(), begin {CipherText, CipherTag} = jose_jwa_aes:block_encrypt({aes_gcm, Bits}, Key, IV, {AAD, PlainText}), PlainText =:= jose_jwa_aes:block_decrypt({aes_gcm, Bits}, Key, IV, {AAD, CipherText, CipherTag}) end). prop_gcm_block_encrypt_and_jwa_block_decrypt() -> ?FORALL({Bits, Key, IV, AAD, PlainText}, gcm_block_encryptor_gen(), begin {CipherText, CipherTag} = jose_jwa_aes:block_encrypt({aes_gcm, Bits}, Key, IV, {AAD, PlainText}), Cipher = aes_gcm, PlainText =:= jose_jwa:block_decrypt({Cipher, Bits}, Key, IV, {AAD, CipherText, CipherTag}) end). erlang-jose-1.10.1/test/property_test/jose_jwa_curve448_props.erl0000644000232200023220000000334713605433351025456 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_curve448_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). eddsa_secret() -> binary(57). eddsa_keypair(Secret) -> {PK, SK} = jose_curve448:eddsa_keypair(Secret), {SK, PK}. x448_secret() -> binary(56). x448_keypair(Secret) -> {PK, SK} = jose_curve448:x448_keypair(Secret), {SK, PK}. eddsa_keypair_gen() -> ?LET(Secret, eddsa_secret(), eddsa_keypair(Secret)). prop_eddsa_secret_to_public() -> ?FORALL({<< Secret:57/binary, _/binary >>, PK}, eddsa_keypair_gen(), begin PK =:= jose_jwa_curve448:eddsa_secret_to_public(Secret) end). prop_ed448_sign_and_verify() -> ?FORALL({{SK, PK}, M}, {eddsa_keypair_gen(), binary()}, begin S = jose_jwa_curve448:ed448_sign(M, SK), jose_jwa_curve448:ed448_verify(S, M, PK) end). prop_ed448ph_sign_and_verify() -> ?FORALL({{SK, PK}, M}, {eddsa_keypair_gen(), binary()}, begin S = jose_jwa_curve448:ed448ph_sign(M, SK), jose_jwa_curve448:ed448ph_verify(S, M, PK) end). x448_keypair_gen() -> ?LET(Secret, x448_secret(), x448_keypair(Secret)). x448_keypairs_gen() -> ?LET({AliceSecret, BobSecret}, {x448_secret(), x448_secret()}, {x448_keypair(AliceSecret), x448_keypair(BobSecret)}). prop_x448_secret_to_public() -> ?FORALL({SK, PK}, x448_keypair_gen(), begin PK =:= jose_jwa_curve448:x448_secret_to_public(SK) end). prop_x448_shared_secret() -> ?FORALL({{AliceSK, AlicePK}, {BobSK, BobPK}}, x448_keypairs_gen(), begin K = jose_jwa_curve448:x448_shared_secret(AliceSK, BobPK), K =:= jose_jwa_curve448:x448_shared_secret(BobSK, AlicePK) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_okp_x448_props.erl0000644000232200023220000001017313605433351026346 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_okp_x448_props). -include("jose_public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). x448_secret() -> binary(56). x448_keypair(Secret) -> {PK, S} = jose_curve448:x448_keypair(Secret), PublicKey = #'jose_X448PublicKey'{publicKey=PK}, SecretKey = #'jose_X448PrivateKey'{publicKey=PublicKey, privateKey=S}, {SecretKey, PublicKey}. jwk_map() -> ?LET({AliceSecret, BobSecret}, {x448_secret(), x448_secret()}, begin AliceKeys = {AlicePrivateKey, _} = x448_keypair(AliceSecret), BobKeys = x448_keypair(BobSecret), AlicePrivateJWK = jose_jwk:from_key(AlicePrivateKey), {_, AlicePrivateJWKMap} = jose_jwk:to_map(AlicePrivateJWK), Keys = {AliceKeys, BobKeys}, {Keys, AlicePrivateJWKMap} end). jwk_gen() -> ?LET({Keys, AlicePrivateJWKMap}, jwk_map(), {Keys, jose_jwk:from_map(AlicePrivateJWKMap)}). prop_from_der_and_to_der() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivateDER = element(2, jose_jwk:to_der(AlicePrivateJWK)), EncryptedAlicePrivateDER = element(2, jose_jwk:to_der(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicDER = element(2, jose_jwk:to_der(AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_der(AlicePrivateDER) andalso AlicePrivateJWK =:= jose_jwk:from_der(Password, EncryptedAlicePrivateDER) andalso AlicePublicJWK =:= jose_jwk:from_der(AlicePublicDER) end). prop_from_map_and_to_map() -> ?FORALL({{{AlicePrivateKey, AlicePublicKey}, _}, AlicePrivateJWKMap}, ?LET({{Keys, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Keys, maps:merge(Extras, JWKMap)}), begin AlicePrivateJWK = jose_jwk:from_map(AlicePrivateJWKMap), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicJWKMap = element(2, jose_jwk:to_map(AlicePublicJWK)), AlicePublicThumbprint = jose_jwk:thumbprint(AlicePublicJWK), AlicePrivateJWKMap =:= element(2, jose_jwk:to_map(AlicePrivateJWK)) andalso AlicePrivateKey =:= element(2, jose_jwk:to_key(AlicePrivateJWK)) andalso AlicePublicKey =:= element(2, jose_jwk:to_public_key(AlicePrivateJWK)) andalso AlicePublicJWKMap =:= element(2, jose_jwk:to_public_map(AlicePrivateJWK)) andalso AlicePublicThumbprint =:= jose_jwk:thumbprint(AlicePrivateJWK) end). prop_from_pem_and_to_pem() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivatePEM = element(2, jose_jwk:to_pem(AlicePrivateJWK)), EncryptedAlicePrivatePEM = element(2, jose_jwk:to_pem(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicPEM = element(2, jose_jwk:to_pem(AlicePublicJWK)), EncryptedAlicePublicPEM = element(2, jose_jwk:to_pem(Password, AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_pem(AlicePrivatePEM) andalso AlicePrivateJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePrivatePEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(AlicePublicPEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePublicPEM) end). prop_box_encrypt_and_box_decrypt() -> ?FORALL({{{_, {BobPrivateKey, BobPublicKey}}, AlicePrivateJWK}, PlainText}, {jwk_gen(), binary()}, begin BobPrivateJWK = jose_jwk:from_key(BobPrivateKey), BobPublicJWK = jose_jwk:from_key(BobPublicKey), Encrypted = jose_jwk:box_encrypt_ecdh_es(PlainText, BobPublicJWK, AlicePrivateJWK), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, JWE} = jose_jwk:box_decrypt_ecdh_es(Encrypted, BobPrivateJWK), {PlainText, JWE} =:= Decrypted andalso {PlainText, JWE} =:= jose_jwk:block_decrypt(CompactEncrypted, BobPrivateJWK) end). erlang-jose-1.10.1/test/property_test/jose_jws_alg_poly1305_props.erl0000644000232200023220000000412713605433351026230 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jws_alg_poly1305_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> return(<<"Poly1305">>). jwk_jws_maps() -> ?LET({ALG, Key, Nonce}, {alg(), binary(32), binary(12)}, begin JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWSMap = #{ <<"alg">> => ALG }, NonceJWSMap = #{ <<"alg">> => ALG, <<"nonce">> => jose_jwa_base64url:encode(Nonce) }, {Key, JWKMap, JWSMap, NonceJWSMap} end). jwk_jws_gen() -> ?LET({Key, JWKMap, JWSMap, NonceJWSMap}, jwk_jws_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jws:from_map(JWSMap), jose_jws:from_map(NonceJWSMap)}). prop_from_map_and_to_map() -> ?FORALL({JWSMap, NonceJWSMap}, ?LET({{_Key, _JWKMap, JWSMap, NonceJWSMap}, Extras}, {jwk_jws_maps(), binary_map()}, {maps:merge(Extras, JWSMap), maps:merge(Extras, NonceJWSMap)}), begin JWS = jose_jws:from_map(JWSMap), NonceJWS = jose_jws:from_map(NonceJWSMap), JWSMap == element(2, jose_jws:to_map(JWS)) andalso NonceJWSMap == element(2, jose_jws:to_map(NonceJWS)) end). prop_sign_and_verify() -> ?FORALL({{_Key, JWK, JWS, NonceJWS}, Message}, {jwk_jws_gen(), binary()}, begin NonceSigned = jose_jws:sign(JWK, Message, NonceJWS), NonceCompactSigned = jose_jws:compact(NonceSigned), Signed = jose_jws:sign(JWK, Message, JWS), CompactSigned = jose_jws:compact(Signed), {true, Message, NonceJWS} == jose_jws:verify(JWK, NonceSigned) andalso {true, Message, NonceJWS} == jose_jws:verify(JWK, NonceCompactSigned) andalso true == element(1, jose_jws:verify(JWK, Signed)) andalso true == element(1, jose_jws:verify(JWK, CompactSigned)) andalso JWS =/= element(3, jose_jws:verify(JWK, Signed)) andalso NonceJWS =/= element(3, jose_jws:verify(JWK, Signed)) end). erlang-jose-1.10.1/test/property_test/jose_jwe_alg_rsa_props.erl0000644000232200023220000000441613605433351025504 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_alg_rsa_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). modulus_size() -> integer(1048, 1280). % integer(256, 8192) | pos_integer(). exponent_size() -> return(65537). % pos_integer(). rsa_keypair(ModulusSize) -> ?LET(ExponentSize, exponent_size(), begin case public_key:generate_key({rsa, ModulusSize, ExponentSize}) of PrivateKey=#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent} -> {PrivateKey, #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}} end end). alg() -> oneof([ <<"RSA1_5">>, <<"RSA-OAEP">>, <<"RSA-OAEP-256">> ]). enc() -> oneof([ <<"A128CBC-HS256">>, <<"A192CBC-HS384">>, <<"A256CBC-HS512">>, <<"A128GCM">>, <<"A192GCM">>, <<"A256GCM">>, <<"C20P">>, <<"XC20P">> ]). jwk_jwe_maps(ModulusSize) -> ?LET({ALG, ENC, {AlicePrivateKey, AlicePublicKey}}, {alg(), enc(), rsa_keypair(ModulusSize)}, begin AlicePrivateJWK = jose_jwk:from_key(AlicePrivateKey), AlicePublicJWK = jose_jwk:from_key(AlicePublicKey), JWKs = {AlicePrivateJWK, AlicePublicJWK}, JWEMap = #{ <<"alg">> => ALG, <<"enc">> => ENC }, {JWKs, JWEMap} end). jwk_jwe_gen() -> ?LET({JWKs, JWEMap}, ?LET(ModulusSize, modulus_size(), jwk_jwe_maps(ModulusSize)), {JWKs, jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_JWKs, JWEMap}, Extras}, ?LET(ModulusSize, integer(1024, 1280), {jwk_jwe_maps(ModulusSize), binary_map()}), maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_key_encrypt_and_key_decrypt() -> ?FORALL({{AlicePrivateJWK, AlicePublicJWK}, JWE}, jwk_jwe_gen(), begin {DecKey, DecJWE} = jose_jwe:next_cek(AlicePublicJWK, JWE), {EncKey, EncJWE} = jose_jwe:key_encrypt(AlicePublicJWK, DecKey, DecJWE), DecKey =:= jose_jwe:key_decrypt(AlicePrivateJWK, EncKey, EncJWE) end). erlang-jose-1.10.1/test/property_test/jose_jws_alg_hmac_props.erl0000644000232200023220000000261613605433351025645 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jws_alg_hmac_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> oneof([ <<"HS256">>, <<"HS384">>, <<"HS512">> ]). jwk_jws_maps() -> ?LET({ALG, Key}, {alg(), binary()}, begin JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWSMap = #{ <<"alg">> => ALG }, {Key, JWKMap, JWSMap} end). jwk_jws_gen() -> ?LET({Key, JWKMap, JWSMap}, jwk_jws_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jws:from_map(JWSMap)}). prop_from_map_and_to_map() -> ?FORALL(JWSMap, ?LET({{_Key, _JWKMap, JWSMap}, Extras}, {jwk_jws_maps(), binary_map()}, maps:merge(Extras, JWSMap)), begin JWS = jose_jws:from_map(JWSMap), JWSMap =:= element(2, jose_jws:to_map(JWS)) end). prop_sign_and_verify() -> ?FORALL({{_Key, JWK, JWS}, Message}, {jwk_jws_gen(), binary()}, begin Signed = jose_jws:sign(JWK, Message, JWS), CompactSigned = jose_jws:compact(Signed), {true, Message, JWS} =:= jose_jws:verify(JWK, Signed) andalso {true, Message, JWS} =:= jose_jws:verify(JWK, CompactSigned) end). erlang-jose-1.10.1/test/property_test/jose_jwe_enc_aes_props.erl0000644000232200023220000000330113605433351025461 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_enc_aes_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). enc() -> oneof([ <<"A128CBC-HS256">>, <<"A192CBC-HS384">>, <<"A256CBC-HS512">>, <<"A128GCM">>, <<"A192GCM">>, <<"A256GCM">> ]). jwk_jwe_maps() -> ?LET(ENC, enc(), begin FakeJWEMap = #{ <<"alg">> => <<"RSA1_5">>, <<"enc">> => ENC }, FakeJWE = jose_jwe:from_map(FakeJWEMap), {Key, _} = jose_jwe:next_cek(undefined, FakeJWE), JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWEMap = #{ <<"alg">> => <<"dir">>, <<"enc">> => ENC }, {Key, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_Key, _JWKMap, JWEMap}, Extras}, {jwk_jwe_maps(), binary_map()}, maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_block_encrypt_and_block_decrypt() -> ?FORALL({CEK, IV, JWK, JWE, PlainText}, ?LET({CEK, JWK, JWE}, jwk_jwe_gen(), {CEK, jose_jwe:next_iv(JWE), JWK, JWE, binary()}), begin Encrypted = jose_jwe:block_encrypt(JWK, PlainText, CEK, IV, JWE), CompactEncrypted = jose_jwe:compact(Encrypted), PlainText =:= element(1, jose_jwe:block_decrypt(JWK, CompactEncrypted)) end). erlang-jose-1.10.1/test/property_test/jose_public_key.hrl0000777000232200023220000000000013605433351032053 2../../include/jose_public_key.hrlustar debalancedebalanceerlang-jose-1.10.1/test/property_test/jose_jwe_alg_dir_props.erl0000644000232200023220000000365013605433351025474 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_alg_dir_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). key_size() -> oneof([128, 192, 256]). key_gen() -> ?LET(KeySize, key_size(), {KeySize, binary(KeySize div 8)}). jwk_jwe_maps() -> ?LET({KeySize, Key}, key_gen(), begin ALG = <<"dir">>, ENC = list_to_binary("A" ++ integer_to_list(KeySize) ++ "GCM"), JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWEMap = #{ <<"alg">> => ALG, <<"enc">> => ENC }, {Key, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_Key, _JWKMap, JWEMap}, Extras}, {jwk_jwe_maps(), binary_map()}, maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_key_decrypt() -> ?FORALL({Key, JWK, JWE}, ?LET({Key, JWK, JWE}, jwk_jwe_gen(), {Key, oneof([Key, JWK]), JWE}), begin {DecKey, DecJWE} = jose_jwe:next_cek(JWK, JWE), Key =:= jose_jwe:key_decrypt(JWK, DecKey, DecJWE) end). prop_key_encrypt() -> ?FORALL({_Key, JWK, JWE}, ?LET({Key, JWK, JWE}, jwk_jwe_gen(), {Key, oneof([Key, JWK]), JWE}), begin {DecKey, DecJWE} = jose_jwe:next_cek(JWK, JWE), {<<>>, DecJWE} =:= jose_jwe:key_encrypt(JWK, DecKey, DecJWE) end). prop_next_cek() -> ?FORALL({Key, JWK, JWE}, ?LET({Key, JWK, JWE}, jwk_jwe_gen(), {Key, oneof([Key, JWK]), JWE}), begin {DecKey, _DecJWE} = jose_jwe:next_cek(JWK, JWE), Key =:= DecKey end). erlang-jose-1.10.1/test/property_test/jose_jwt_props.erl0000644000232200023220000000560713605433351024036 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwt_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). modulus_size() -> integer(1024, 1280). % integer(256, 8192) | pos_integer(). exponent_size() -> return(65537). % pos_integer(). rsa_keypair(ModulusSize) -> ?LET(ExponentSize, exponent_size(), begin case public_key:generate_key({rsa, ModulusSize, ExponentSize}) of PrivateKey=#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent} -> {PrivateKey, #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}} end end). % ec_curve() -> % oneof([ % secp256r1, % secp384r1, % secp521r1 % ]). % ec_keypair(CurveId) -> % ECPrivateKey = #'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0} = public_key:generate_key({namedCurve, pubkey_cert_records:namedCurves(CurveId)}), % Octets = case Octets0 of % {_, Octets1} -> % Octets1; % _ -> % Octets0 % end, % ECPoint = #'ECPoint'{point=Octets}, % ECPublicKey = {ECPoint, ECParameters}, % {ECPrivateKey, ECPublicKey}. % jwk_ec() -> % ?LET(CurveId, % ec_curve(), % begin % {PrivateKey, PublicKey} = ec_keypair(CurveId), % oneof([jose_jwk:from_key(PrivateKey), jose_jwk:from_key(PublicKey)]) % end). jwk_hmac() -> ?LET(Key, binary(32), jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) })). jwk_rsa() -> ?LET({_ModulusSize, {PrivateKey, _PublicKey}}, ?LET(ModulusSize, modulus_size(), {ModulusSize, rsa_keypair(ModulusSize)}), return(jose_jwk:from_key(PrivateKey))). jwk() -> frequency([ {50, jwk_hmac()}, {1, jwk_rsa()} ]). % oneof([ % % jwk_ec(), % jwk_hmac(), % jwk_rsa() % ]). jwk_jwt() -> ?LET({JWK, JWTMap}, {jwk(), binary_map()}, {JWK, jose_jwt:from_map(JWTMap)}). prop_from_map_and_to_map() -> ?FORALL({_JWK, JWTMap}, {jwk(), binary_map()}, begin JWT = jose_jwt:from_map(JWTMap), JWTMap =:= element(2, jose_jwt:to_map(JWT)) end). prop_encrypt_and_decrypt() -> ?FORALL({JWK, JWT}, jwk_jwt(), begin Encrypted = jose_jwt:encrypt(JWK, JWT), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {JWE, _} = jose_jwt:decrypt(JWK, Encrypted), {JWE, JWT} =:= Decrypted andalso {JWE, JWT} =:= jose_jwt:decrypt(JWK, CompactEncrypted) end). prop_sign_and_verify() -> ?FORALL({JWK, JWT}, jwk_jwt(), begin Signed = jose_jwt:sign(JWK, JWT), CompactSigned = jose_jws:compact(Signed), Verified = {_, _, JWS} = jose_jwt:verify(JWK, Signed), {true, JWT, JWS} =:= Verified andalso {true, JWT, JWS} =:= jose_jwt:verify(JWK, CompactSigned) end). erlang-jose-1.10.1/test/property_test/jose_jws_alg_rsa_pkcs1_v1_5_props.erl0000644000232200023220000000406213605433351027452 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jws_alg_rsa_pkcs1_v1_5_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> oneof([ <<"RS256">>, <<"RS384">>, <<"RS512">> ]). modulus_size() -> integer(1024, 1280). % integer(256, 8192) | pos_integer(). exponent_size() -> return(65537). % pos_integer(). rsa_keypair(ModulusSize) -> ?LET(ExponentSize, exponent_size(), begin case public_key:generate_key({rsa, ModulusSize, ExponentSize}) of PrivateKey=#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent} -> {PrivateKey, #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}} end end). jwk_jws_maps() -> ?LET({ModulusSize, ALG, {PrivateKey, PublicKey}}, ?LET(ModulusSize, modulus_size(), {ModulusSize, alg(), rsa_keypair(ModulusSize)}), begin JWKSigner = jose_jwk:from_key(PrivateKey), JWKVerifier = jose_jwk:from_key(PublicKey), JWSMap = #{ <<"alg">> => ALG }, {ModulusSize, {JWKSigner, JWKVerifier}, JWSMap} end). jwk_jws_gen() -> ?LET({ModulusSize, JWKs, JWSMap}, jwk_jws_maps(), {ModulusSize, JWKs, jose_jws:from_map(JWSMap)}). prop_from_map_and_to_map() -> ?FORALL(JWSMap, ?LET({ALG, Extras}, {alg(), binary_map()}, maps:merge(Extras, #{ <<"alg">> => ALG })), begin JWS = jose_jws:from_map(JWSMap), JWSMap =:= element(2, jose_jws:to_map(JWS)) end). prop_sign_and_verify() -> ?FORALL({{_ModulusSize, {JWKSigner, JWKVerifier}, JWS}, Message}, {jwk_jws_gen(), binary()}, begin Signed = jose_jws:sign(JWKSigner, Message, JWS), CompactSigned = jose_jws:compact(Signed), {true, Message, JWS} =:= jose_jws:verify(JWKVerifier, Signed) andalso {true, Message, JWS} =:= jose_jws:verify(JWKVerifier, CompactSigned) end). erlang-jose-1.10.1/test/property_test/jose_jwe_enc_xc20p_props.erl0000644000232200023220000000276613605433351025663 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_enc_xc20p_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). enc() -> return(<<"XC20P">>). jwk_jwe_maps() -> ?LET(ENC, enc(), begin JWEMap = #{ <<"alg">> => <<"dir">>, <<"enc">> => ENC }, Key = element(2, jose_jwk:to_oct(jose_jwe:generate_key(JWEMap))), JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, {Key, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_Key, _JWKMap, JWEMap}, Extras}, {jwk_jwe_maps(), binary_map()}, maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_block_encrypt_and_block_decrypt() -> ?FORALL({CEK, IV, JWK, JWE, PlainText}, ?LET({CEK, JWK, JWE}, jwk_jwe_gen(), {CEK, jose_jwe:next_iv(JWE), JWK, JWE, binary()}), begin Encrypted = jose_jwe:block_encrypt(JWK, PlainText, CEK, IV, JWE), CompactEncrypted = jose_jwe:compact(Encrypted), PlainText =:= element(1, jose_jwe:block_decrypt(JWK, CompactEncrypted)) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_okp_x25519_props.erl0000644000232200023220000001022113605433351026506 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_okp_x25519_props). -include("jose_public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). x25519_secret() -> binary(32). x25519_keypair(Secret) -> {PK, S} = jose_curve25519:x25519_keypair(Secret), PublicKey = #'jose_X25519PublicKey'{publicKey=PK}, SecretKey = #'jose_X25519PrivateKey'{publicKey=PublicKey, privateKey=S}, {SecretKey, PublicKey}. jwk_map() -> ?LET({AliceSecret, BobSecret}, {x25519_secret(), x25519_secret()}, begin AliceKeys = {AlicePrivateKey, _} = x25519_keypair(AliceSecret), BobKeys = x25519_keypair(BobSecret), AlicePrivateJWK = jose_jwk:from_key(AlicePrivateKey), {_, AlicePrivateJWKMap} = jose_jwk:to_map(AlicePrivateJWK), Keys = {AliceKeys, BobKeys}, {Keys, AlicePrivateJWKMap} end). jwk_gen() -> ?LET({Keys, AlicePrivateJWKMap}, jwk_map(), {Keys, jose_jwk:from_map(AlicePrivateJWKMap)}). prop_from_der_and_to_der() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivateDER = element(2, jose_jwk:to_der(AlicePrivateJWK)), EncryptedAlicePrivateDER = element(2, jose_jwk:to_der(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicDER = element(2, jose_jwk:to_der(AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_der(AlicePrivateDER) andalso AlicePrivateJWK =:= jose_jwk:from_der(Password, EncryptedAlicePrivateDER) andalso AlicePublicJWK =:= jose_jwk:from_der(AlicePublicDER) end). prop_from_map_and_to_map() -> ?FORALL({{{AlicePrivateKey, AlicePublicKey}, _}, AlicePrivateJWKMap}, ?LET({{Keys, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Keys, maps:merge(Extras, JWKMap)}), begin AlicePrivateJWK = jose_jwk:from_map(AlicePrivateJWKMap), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicJWKMap = element(2, jose_jwk:to_map(AlicePublicJWK)), AlicePublicThumbprint = jose_jwk:thumbprint(AlicePublicJWK), AlicePrivateJWKMap =:= element(2, jose_jwk:to_map(AlicePrivateJWK)) andalso AlicePrivateKey =:= element(2, jose_jwk:to_key(AlicePrivateJWK)) andalso AlicePublicKey =:= element(2, jose_jwk:to_public_key(AlicePrivateJWK)) andalso AlicePublicJWKMap =:= element(2, jose_jwk:to_public_map(AlicePrivateJWK)) andalso AlicePublicThumbprint =:= jose_jwk:thumbprint(AlicePrivateJWK) end). prop_from_pem_and_to_pem() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivatePEM = element(2, jose_jwk:to_pem(AlicePrivateJWK)), EncryptedAlicePrivatePEM = element(2, jose_jwk:to_pem(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicPEM = element(2, jose_jwk:to_pem(AlicePublicJWK)), EncryptedAlicePublicPEM = element(2, jose_jwk:to_pem(Password, AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_pem(AlicePrivatePEM) andalso AlicePrivateJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePrivatePEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(AlicePublicPEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePublicPEM) end). prop_box_encrypt_and_box_decrypt() -> ?FORALL({{{_, {BobPrivateKey, BobPublicKey}}, AlicePrivateJWK}, PlainText}, {jwk_gen(), binary()}, begin BobPrivateJWK = jose_jwk:from_key(BobPrivateKey), BobPublicJWK = jose_jwk:from_key(BobPublicKey), Encrypted = jose_jwk:box_encrypt_ecdh_es(PlainText, BobPublicJWK, AlicePrivateJWK), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, JWE} = jose_jwk:box_decrypt_ecdh_es(Encrypted, BobPrivateJWK), {PlainText, JWE} =:= Decrypted andalso {PlainText, JWE} =:= jose_jwk:block_decrypt(CompactEncrypted, BobPrivateJWK) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_okp_ed25519_props.erl0000644000232200023220000000774613605433351026651 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_okp_ed25519_props). -include("jose_public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). ed25519_secret() -> binary(32). ed25519_keypair(Secret) -> {PK, << S:32/binary, _:32/binary >>} = jose_curve25519:eddsa_keypair(Secret), PublicKey = #'jose_EdDSA25519PublicKey'{publicKey=PK}, SecretKey = #'jose_EdDSA25519PrivateKey'{publicKey=PublicKey, privateKey=S}, {SecretKey, PublicKey}. jwk_map() -> ?LET({AliceSecret, BobSecret}, {ed25519_secret(), ed25519_secret()}, begin AliceKeys = {AlicePrivateKey, _} = ed25519_keypair(AliceSecret), BobKeys = ed25519_keypair(BobSecret), AlicePrivateJWK = jose_jwk:from_key(AlicePrivateKey), {_, AlicePrivateJWKMap} = jose_jwk:to_map(AlicePrivateJWK), Keys = {AliceKeys, BobKeys}, {Keys, AlicePrivateJWKMap} end). jwk_gen() -> ?LET({Keys, AlicePrivateJWKMap}, jwk_map(), {Keys, jose_jwk:from_map(AlicePrivateJWKMap)}). prop_from_der_and_to_der() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivateDER = element(2, jose_jwk:to_der(AlicePrivateJWK)), EncryptedAlicePrivateDER = element(2, jose_jwk:to_der(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicDER = element(2, jose_jwk:to_der(AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_der(AlicePrivateDER) andalso AlicePrivateJWK =:= jose_jwk:from_der(Password, EncryptedAlicePrivateDER) andalso AlicePublicJWK =:= jose_jwk:from_der(AlicePublicDER) end). prop_from_map_and_to_map() -> ?FORALL({{{AlicePrivateKey, AlicePublicKey}, _}, AlicePrivateJWKMap}, ?LET({{Keys, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Keys, maps:merge(Extras, JWKMap)}), begin AlicePrivateJWK = jose_jwk:from_map(AlicePrivateJWKMap), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicJWKMap = element(2, jose_jwk:to_map(AlicePublicJWK)), AlicePublicThumbprint = jose_jwk:thumbprint(AlicePublicJWK), AlicePrivateJWKMap =:= element(2, jose_jwk:to_map(AlicePrivateJWK)) andalso AlicePrivateKey =:= element(2, jose_jwk:to_key(AlicePrivateJWK)) andalso AlicePublicKey =:= element(2, jose_jwk:to_public_key(AlicePrivateJWK)) andalso AlicePublicJWKMap =:= element(2, jose_jwk:to_public_map(AlicePrivateJWK)) andalso AlicePublicThumbprint =:= jose_jwk:thumbprint(AlicePrivateJWK) end). prop_from_pem_and_to_pem() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivatePEM = element(2, jose_jwk:to_pem(AlicePrivateJWK)), EncryptedAlicePrivatePEM = element(2, jose_jwk:to_pem(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicPEM = element(2, jose_jwk:to_pem(AlicePublicJWK)), EncryptedAlicePublicPEM = element(2, jose_jwk:to_pem(Password, AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_pem(AlicePrivatePEM) andalso AlicePrivateJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePrivatePEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(AlicePublicPEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePublicPEM) end). prop_sign_and_verify() -> ?FORALL({_Keys, JWK, Message}, ?LET({Keys, JWK}, jwk_gen(), {Keys, JWK, binary()}), begin Signed = jose_jwk:sign(Message, JWK), CompactSigned = jose_jws:compact(Signed), Verified = {_, _, JWS} = jose_jwk:verify(Signed, JWK), {true, Message, JWS} =:= Verified andalso {true, Message, JWS} =:= jose_jwk:verify(CompactSigned, JWK) end). erlang-jose-1.10.1/test/property_test/jose_jws_alg_ecdsa_props.erl0000644000232200023220000000441513605433351026013 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jws_alg_ecdsa_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> oneof([ <<"ES256">>, <<"ES384">>, <<"ES512">> ]). alg(secp256r1) -> return(<<"ES256">>); alg(secp384r1) -> return(<<"ES384">>); alg(secp521r1) -> return(<<"ES512">>). opt_map() -> oneof([ #{}, #{ <<"b64">> => true }, #{ <<"b64">> => false } ]). ec_curve() -> oneof([ secp256r1, secp384r1, secp521r1 ]). ec_keypair(CurveId) -> ECPrivateKey = #'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0} = public_key:generate_key({namedCurve, pubkey_cert_records:namedCurves(CurveId)}), Octets = case Octets0 of {_, Octets1} -> Octets1; _ -> Octets0 end, ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, {ECPrivateKey, ECPublicKey}. jwk_jws_maps() -> ?LET({CurveId, ALG, {PrivateKey, PublicKey}, Opts}, ?LET(CurveId, ec_curve(), {CurveId, alg(CurveId), ec_keypair(CurveId), opt_map()}), begin JWKSigner = jose_jwk:from_key(PrivateKey), JWKVerifier = jose_jwk:from_key(PublicKey), JWSMap = maps:merge(Opts, #{ <<"alg">> => ALG }), {CurveId, {JWKSigner, JWKVerifier}, JWSMap} end). jwk_jws_gen() -> ?LET({CurveId, JWKs, JWSMap}, jwk_jws_maps(), {CurveId, JWKs, jose_jws:from_map(JWSMap)}). prop_from_map_and_to_map() -> ?FORALL(JWSMap, ?LET({ALG, Opts, Extras}, {alg(), opt_map(), binary_map()}, maps:merge(maps:merge(Extras, Opts), #{ <<"alg">> => ALG })), begin JWS = jose_jws:from_map(JWSMap), JWSMap =:= element(2, jose_jws:to_map(JWS)) end). prop_sign_and_verify() -> ?FORALL({{_CurveId, {JWKSigner, JWKVerifier}, JWS}, Message}, {jwk_jws_gen(), binary()}, begin Signed = jose_jws:sign(JWKSigner, Message, JWS), CompactSigned = jose_jws:compact(Signed), {true, Message, JWS} =:= jose_jws:verify(JWKVerifier, Signed) andalso {true, Message, JWS} =:= jose_jws:verify(JWKVerifier, CompactSigned) end). erlang-jose-1.10.1/test/property_test/jose_jwa_aes_kw_props.erl0000644000232200023220000000112113605433351025327 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_aes_kw_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). kek_size() -> oneof([128, 192, 256]). key_wrapper_gen() -> ?LET({Bits, PlainText}, {kek_size(), binary()}, {Bits, binary(Bits div 8), jose_jwa_pkcs7:pad(PlainText)}). prop_wrap_and_unwrap() -> ?FORALL({_Bits, KEK, PlainText}, key_wrapper_gen(), begin CipherText = jose_jwa_aes_kw:wrap(PlainText, KEK), PlainText =:= jose_jwa_aes_kw:unwrap(CipherText, KEK) end). erlang-jose-1.10.1/test/property_test/jose_jwa_pkcs7_props.erl0000644000232200023220000000056613605433351025121 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_pkcs7_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). prop_pad_and_unpad() -> ?FORALL(Binary, binary(), begin PaddedBinary = jose_jwa_pkcs7:pad(Binary), Binary =:= jose_jwa_pkcs7:unpad(PaddedBinary) end). erlang-jose-1.10.1/test/property_test/jose_jwa_concat_kdf_props.erl0000644000232200023220000000167113605433351026163 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_concat_kdf_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). hash_fun() -> oneof([md5, sha, sha224, sha256, sha384, sha512, {hmac, md5, <<>>}, {hmac, sha, <<>>}, {hmac, sha224, <<>>}, {hmac, sha256, <<>>}, {hmac, sha384, <<>>}, {hmac, sha512, <<>>}]). prop_kdf() -> ?FORALL({Hash, Z, OtherInfo}, {hash_fun(), binary(), {binary(), binary(), binary()}}, begin DerivedKey = jose_jwa_concat_kdf:kdf(Hash, Z, OtherInfo), DerivedKey =:= jose_jwa_concat_kdf:kdf(Hash, Z, OtherInfo) end). prop_kdf_keylen() -> ?FORALL({Hash, Z, OtherInfo, KeyDataLen}, {hash_fun(), binary(), {binary(), binary(), binary()}, integer(0, 1024)}, begin DerivedKey = jose_jwa_concat_kdf:kdf(Hash, Z, OtherInfo, KeyDataLen), DerivedKey =:= jose_jwa_concat_kdf:kdf(Hash, Z, OtherInfo, KeyDataLen) end). erlang-jose-1.10.1/test/property_test/jose_jwa_props.erl0000644000232200023220000000057413605433351024011 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). prop_constant_time_compare() -> ?FORALL(Binary, ?SUCHTHAT(Binary, binary(), byte_size(Binary) >= 1), begin jose_jwa:constant_time_compare(Binary, Binary) end). erlang-jose-1.10.1/test/property_test/jose_jwe_alg_ecdh_es_props.erl0000644000232200023220000000674313605433351026316 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_alg_ecdh_es_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> oneof([ <<"ECDH-ES">>, <<"ECDH-ES+A128GCMKW">>, <<"ECDH-ES+A192GCMKW">>, <<"ECDH-ES+A256GCMKW">>, <<"ECDH-ES+A128KW">>, <<"ECDH-ES+A192KW">>, <<"ECDH-ES+A256KW">>, <<"ECDH-ES+C20PKW">>, <<"ECDH-ES+XC20PKW">> ]). alg_map() -> ?LET({ALG, APU, APV}, {alg(), binary(), binary()}, #{ <<"alg">> => ALG, <<"apu">> => jose_jwa_base64url:encode(APU), <<"apv">> => jose_jwa_base64url:encode(APV) }). ec_curve() -> oneof([ secp256r1, secp384r1, secp521r1, x25519, x448 ]). % ec_curve() -> % ?SUCHTHAT(CurveId, % oneof(crypto:ec_curves()), % begin % try pubkey_cert_records:namedCurves(CurveId) of % Curve when is_tuple(Curve) -> % true; % _ -> % false % catch % _:_ -> % false % end % end). % ec_keypair() -> % ?LET(CurveId, % ec_curve(), % ec_keypair(CurveId)). ec_keypair(x25519) -> SecretJWK = jose_jwk:generate_key({okp, 'X25519'}), {_, SecretKey} = jose_jwk:to_key(SecretJWK), {_, PublicKey} = jose_jwk:to_public_key(SecretJWK), {SecretKey, PublicKey}; ec_keypair(x448) -> SecretJWK = jose_jwk:generate_key({okp, 'X448'}), {_, SecretKey} = jose_jwk:to_key(SecretJWK), {_, PublicKey} = jose_jwk:to_public_key(SecretJWK), {SecretKey, PublicKey}; ec_keypair(CurveId) -> ECPrivateKey = #'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0} = public_key:generate_key({namedCurve, pubkey_cert_records:namedCurves(CurveId)}), Octets = case Octets0 of {_, Octets1} -> Octets1; _ -> Octets0 end, ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, {ECPrivateKey, ECPublicKey}. enc() -> oneof([ <<"A128GCM">>, <<"A192GCM">>, <<"A256GCM">>, <<"C20P">>, <<"XC20P">> ]). jwk_jwe_maps() -> ?LET({ALGMap, ENC, {BobPrivateKey, BobPublicKey}, {AlicePrivateKey, AlicePublicKey}}, ?LET(CurveId, ec_curve(), {alg_map(), enc(), ec_keypair(CurveId), ec_keypair(CurveId)}), begin BobPrivateJWK = jose_jwk:from_key(BobPrivateKey), BobPublicJWK = jose_jwk:from_key(BobPublicKey), AlicePrivateJWK = jose_jwk:from_key(AlicePrivateKey), AlicePublicJWK = jose_jwk:from_key(AlicePublicKey), {_, AlicePublicJWKMap} = jose_jwk:to_public_map(AlicePrivateJWK), BobBox = {AlicePublicJWK, BobPrivateJWK}, AliceBox = {BobPublicJWK, AlicePrivateJWK}, JWKs = {BobBox, AliceBox}, JWEMap = maps:merge(#{ <<"enc">> => ENC, <<"epk">> => AlicePublicJWKMap }, ALGMap), {JWKs, JWEMap} end). jwk_jwe_gen() -> ?LET({JWKs, JWEMap}, jwk_jwe_maps(), {JWKs, jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_JWKs, JWEMap}, Extras}, {jwk_jwe_maps(), binary_map()}, maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_key_encrypt_and_key_decrypt() -> ?FORALL({{BobBox, AliceBox}, JWE}, jwk_jwe_gen(), begin {DecKey, DecJWE} = jose_jwe:next_cek(AliceBox, JWE), {EncKey, EncJWE} = jose_jwe:key_encrypt(AliceBox, DecKey, DecJWE), DecKey =:= jose_jwe:key_decrypt(BobBox, EncKey, EncJWE) end). erlang-jose-1.10.1/test/property_test/jose_jwk_props.erl0000644000232200023220000002654513605433351024031 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). alg_map() -> oneof([ #{ <<"alg">> => <<"RSA1_5">> }, #{ <<"alg">> => <<"RSA-OAEP">> }, #{ <<"alg">> => <<"RSA-OAEP-256">> }, #{ <<"alg">> => <<"A128KW">> }, #{ <<"alg">> => <<"A192KW">> }, #{ <<"alg">> => <<"A256KW">> }, #{ <<"alg">> => <<"dir">> }, #{ <<"alg">> => <<"ECDH-1PU">> }, #{ <<"alg">> => <<"ECDH-1PU+A128GCMKW">> }, #{ <<"alg">> => <<"ECDH-1PU+A192GCMKW">> }, #{ <<"alg">> => <<"ECDH-1PU+A256GCMKW">> }, #{ <<"alg">> => <<"ECDH-1PU+A128KW">> }, #{ <<"alg">> => <<"ECDH-1PU+A192KW">> }, #{ <<"alg">> => <<"ECDH-1PU+A256KW">> }, #{ <<"alg">> => <<"ECDH-1PU+C20PKW">> }, #{ <<"alg">> => <<"ECDH-1PU+XC20PKW">> }, #{ <<"alg">> => <<"ECDH-ES">> }, #{ <<"alg">> => <<"ECDH-ES+A128GCMKW">> }, #{ <<"alg">> => <<"ECDH-ES+A192GCMKW">> }, #{ <<"alg">> => <<"ECDH-ES+A256GCMKW">> }, #{ <<"alg">> => <<"ECDH-ES+A128KW">> }, #{ <<"alg">> => <<"ECDH-ES+A192KW">> }, #{ <<"alg">> => <<"ECDH-ES+A256KW">> }, #{ <<"alg">> => <<"ECDH-ES+C20PKW">> }, #{ <<"alg">> => <<"ECDH-ES+XC20PKW">> }, #{ <<"alg">> => <<"A128GCMKW">> }, #{ <<"alg">> => <<"A192GCMKW">> }, #{ <<"alg">> => <<"A256GCMKW">> }, ?LET({P2C, P2S}, {integer(1, 256), binary()}, #{ <<"alg">> => <<"PBES2-HS256+A128GCMKW">>, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }), ?LET({P2C, P2S}, {integer(1, 256), binary()}, #{ <<"alg">> => <<"PBES2-HS384+A192GCMKW">>, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }), ?LET({P2C, P2S}, {integer(1, 256), binary()}, #{ <<"alg">> => <<"PBES2-HS512+A256GCMKW">>, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }), ?LET({P2C, P2S}, {integer(1, 256), binary()}, #{ <<"alg">> => <<"PBES2-HS256+A128KW">>, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }), ?LET({P2C, P2S}, {integer(1, 256), binary()}, #{ <<"alg">> => <<"PBES2-HS384+A192KW">>, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }), ?LET({P2C, P2S}, {integer(1, 256), binary()}, #{ <<"alg">> => <<"PBES2-HS512+A256KW">>, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }), ?LET({P2C, P2S}, {integer(1, 256), binary()}, #{ <<"alg">> => <<"PBES2-HS512+C20PKW">>, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }), ?LET({P2C, P2S}, {integer(1, 256), binary()}, #{ <<"alg">> => <<"PBES2-HS512+XC20PKW">>, <<"p2c">> => P2C, <<"p2s">> => jose_jwa_base64url:encode(P2S) }) ]). enc_map() -> oneof([ #{ <<"enc">> => <<"A128CBC-HS256">> }, #{ <<"enc">> => <<"A192CBC-HS384">> }, #{ <<"enc">> => <<"A256CBC-HS512">> }, #{ <<"enc">> => <<"A128GCM">> }, #{ <<"enc">> => <<"A192GCM">> }, #{ <<"enc">> => <<"A256GCM">> }, #{ <<"enc">> => <<"C20P">> }, #{ <<"enc">> => <<"XC20P">> } ]). jwk_encryptor_gen() -> ?LET({ALGMap, ENCMap}, ?SUCHTHAT({#{ <<"alg">> := _ALG }, #{ <<"enc">> := _ENC }}, {alg_map(), enc_map()}, true), begin ALG = maps:get(<<"alg">>, ALGMap), ENC = maps:get(<<"enc">>, ENCMap), JWE = jose_jwe:from_map(maps:merge(ENCMap, ALGMap)), case {ALG, ENC} of {<<"RSA", _/binary>>, _} -> ?LET({RSAPrivateKey, RSAPublicKey}, ?LET(ModulusSize, modulus_size(), rsa_keypair(ModulusSize)), begin PrivateJWK = jose_jwk:from_key(RSAPrivateKey), PublicJWK = jose_jwk:from_key(RSAPublicKey), {{rsa, RSAPrivateKey, RSAPublicKey}, JWE, {PrivateJWK, PublicJWK}} end); {<<"A128KW">>, _} -> K = crypto:strong_rand_bytes(16), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"A192KW">>, _} -> K = crypto:strong_rand_bytes(24), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"A256KW">>, _} -> K = crypto:strong_rand_bytes(32), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"dir">>, <<"A128CBC-HS256">>} -> K = crypto:strong_rand_bytes(32), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"dir">>, <<"A192CBC-HS384">>} -> K = crypto:strong_rand_bytes(48), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"dir">>, <<"A256CBC-HS512">>} -> K = crypto:strong_rand_bytes(64), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"dir">>, <<"A128GCM">>} -> K = crypto:strong_rand_bytes(16), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"dir">>, <<"A192GCM">>} -> K = crypto:strong_rand_bytes(24), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"dir">>, <<"A256GCM">>} -> K = crypto:strong_rand_bytes(32), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"dir">>, <<"C20P">>} -> K = crypto:strong_rand_bytes(32), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"dir">>, <<"XC20P">>} -> K = crypto:strong_rand_bytes(32), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"ECDH-1PU", _/binary>>, _} -> ?LET(CurveId, ec_curve(), begin VStaticKeypair = {VStaticSecret, VStaticPublic} = ec_keypair(CurveId), UStaticKeypair = {UStaticSecret, UStaticPublic} = ec_keypair(CurveId), UEphemeralKeypair = {UEphemeralSecret, UEphemeralPublic} = ec_keypair(CurveId), VStaticSecretKey = jose_jwk:from_key(VStaticSecret), VStaticPublicKey = jose_jwk:from_key(VStaticPublic), UStaticSecretKey = jose_jwk:from_key(UStaticSecret), UStaticPublicKey = jose_jwk:from_key(UStaticPublic), UEphemeralSecretKey = jose_jwk:from_key(UEphemeralSecret), UEphemeralPublicKey = jose_jwk:from_key(UEphemeralPublic), {{ecdh_1pu, VStaticKeypair, UStaticKeypair, UEphemeralKeypair}, JWE, {{VStaticSecretKey, VStaticPublicKey}, {UStaticSecretKey, UStaticPublicKey}, {UEphemeralSecretKey, UEphemeralPublicKey}}} end); {<<"ECDH-ES", _/binary>>, _} -> ?LET(CurveId, ec_curve(), begin AliceKeypair = {AlicePrivateKey, AlicePublicKey} = ec_keypair(CurveId), BobKeypair = {BobPrivateKey, BobPublicKey} = ec_keypair(CurveId), AlicePrivateJWK = jose_jwk:from_key(AlicePrivateKey), AlicePublicJWK = jose_jwk:from_key(AlicePublicKey), BobPrivateJWK = jose_jwk:from_key(BobPrivateKey), BobPublicJWK = jose_jwk:from_key(BobPublicKey), {{ecdh_es, AliceKeypair, BobKeypair}, JWE, {{AlicePrivateJWK, AlicePublicJWK}, {BobPrivateJWK, BobPublicJWK}}} end); {<<"A128GCMKW">>, _} -> K = crypto:strong_rand_bytes(16), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"A192GCMKW">>, _} -> K = crypto:strong_rand_bytes(24), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"A256GCMKW">>, _} -> K = crypto:strong_rand_bytes(32), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"C20PKW">>, _} -> K = crypto:strong_rand_bytes(32), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"XC20PKW">>, _} -> K = crypto:strong_rand_bytes(32), {K, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(K) })}; {<<"PBES2", _/binary>>, _} -> ?LET(Key, binary(), begin Password = jose_jwa_base64url:encode(Key), {Password, JWE, jose_jwk:from_map(#{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Password) })} end) end end). ec_curve() -> oneof([ secp256r1, secp384r1, secp521r1, x25519, x448 ]). ec_keypair(x25519) -> SecretJWK = jose_jwk:generate_key({okp, 'X25519'}), {_, SecretKey} = jose_jwk:to_key(SecretJWK), {_, PublicKey} = jose_jwk:to_public_key(SecretJWK), {SecretKey, PublicKey}; ec_keypair(x448) -> SecretJWK = jose_jwk:generate_key({okp, 'X448'}), {_, SecretKey} = jose_jwk:to_key(SecretJWK), {_, PublicKey} = jose_jwk:to_public_key(SecretJWK), {SecretKey, PublicKey}; ec_keypair(CurveId) -> ECPrivateKey = #'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0} = public_key:generate_key({namedCurve, pubkey_cert_records:namedCurves(CurveId)}), Octets = case Octets0 of {_, Octets1} -> Octets1; _ -> Octets0 end, ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, {ECPrivateKey, ECPublicKey}. modulus_size() -> integer(1048, 1280). % integer(256, 8192) | pos_integer(). exponent_size() -> return(65537). % pos_integer(). rsa_keypair(ModulusSize) -> ?LET(ExponentSize, exponent_size(), begin case public_key:generate_key({rsa, ModulusSize, ExponentSize}) of PrivateKey=#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent} -> {PrivateKey, #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}} end end). prop_encrypt_and_decrypt() -> ?FORALL({Keys, JWE, JWKs, PlainText}, ?LET({Keys, JWE, JWKs}, jwk_encryptor_gen(), {Keys, JWE, JWKs, binary()}), begin case {Keys, JWKs} of {{ecdh_1pu, _, _, _}, {{VStaticSecretKey, VStaticPublicKey}, {UStaticSecretKey, UStaticPublicKey}, {UEphemeralSecretKey, UEphemeralPublicKey}}} -> JWEMap = jose_jwe:to_map(JWE), Encrypted = jose_jwk:box_encrypt_ecdh_1pu(PlainText, JWEMap, VStaticPublicKey, UStaticSecretKey, UEphemeralSecretKey), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, NewJWE} = jose_jwk:box_decrypt_ecdh_1pu(Encrypted, UStaticPublicKey, VStaticSecretKey), {PlainText, NewJWE} =:= Decrypted andalso {PlainText, NewJWE} =:= jose_jwe:block_decrypt({UStaticPublicKey, VStaticSecretKey, UEphemeralPublicKey}, CompactEncrypted); {{ecdh_es, _, _}, {{AlicePrivateJWK, _AlicePublicJWK}, {BobPrivateJWK, BobPublicJWK}}} -> JWEMap = jose_jwe:to_map(JWE), Encrypted = jose_jwk:box_encrypt_ecdh_es(PlainText, JWEMap, BobPublicJWK, AlicePrivateJWK), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, NewJWE} = jose_jwk:box_decrypt_ecdh_es(Encrypted, BobPrivateJWK), {PlainText, NewJWE} =:= Decrypted andalso {PlainText, NewJWE} =:= jose_jwk:block_decrypt(CompactEncrypted, BobPrivateJWK); {{rsa, _, _}, {PrivateJWK, PublicJWK}} -> Encrypted = jose_jwk:block_encrypt(PlainText, JWE, PublicJWK), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, NewJWE} = jose_jwk:block_decrypt(Encrypted, PrivateJWK), {PlainText, NewJWE} =:= Decrypted andalso {PlainText, NewJWE} =:= jose_jwk:block_decrypt(CompactEncrypted, PrivateJWK); {_, JWK} -> Encrypted = jose_jwk:block_encrypt(PlainText, JWE, JWK), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, NewJWE} = jose_jwk:block_decrypt(Encrypted, JWK), {PlainText, NewJWE} =:= Decrypted andalso {PlainText, NewJWE} =:= jose_jwk:block_decrypt(CompactEncrypted, JWK) end end). erlang-jose-1.10.1/test/property_test/jose_jws_alg_none_props.erl0000644000232200023220000000255013605433351025671 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jws_alg_none_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> return(<<"none">>). jwk_jws_maps() -> ?LET({ALG, Key}, {alg(), binary()}, begin JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWSMap = #{ <<"alg">> => ALG }, {Key, JWKMap, JWSMap} end). jwk_jws_gen() -> ?LET({Key, JWKMap, JWSMap}, jwk_jws_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jws:from_map(JWSMap)}). prop_from_map_and_to_map() -> ?FORALL(JWSMap, ?LET({{_Key, _JWKMap, JWSMap}, Extras}, {jwk_jws_maps(), binary_map()}, maps:merge(Extras, JWSMap)), begin JWS = jose_jws:from_map(JWSMap), JWSMap =:= element(2, jose_jws:to_map(JWS)) end). prop_sign_and_verify() -> ?FORALL({{_Key, JWK, JWS}, Message}, {jwk_jws_gen(), binary()}, begin Signed = jose_jws:sign(JWK, Message, JWS), CompactSigned = jose_jws:compact(Signed), {true, Message, JWS} =:= jose_jws:verify(JWK, Signed) andalso {true, Message, JWS} =:= jose_jws:verify(JWK, CompactSigned) end). erlang-jose-1.10.1/test/property_test/jose_jwe_alg_xc20p_kw_props.erl0000644000232200023220000000354313605433351026354 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_alg_xc20p_kw_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). key_size() -> return(256). key_gen() -> ?LET(KeySize, key_size(), {KeySize, binary(KeySize div 8)}). alg_map(256) -> return(#{ <<"alg">> => <<"XC20PKW">> }). extra_map(_) -> oneof([ #{}, #{ <<"iv">> => jose_jwa_base64url:encode(crypto:strong_rand_bytes(12)), <<"tag">> => jose_jwa_base64url:encode(crypto:strong_rand_bytes(8)) } ]). jwk_jwe_maps() -> ?LET({_KeySize, Key, ALGMap}, ?LET({KeySize, Key}, key_gen(), {KeySize, Key, alg_map(KeySize)}), begin ENC = <<"XC20P">>, JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWEMap = maps:merge(#{ <<"enc">> => ENC }, ALGMap), {Key, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({JWEMap, ExtraMap, Extras}, ?LET({_Key, _JWKMap, JWEMap}, jwk_jwe_maps(), {JWEMap, extra_map(JWEMap), binary_map()}), maps:merge(maps:merge(Extras, ExtraMap), JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_key_encrypt_and_key_decrypt() -> ?FORALL({_Key, JWK, JWE}, ?LET({Key, JWK, JWE}, jwk_jwe_gen(), {Key, oneof([Key, JWK]), JWE}), begin {DecKey, DecJWE} = jose_jwe:next_cek(JWK, JWE), {EncKey, EncJWE} = jose_jwe:key_encrypt(JWK, DecKey, DecJWE), DecKey =:= jose_jwe:key_decrypt(JWK, EncKey, EncJWE) end). erlang-jose-1.10.1/test/property_test/jose_jws_alg_eddsa_props.erl0000644000232200023220000000547513605433351026023 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jws_alg_eddsa_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> oneof([ <<"Ed25519">>, <<"Ed25519ph">>, <<"Ed448">>, <<"Ed448ph">>, <<"EdDSA">> ]). opt_map() -> oneof([ #{}, #{ <<"b64">> => true }, #{ <<"b64">> => false } ]). okp_type(<<"EdDSA">>, PK) when byte_size(PK) =:= 32 -> oneof([ 'Ed25519', 'Ed25519ph' ]); okp_type(<<"EdDSA">>, PK) when byte_size(PK) =:= 57 -> oneof([ 'Ed448', 'Ed448ph' ]); okp_type(<<"Ed25519">>, PK) when byte_size(PK) =:= 32 -> 'Ed25519'; okp_type(<<"Ed25519ph">>, PK) when byte_size(PK) =:= 32 -> 'Ed25519ph'; okp_type(<<"Ed448">>, PK) when byte_size(PK) =:= 57 -> 'Ed448'; okp_type(<<"Ed448ph">>, PK) when byte_size(PK) =:= 57 -> 'Ed448ph'. ed_curve_module(<< "EdDSA" >>) -> oneof([ jose_curve25519, jose_curve448 ]); ed_curve_module(<< "Ed25519", _/binary >>) -> jose_curve25519; ed_curve_module(<< "Ed448", _/binary >>) -> jose_curve448. eddsa_secret(jose_curve25519) -> binary(32); eddsa_secret(jose_curve448) -> binary(57). eddsa_keypair(EdCurveModule, Secret) -> {PK, SK} = EdCurveModule:eddsa_keypair(Secret), {SK, PK}. eddsa_keypair_gen(ALG) -> ?LET({EdCurveModule, Secret}, ?LET(EdCurveModule, ed_curve_module(ALG), {EdCurveModule, eddsa_secret(EdCurveModule)}), eddsa_keypair(EdCurveModule, Secret)). jwk_jws_maps() -> ?LET({{SK, PK}, Opts, OKP, ALG}, ?LET({{SK, PK}, ALG}, ?LET(ALG, alg(), {eddsa_keypair_gen(ALG), ALG}), {{SK, PK}, opt_map(), okp_type(ALG, PK), ALG}), begin JWKSigner = jose_jwk:from_okp({OKP, SK}), JWKVerifier = jose_jwk:from_okp({OKP, PK}), JWSMap = maps:merge(Opts, #{ <<"alg">> => ALG }), {JWKSigner, JWKVerifier, JWSMap} end). jwk_jws_gen() -> ?LET({JWKSigner, JWKVerifier, JWSMap}, jwk_jws_maps(), {JWKSigner, JWKVerifier, jose_jws:from_map(JWSMap)}). prop_from_map_and_to_map() -> ?FORALL(JWSMap, ?LET({ALG, Opts, Extras}, {alg(), opt_map(), binary_map()}, maps:merge(maps:merge(Extras, Opts), #{ <<"alg">> => ALG })), begin JWS = jose_jws:from_map(JWSMap), JWSMap =:= element(2, jose_jws:to_map(JWS)) end). prop_sign_and_verify() -> ?FORALL({{JWKSigner, JWKVerifier, JWS}, Message}, {jwk_jws_gen(), binary()}, begin Signed = jose_jws:sign(JWKSigner, Message, JWS), CompactSigned = jose_jws:compact(Signed), {true, Message, JWS} =:= jose_jws:verify(JWKVerifier, Signed) andalso {true, Message, JWS} =:= jose_jws:verify(JWKVerifier, CompactSigned) end). erlang-jose-1.10.1/test/property_test/jose_jwa_pkcs5_props.erl0000644000232200023220000000372113605433351025113 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_pkcs5_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). hash_fun() -> oneof([md5, sha, sha224, sha256, sha384, sha512, {hmac, md5, <<>>}, {hmac, sha, <<>>}, {hmac, sha224, <<>>}, {hmac, sha256, <<>>}, {hmac, sha384, <<>>}, {hmac, sha512, <<>>}]). mac_fun() -> oneof([md5, sha, sha224, sha256, sha384, sha512, {hmac, md5}, {hmac, sha}, {hmac, sha224}, {hmac, sha256}, {hmac, sha384}, {hmac, sha512}]). prop_pbkdf1() -> ?FORALL({Hash, Password, Salt}, {hash_fun(), binary(), binary()}, begin {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf1(Hash, Password, Salt), DerivedKey =:= element(2, jose_jwa_pkcs5:pbkdf1(Hash, Password, Salt)) end). prop_pbkdf1_iterations() -> ?FORALL({Hash, Password, Salt, Iterations}, {hash_fun(), binary(), binary(), integer(1, 10)}, begin {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf1(Hash, Password, Salt, Iterations), DerivedKey =:= element(2, jose_jwa_pkcs5:pbkdf1(Hash, Password, Salt, Iterations)) end). prop_pbkdf2() -> ?FORALL({Mac, Password, Salt}, {mac_fun(), binary(), binary()}, begin {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt), DerivedKey =:= element(2, jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt)) end). prop_pbkdf2_iterations() -> ?FORALL({Mac, Password, Salt, Iterations}, {mac_fun(), binary(), binary(), integer(1, 10)}, begin {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt, Iterations), DerivedKey =:= element(2, jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt, Iterations)) end). prop_pbkdf2_iterations_keylen() -> ?FORALL({Mac, Password, Salt, Iterations, KeyLen}, {mac_fun(), binary(), binary(), integer(1, 10), integer(0, 128)}, begin {ok, DerivedKey} = jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt, Iterations, KeyLen), DerivedKey =:= element(2, jose_jwa_pkcs5:pbkdf2(Mac, Password, Salt, Iterations, KeyLen)) end). erlang-jose-1.10.1/test/property_test/jose_jwe_alg_aes_kw_props.erl0000644000232200023220000000431613605433351026167 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_alg_aes_kw_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). key_size() -> oneof([128, 192, 256]). key_gen() -> ?LET(KeySize, key_size(), {KeySize, binary(KeySize div 8)}). alg_map(128) -> oneof([ #{ <<"alg">> => <<"A128KW">> }, #{ <<"alg">> => <<"A128GCMKW">> } ]); alg_map(192) -> oneof([ #{ <<"alg">> => <<"A192KW">> }, #{ <<"alg">> => <<"A192GCMKW">> } ]); alg_map(256) -> oneof([ #{ <<"alg">> => <<"A256KW">> }, #{ <<"alg">> => <<"A256GCMKW">> } ]). aes_gcm_map(#{ <<"alg">> := << "A", _, _, _, "GCMKW" >> }) -> oneof([ #{}, #{ <<"iv">> => jose_jwa_base64url:encode(crypto:strong_rand_bytes(12)), <<"tag">> => jose_jwa_base64url:encode(crypto:strong_rand_bytes(8)) } ]); aes_gcm_map(_) -> #{}. jwk_jwe_maps() -> ?LET({KeySize, Key, ALGMap}, ?LET({KeySize, Key}, key_gen(), {KeySize, Key, alg_map(KeySize)}), begin ENC = list_to_binary("A" ++ integer_to_list(KeySize) ++ "GCM"), JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWEMap = maps:merge(#{ <<"enc">> => ENC }, ALGMap), {Key, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({JWEMap, GCMMap, Extras}, ?LET({_Key, _JWKMap, JWEMap}, jwk_jwe_maps(), {JWEMap, aes_gcm_map(JWEMap), binary_map()}), maps:merge(maps:merge(Extras, GCMMap), JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_key_encrypt_and_key_decrypt() -> ?FORALL({_Key, JWK, JWE}, ?LET({Key, JWK, JWE}, jwk_jwe_gen(), {Key, oneof([Key, JWK]), JWE}), begin {DecKey, DecJWE} = jose_jwe:next_cek(JWK, JWE), {EncKey, EncJWE} = jose_jwe:key_encrypt(JWK, DecKey, DecJWE), DecKey =:= jose_jwe:key_decrypt(JWK, EncKey, EncJWE) end). erlang-jose-1.10.1/test/property_test/jose_jwa_pkcs1_props.erl0000644000232200023220000001331413605433351025106 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_pkcs1_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). digest_type() -> oneof([md5, sha, sha224, sha256, sha384, sha512, {hmac, md5, <<>>}, {hmac, sha, <<>>}, {hmac, sha224, <<>>}, {hmac, sha256, <<>>}, {hmac, sha384, <<>>}, {hmac, sha512, <<>>}]). pkcs1_digest() -> oneof([md5, sha, sha256, sha384, sha512]). salt_size() -> non_neg_integer(). modulus_size() -> integer(1024, 1280). % integer(256, 8192) | pos_integer(). exponent_size() -> return(65537). % pos_integer(). rsa_keypair(ModulusSize) -> ?LET(ExponentSize, exponent_size(), begin case public_key:generate_key({rsa, ModulusSize, ExponentSize}) of PrivateKey=#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent} -> {PrivateKey, #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}} end end). %%==================================================================== %% RSAES-OAEP %%==================================================================== rsaes_oaep_encryptor_gen() -> ?LET({DigestType, ModulusSize, PlainText}, ?SUCHTHAT({DigestType, ModulusSize, PlainText}, {digest_type(), modulus_size(), binary()}, ModulusSize >= ((byte_size(do_hash(DigestType, <<>>)) * 2 + 2 + byte_size(PlainText)) * 8)), {rsa_keypair(ModulusSize), ModulusSize, DigestType, PlainText}). rsaes_oaep_encryptor_with_label_gen() -> ?LET({DigestType, ModulusSize, PlainText}, ?SUCHTHAT({DigestType, ModulusSize, PlainText}, {digest_type(), modulus_size(), binary()}, ModulusSize >= ((byte_size(do_hash(DigestType, <<>>)) * 2 + 2 + byte_size(PlainText)) * 8)), {rsa_keypair(ModulusSize), ModulusSize, DigestType, binary(), PlainText}). prop_rsaes_oaep_encrypt_and_decrypt() -> ?FORALL({{PrivateKey, PublicKey}, _ModulusSize, DigestType, PlainText}, rsaes_oaep_encryptor_gen(), begin {ok, CipherText} = jose_jwa_pkcs1:rsaes_oaep_encrypt(DigestType, PlainText, PublicKey), PlainText =:= jose_jwa_pkcs1:rsaes_oaep_decrypt(DigestType, CipherText, PrivateKey) end). prop_rsaes_oaep_encrypt_and_decrypt_with_label() -> ?FORALL({{PrivateKey, PublicKey}, _ModulusSize, DigestType, Label, PlainText}, rsaes_oaep_encryptor_with_label_gen(), begin {ok, CipherText} = jose_jwa_pkcs1:rsaes_oaep_encrypt(DigestType, PlainText, Label, PublicKey), PlainText =:= jose_jwa_pkcs1:rsaes_oaep_decrypt(DigestType, CipherText, Label, PrivateKey) end). %%==================================================================== %% RSAES-PKCS1-v1_5 %%==================================================================== rsaes_pkcs1_encryptor_gen() -> ?LET({ModulusSize, PlainText}, ?SUCHTHAT({ModulusSize, PlainText}, {modulus_size(), binary()}, ModulusSize >= ((byte_size(PlainText) + 11) * 8)), {rsa_keypair(ModulusSize), ModulusSize, PlainText}). prop_rsaes_pkcs1_encrypt_and_decrypt() -> ?FORALL({{PrivateKey, PublicKey}, _ModulusSize, PlainText}, rsaes_pkcs1_encryptor_gen(), begin {ok, CipherText} = jose_jwa_pkcs1:rsaes_pkcs1_encrypt(PlainText, PublicKey), PlainText =:= jose_jwa_pkcs1:rsaes_pkcs1_decrypt(CipherText, PrivateKey) end). %%==================================================================== %% RSASSA-PKCS1-v1_5 %%==================================================================== rsassa_pkcs1_signer_gen() -> ?LET({DigestType, ModulusSize}, ?SUCHTHAT({DigestType, ModulusSize}, {pkcs1_digest(), modulus_size()}, ModulusSize >= (bit_size(do_hash(DigestType, <<>>)) * 3 + 16)), {rsa_keypair(ModulusSize), ModulusSize, DigestType, binary()}). prop_rsassa_pkcs1_sign_and_verify() -> ?FORALL({{PrivateKey, PublicKey}, _, DigestType, Message}, rsassa_pkcs1_signer_gen(), begin {ok, Signature} = jose_jwa_pkcs1:rsassa_pkcs1_sign(DigestType, Message, PrivateKey), jose_jwa_pkcs1:rsassa_pkcs1_verify(DigestType, Message, Signature, PublicKey) end). %%==================================================================== %% RSASSA-PSS %%==================================================================== rsassa_pss_signer_gen() -> ?LET({DigestType, ModulusSize}, ?SUCHTHAT({DigestType, ModulusSize}, {digest_type(), modulus_size()}, ModulusSize >= (bit_size(do_hash(DigestType, <<>>)) * 2 + 16)), {rsa_keypair(ModulusSize), ModulusSize, DigestType, binary()}). rsassa_pss_signer_with_salt_gen() -> ?LET({DigestType, ModulusSize, SaltSize}, ?SUCHTHAT({DigestType, ModulusSize, SaltSize}, {digest_type(), modulus_size(), salt_size()}, ModulusSize >= (bit_size(do_hash(DigestType, <<>>)) + (SaltSize * 8) + 16)), {rsa_keypair(ModulusSize), ModulusSize, DigestType, binary(SaltSize), binary()}). prop_rsassa_pss_sign_and_verify() -> ?FORALL({{PrivateKey, PublicKey}, _, DigestType, Message}, rsassa_pss_signer_gen(), begin {ok, Signature} = jose_jwa_pkcs1:rsassa_pss_sign(DigestType, Message, PrivateKey), jose_jwa_pkcs1:rsassa_pss_verify(DigestType, Message, Signature, PublicKey) end). prop_rsassa_pss_sign_and_verify_with_salt() -> ?FORALL({{PrivateKey, PublicKey}, _ModulusSize, DigestType, Salt, Message}, rsassa_pss_signer_with_salt_gen(), begin {ok, Signature} = jose_jwa_pkcs1:rsassa_pss_sign(DigestType, Message, Salt, PrivateKey), jose_jwa_pkcs1:rsassa_pss_verify(DigestType, Message, Signature, byte_size(Salt), PublicKey) end). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- do_hash(DigestType, PlainText) when is_atom(DigestType) -> crypto:hash(DigestType, PlainText); do_hash({hmac, DigestType, Key}, PlainText) -> crypto:hmac(DigestType, Key, PlainText). erlang-jose-1.10.1/test/property_test/jose_jwa_curve25519_props.erl0000644000232200023220000000345513605433351025624 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_curve25519_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). eddsa_secret() -> binary(32). eddsa_keypair(Secret) -> {PK, SK} = jose_curve25519:eddsa_keypair(Secret), {SK, PK}. x25519_secret() -> binary(32). x25519_keypair(Secret) -> {PK, SK} = jose_curve25519:x25519_keypair(Secret), {SK, PK}. eddsa_keypair_gen() -> ?LET(Secret, eddsa_secret(), eddsa_keypair(Secret)). prop_eddsa_secret_to_public() -> ?FORALL({<< Secret:32/binary, _/binary >>, PK}, eddsa_keypair_gen(), begin PK =:= jose_jwa_curve25519:eddsa_secret_to_public(Secret) end). prop_ed25519_sign_and_verify() -> ?FORALL({{SK, PK}, M}, {eddsa_keypair_gen(), binary()}, begin S = jose_jwa_curve25519:ed25519_sign(M, SK), jose_jwa_curve25519:ed25519_verify(S, M, PK) end). prop_ed25519ph_sign_and_verify() -> ?FORALL({{SK, PK}, M}, {eddsa_keypair_gen(), binary()}, begin S = jose_jwa_curve25519:ed25519ph_sign(M, SK), jose_jwa_curve25519:ed25519ph_verify(S, M, PK) end). x25519_keypair_gen() -> ?LET(Secret, x25519_secret(), x25519_keypair(Secret)). x25519_keypairs_gen() -> ?LET({AliceSecret, BobSecret}, {x25519_secret(), x25519_secret()}, {x25519_keypair(AliceSecret), x25519_keypair(BobSecret)}). prop_x25519_secret_to_public() -> ?FORALL({SK, PK}, x25519_keypair_gen(), begin PK =:= jose_jwa_curve25519:x25519_secret_to_public(SK) end). prop_x25519_shared_secret() -> ?FORALL({{AliceSK, AlicePK}, {BobSK, BobPK}}, x25519_keypairs_gen(), begin K = jose_jwa_curve25519:x25519_shared_secret(AliceSK, BobPK), K =:= jose_jwa_curve25519:x25519_shared_secret(BobSK, AlicePK) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_rsa_props.erl0000644000232200023220000001252213605433351025553 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_rsa_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). modulus_size() -> integer(1024, 1280). % integer(256, 8192) | pos_integer(). exponent_size() -> return(65537). % pos_integer(). rsa_keypair(ModulusSize) -> ?LET(ExponentSize, exponent_size(), begin case public_key:generate_key({rsa, ModulusSize, ExponentSize}) of PrivateKey=#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent} -> {PrivateKey, #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}} end end). jwk_map() -> ?LET({_ModulusSize, Keys={PrivateKey, _}}, ?LET(ModulusSize, modulus_size(), {ModulusSize, rsa_keypair(ModulusSize)}), begin PrivateJWK = jose_jwk:from_key(PrivateKey), PrivateJWKMap = element(2, jose_jwk:to_map(PrivateJWK)), {Keys, PrivateJWKMap} end). jwk_map_sfm_and_crt() -> ?LET({Keys, PrivateJWKMapCRT}, jwk_map(), begin PrivateJWKMapSFM = maps:without([ <<"dp">>, <<"dq">>, <<"p">>, <<"q">>, <<"qi">> ], PrivateJWKMapCRT), {Keys, PrivateJWKMapCRT, PrivateJWKMapSFM} end). jwk_gen() -> ?LET({Keys, PrivateJWKMap}, jwk_map(), {Keys, jose_jwk:from_map(PrivateJWKMap)}). prop_convert_sfm_to_crt() -> ?FORALL({{PrivateKey, PublicKey}, PrivateJWKMapCRT, PrivateJWKMapSFM}, ?LET({{Keys, JWKMapCRT, JWKMapSFM}, Extras}, {jwk_map_sfm_and_crt(), binary_map()}, {Keys, maps:merge(Extras, JWKMapCRT), maps:merge(Extras, JWKMapSFM)}), begin PrivateJWKCRT = jose_jwk:from_map(PrivateJWKMapCRT), PrivateJWKSFM = jose_jwk:from_map(PrivateJWKMapSFM), ThumbprintCRT = jose_jwk:thumbprint(PrivateJWKMapCRT), ThumbprintSFM = jose_jwk:thumbprint(PrivateJWKMapSFM), PrivateJWKCRT =:= PrivateJWKSFM andalso PrivateKey =:= element(2, jose_jwk:to_key(PrivateJWKCRT)) andalso PrivateKey =:= element(2, jose_jwk:to_key(PrivateJWKSFM)) andalso PublicKey =:= element(2, jose_jwk:to_public_key(PrivateJWKCRT)) andalso PublicKey =:= element(2, jose_jwk:to_public_key(PrivateJWKSFM)) andalso ThumbprintCRT =:= ThumbprintSFM end). prop_from_der_and_to_der() -> ?FORALL({{_, PublicKey}, PrivateJWK, Password}, ?LET({{Keys, PrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, PrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin PublicJWK = jose_jwk:from_key(PublicKey), PublicDER = element(2, jose_jwk:to_der(PublicJWK)), PrivateDER = element(2, jose_jwk:to_der(PrivateJWK)), EncryptedPrivateDER = element(2, jose_jwk:to_der(Password, PrivateJWK)), PrivateJWK =:= jose_jwk:from_der(PrivateDER) andalso PrivateJWK =:= jose_jwk:from_der(Password, EncryptedPrivateDER) andalso PublicJWK =:= jose_jwk:from_der(PublicDER) end). prop_from_map_and_to_map() -> ?FORALL({{PrivateKey, PublicKey}, PrivateJWKMap}, ?LET({{Keys, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Keys, maps:merge(Extras, JWKMap)}), begin PrivateJWK = jose_jwk:from_map(PrivateJWKMap), PublicJWK = jose_jwk:to_public(PrivateJWK), PublicJWKMap = element(2, jose_jwk:to_map(PublicJWK)), PublicThumbprint = jose_jwk:thumbprint(PublicJWK), PrivateJWKMap =:= element(2, jose_jwk:to_map(PrivateJWK)) andalso PrivateKey =:= element(2, jose_jwk:to_key(PrivateJWK)) andalso PublicKey =:= element(2, jose_jwk:to_public_key(PrivateJWK)) andalso PublicJWKMap =:= element(2, jose_jwk:to_public_map(PrivateJWK)) andalso PublicThumbprint =:= jose_jwk:thumbprint(PrivateJWK) end). prop_from_pem_and_to_pem() -> ?FORALL({{_, PublicKey}, PrivateJWK, Password}, ?LET({{Keys, PrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, PrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin PublicJWK = jose_jwk:from_key(PublicKey), PublicPEM = element(2, jose_jwk:to_pem(PublicJWK)), EncryptedPublicPEM = element(2, jose_jwk:to_pem(Password, PublicJWK)), PrivatePEM = element(2, jose_jwk:to_pem(PrivateJWK)), EncryptedPrivatePEM = element(2, jose_jwk:to_pem(Password, PrivateJWK)), PrivateJWK =:= jose_jwk:from_pem(PrivatePEM) andalso PrivateJWK =:= jose_jwk:from_pem(Password, EncryptedPrivatePEM) andalso PublicJWK =:= jose_jwk:from_pem(PublicPEM) andalso PublicJWK =:= jose_jwk:from_pem(Password, EncryptedPublicPEM) end). prop_block_encrypt_and_block_decrypt() -> ?FORALL({{{_, PublicKey}, PrivateJWK}, PlainText}, {jwk_gen(), binary()}, begin PublicJWK = jose_jwk:from_key(PublicKey), Encrypted = jose_jwk:block_encrypt(PlainText, PublicJWK), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, JWE} = jose_jwk:box_decrypt(Encrypted, PrivateJWK), {PlainText, JWE} =:= Decrypted andalso {PlainText, JWE} =:= jose_jwk:block_decrypt(CompactEncrypted, PrivateJWK) end). prop_sign_and_verify() -> ?FORALL({_Keys, JWK, Message}, ?LET({Keys, JWK}, jwk_gen(), {Keys, JWK, binary()}), begin Signed = jose_jwk:sign(Message, JWK), CompactSigned = jose_jws:compact(Signed), Verified = {_, _, JWS} = jose_jwk:verify(Signed, JWK), {true, Message, JWS} =:= Verified andalso {true, Message, JWS} =:= jose_jwk:verify(CompactSigned, JWK) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_okp_ed448ph_props.erl0000644000232200023220000000445413605433351027024 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_okp_ed448ph_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). ed448ph_secret() -> binary(57). ed448ph_keypair(Secret) -> {PK, SK} = jose_curve448:eddsa_keypair(Secret), {SK, PK}. jwk_map() -> ?LET({AliceSecret, BobSecret}, {ed448ph_secret(), ed448ph_secret()}, begin AliceKeys = {AlicePrivateKey, _} = ed448ph_keypair(AliceSecret), BobKeys = ed448ph_keypair(BobSecret), AlicePrivateJWK = jose_jwk:from_okp({'Ed448ph', AlicePrivateKey}), {_, AlicePrivateJWKMap} = jose_jwk:to_map(AlicePrivateJWK), Keys = {AliceKeys, BobKeys}, {Keys, AlicePrivateJWKMap} end). jwk_gen() -> ?LET({Keys, AlicePrivateJWKMap}, jwk_map(), {Keys, jose_jwk:from_map(AlicePrivateJWKMap)}). prop_from_map_and_to_map() -> ?FORALL({{{AlicePrivateKey, AlicePublicKey}, _}, AlicePrivateJWKMap}, ?LET({{Keys, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Keys, maps:merge(Extras, JWKMap)}), begin AlicePrivateJWK = jose_jwk:from_map(AlicePrivateJWKMap), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicJWKMap = element(2, jose_jwk:to_map(AlicePublicJWK)), AlicePublicThumbprint = jose_jwk:thumbprint(AlicePublicJWK), AlicePrivateJWKMap =:= element(2, jose_jwk:to_map(AlicePrivateJWK)) andalso AlicePrivateKey =:= element(2, jose_jwk:to_key(AlicePrivateJWK)) andalso AlicePublicKey =:= element(2, jose_jwk:to_public_key(AlicePrivateJWK)) andalso AlicePublicJWKMap =:= element(2, jose_jwk:to_public_map(AlicePrivateJWK)) andalso AlicePublicThumbprint =:= jose_jwk:thumbprint(AlicePrivateJWK) end). prop_sign_and_verify() -> ?FORALL({_Keys, JWK, Message}, ?LET({Keys, JWK}, jwk_gen(), {Keys, JWK, binary()}), begin Signed = jose_jwk:sign(Message, JWK), CompactSigned = jose_jws:compact(Signed), Verified = {_, _, JWS} = jose_jwk:verify(Signed, JWK), {true, Message, JWS} =:= Verified andalso {true, Message, JWS} =:= jose_jwk:verify(CompactSigned, JWK) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_oct_props.erl0000644000232200023220000000421113605433351025547 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_oct_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). jwk_map() -> ?LET(Key, binary(), begin JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, {Key, JWKMap} end). jwk_map(KeySize) -> ?LET(Key, binary(KeySize), begin JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, {Key, JWKMap} end). jwk_gen() -> ?LET({Key, JWKMap}, jwk_map(32), {Key, jose_jwk:from_map(JWKMap)}). prop_from_map_and_to_map() -> ?FORALL({Key, JWKMap}, ?LET({{Key, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Key, maps:merge(Extras, JWKMap)}), begin JWK = jose_jwk:from_map(JWKMap), Error = try jose_jwk:to_public(JWK) catch error:Reason:_ -> Reason end, PublicThumbprint = jose_jwk:thumbprint(JWK), JWKMap =:= element(2, jose_jwk:to_map(JWK)) andalso Key =:= element(2, jose_jwk:to_key(JWK)) andalso {not_supported, [to_public_map]} =:= Error andalso PublicThumbprint =:= jose_jwk:thumbprint(JWK) end). prop_block_encrypt_and_block_decrypt() -> ?FORALL({{_Key, JWK}, PlainText}, {jwk_gen(), binary()}, begin Encrypted = jose_jwk:block_encrypt(PlainText, JWK), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, JWE} = jose_jwk:block_decrypt(Encrypted, JWK), {PlainText, JWE} =:= Decrypted andalso {PlainText, JWE} =:= jose_jwk:block_decrypt(CompactEncrypted, JWK) end). prop_sign_and_verify() -> ?FORALL({_Key, JWK, Message}, ?LET({Key, JWK}, jwk_gen(), {Key, JWK, binary()}), begin Signed = jose_jwk:sign(Message, JWK), CompactSigned = jose_jws:compact(Signed), Verified = {_, _, JWS} = jose_jwk:verify(Signed, JWK), {true, Message, JWS} =:= Verified andalso {true, Message, JWS} =:= jose_jwk:verify(CompactSigned, JWK) end). erlang-jose-1.10.1/test/property_test/jose_jws_alg_rsa_pss_props.erl0000644000232200023220000000405413605433351026405 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jws_alg_rsa_pss_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). alg() -> oneof([ <<"PS256">>, <<"PS384">>, <<"PS512">> ]). modulus_size() -> integer(1024, 1280). % integer(256, 8192) | pos_integer(). exponent_size() -> return(65537). % pos_integer(). rsa_keypair(ModulusSize) -> ?LET(ExponentSize, exponent_size(), begin case public_key:generate_key({rsa, ModulusSize, ExponentSize}) of PrivateKey=#'RSAPrivateKey'{modulus=Modulus, publicExponent=PublicExponent} -> {PrivateKey, #'RSAPublicKey'{modulus=Modulus, publicExponent=PublicExponent}} end end). jwk_jws_maps() -> ?LET({ModulusSize, ALG, {PrivateKey, PublicKey}}, ?LET(ModulusSize, modulus_size(), {ModulusSize, alg(), rsa_keypair(ModulusSize)}), begin JWKSigner = jose_jwk:from_key(PrivateKey), JWKVerifier = jose_jwk:from_key(PublicKey), JWSMap = #{ <<"alg">> => ALG }, {ModulusSize, {JWKSigner, JWKVerifier}, JWSMap} end). jwk_jws_gen() -> ?LET({ModulusSize, JWKs, JWSMap}, jwk_jws_maps(), {ModulusSize, JWKs, jose_jws:from_map(JWSMap)}). prop_from_map_and_to_map() -> ?FORALL(JWSMap, ?LET({ALG, Extras}, {alg(), binary_map()}, maps:merge(Extras, #{ <<"alg">> => ALG })), begin JWS = jose_jws:from_map(JWSMap), JWSMap =:= element(2, jose_jws:to_map(JWS)) end). prop_sign_and_verify() -> ?FORALL({{_ModulusSize, {JWKSigner, JWKVerifier}, JWS}, Message}, {jwk_jws_gen(), binary()}, begin Signed = jose_jws:sign(JWKSigner, Message, JWS), CompactSigned = jose_jws:compact(Signed), {true, Message, JWS} =:= jose_jws:verify(JWKVerifier, Signed) andalso {true, Message, JWS} =:= jose_jws:verify(JWKVerifier, CompactSigned) end). erlang-jose-1.10.1/test/property_test/jose_jwk_kty_ec_props.erl0000644000232200023220000001076113605433351025360 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwk_kty_ec_props). -include_lib("public_key/include/public_key.hrl"). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). ec_curve() -> oneof([ secp256r1, secp384r1, secp521r1 ]). ec_keypair(CurveId) -> ECPrivateKey = #'ECPrivateKey'{parameters=ECParameters, publicKey=Octets0} = public_key:generate_key({namedCurve, pubkey_cert_records:namedCurves(CurveId)}), Octets = case Octets0 of {_, Octets1} -> Octets1; _ -> Octets0 end, ECPoint = #'ECPoint'{point=Octets}, ECPublicKey = {ECPoint, ECParameters}, {ECPrivateKey, ECPublicKey}. jwk_map() -> ?LET(CurveId, ec_curve(), begin AliceKeys = {AlicePrivateKey, _} = ec_keypair(CurveId), BobKeys = ec_keypair(CurveId), AlicePrivateJWK = jose_jwk:from_key(AlicePrivateKey), {_, AlicePrivateJWKMap} = jose_jwk:to_map(AlicePrivateJWK), Keys = {AliceKeys, BobKeys}, {Keys, AlicePrivateJWKMap} end). jwk_gen() -> ?LET({Keys, AlicePrivateJWKMap}, jwk_map(), {Keys, jose_jwk:from_map(AlicePrivateJWKMap)}). prop_from_der_and_to_der() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivateDER = element(2, jose_jwk:to_der(AlicePrivateJWK)), EncryptedAlicePrivateDER = element(2, jose_jwk:to_der(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicDER = element(2, jose_jwk:to_der(AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_der(AlicePrivateDER) andalso AlicePrivateJWK =:= jose_jwk:from_der(Password, EncryptedAlicePrivateDER) andalso AlicePublicJWK =:= jose_jwk:from_der(AlicePublicDER) end). prop_from_map_and_to_map() -> ?FORALL({{{AlicePrivateKey, AlicePublicKey}, _}, AlicePrivateJWKMap}, ?LET({{Keys, JWKMap}, Extras}, {jwk_map(), binary_map()}, {Keys, maps:merge(Extras, JWKMap)}), begin AlicePrivateJWK = jose_jwk:from_map(AlicePrivateJWKMap), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicJWKMap = element(2, jose_jwk:to_map(AlicePublicJWK)), AlicePublicThumbprint = jose_jwk:thumbprint(AlicePublicJWK), AlicePrivateJWKMap =:= element(2, jose_jwk:to_map(AlicePrivateJWK)) andalso AlicePrivateKey =:= element(2, jose_jwk:to_key(AlicePrivateJWK)) andalso AlicePublicKey =:= element(2, jose_jwk:to_public_key(AlicePrivateJWK)) andalso AlicePublicJWKMap =:= element(2, jose_jwk:to_public_map(AlicePrivateJWK)) andalso AlicePublicThumbprint =:= jose_jwk:thumbprint(AlicePrivateJWK) end). prop_from_pem_and_to_pem() -> ?FORALL({_Keys, AlicePrivateJWK, Password}, ?LET({{Keys, AlicePrivateJWK}, Bytes}, {jwk_gen(), binary()}, {Keys, AlicePrivateJWK, jose_jwa_base64url:encode(Bytes)}), begin AlicePrivatePEM = element(2, jose_jwk:to_pem(AlicePrivateJWK)), EncryptedAlicePrivatePEM = element(2, jose_jwk:to_pem(Password, AlicePrivateJWK)), AlicePublicJWK = jose_jwk:to_public(AlicePrivateJWK), AlicePublicPEM = element(2, jose_jwk:to_pem(AlicePublicJWK)), AlicePrivateJWK =:= jose_jwk:from_pem(AlicePrivatePEM) andalso AlicePrivateJWK =:= jose_jwk:from_pem(Password, EncryptedAlicePrivatePEM) andalso AlicePublicJWK =:= jose_jwk:from_pem(AlicePublicPEM) end). prop_box_encrypt_and_box_decrypt() -> ?FORALL({{{_, {BobPrivateKey, BobPublicKey}}, AlicePrivateJWK}, PlainText}, {jwk_gen(), binary()}, begin BobPrivateJWK = jose_jwk:from_key(BobPrivateKey), BobPublicJWK = jose_jwk:from_key(BobPublicKey), Encrypted = jose_jwk:box_encrypt_ecdh_es(PlainText, BobPublicJWK, AlicePrivateJWK), CompactEncrypted = jose_jwe:compact(Encrypted), Decrypted = {_, JWE} = jose_jwk:box_decrypt_ecdh_es(Encrypted, BobPrivateJWK), {PlainText, JWE} =:= Decrypted andalso {PlainText, JWE} =:= jose_jwk:block_decrypt(CompactEncrypted, BobPrivateJWK) end). prop_sign_and_verify() -> ?FORALL({_Keys, JWK, Message}, ?LET({Keys, JWK}, jwk_gen(), {Keys, JWK, binary()}), begin Signed = jose_jwk:sign(Message, JWK), CompactSigned = jose_jws:compact(Signed), Verified = {_, _, JWS} = jose_jwk:verify(Signed, JWK), {true, Message, JWS} =:= Verified andalso {true, Message, JWS} =:= jose_jwk:verify(CompactSigned, JWK) end). erlang-jose-1.10.1/test/property_test/jose_jwe_alg_c20p_kw_props.erl0000644000232200023220000000354013605433351026161 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_alg_c20p_kw_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). key_size() -> return(256). key_gen() -> ?LET(KeySize, key_size(), {KeySize, binary(KeySize div 8)}). alg_map(256) -> return(#{ <<"alg">> => <<"C20PKW">> }). extra_map(_) -> oneof([ #{}, #{ <<"iv">> => jose_jwa_base64url:encode(crypto:strong_rand_bytes(12)), <<"tag">> => jose_jwa_base64url:encode(crypto:strong_rand_bytes(8)) } ]). jwk_jwe_maps() -> ?LET({_KeySize, Key, ALGMap}, ?LET({KeySize, Key}, key_gen(), {KeySize, Key, alg_map(KeySize)}), begin ENC = <<"C20P">>, JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWEMap = maps:merge(#{ <<"enc">> => ENC }, ALGMap), {Key, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({JWEMap, ExtraMap, Extras}, ?LET({_Key, _JWKMap, JWEMap}, jwk_jwe_maps(), {JWEMap, extra_map(JWEMap), binary_map()}), maps:merge(maps:merge(Extras, ExtraMap), JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_key_encrypt_and_key_decrypt() -> ?FORALL({_Key, JWK, JWE}, ?LET({Key, JWK, JWE}, jwk_jwe_gen(), {Key, oneof([Key, JWK]), JWE}), begin {DecKey, DecJWE} = jose_jwe:next_cek(JWK, JWE), {EncKey, EncJWE} = jose_jwe:key_encrypt(JWK, DecKey, DecJWE), DecKey =:= jose_jwe:key_decrypt(JWK, EncKey, EncJWE) end). erlang-jose-1.10.1/test/property_test/jose_jwe_zip_props.erl0000644000232200023220000000366413605433351024702 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_zip_props). -include_lib("proper/include/proper.hrl"). % -compile(export_all). base64url_binary() -> ?LET(Binary, binary(), jose_jwa_base64url:encode(Binary)). binary_map() -> ?LET(List, list({base64url_binary(), base64url_binary()}), maps:from_list(List)). enc() -> oneof([ <<"A128GCM">>, <<"A192GCM">>, <<"A256GCM">>, <<"C20P">>, <<"XC20P">> ]). jwk_jwe_maps() -> ?LET(ENC, enc(), begin FakeJWEMap = #{ <<"alg">> => <<"RSA1_5">>, <<"enc">> => ENC }, FakeJWE = jose_jwe:from_map(FakeJWEMap), {Key, _} = jose_jwe:next_cek(undefined, FakeJWE), JWKMap = #{ <<"kty">> => <<"oct">>, <<"k">> => jose_jwa_base64url:encode(Key) }, JWEMap = #{ <<"alg">> => <<"dir">>, <<"enc">> => ENC, <<"zip">> => <<"DEF">> }, {Key, JWKMap, JWEMap} end). jwk_jwe_gen() -> ?LET({Key, JWKMap, JWEMap}, jwk_jwe_maps(), {Key, jose_jwk:from_map(JWKMap), jose_jwe:from_map(JWEMap)}). prop_from_map_and_to_map() -> ?FORALL(JWEMap, ?LET({{_Key, _JWKMap, JWEMap}, Extras}, {jwk_jwe_maps(), binary_map()}, maps:merge(Extras, JWEMap)), begin JWE = jose_jwe:from_map(JWEMap), JWEMap =:= element(2, jose_jwe:to_map(JWE)) end). prop_block_encrypt_and_block_decrypt() -> ?FORALL({CEK, IV, JWK, JWE, PlainText}, ?LET({CEK, JWK, JWE}, jwk_jwe_gen(), {CEK, jose_jwe:next_iv(JWE), JWK, JWE, binary()}), begin Encrypted = jose_jwe:block_encrypt(JWK, PlainText, CEK, IV, JWE), CompactEncrypted = jose_jwe:compact(Encrypted), PlainText =:= element(1, jose_jwe:block_decrypt(JWK, CompactEncrypted)) end). prop_compress_and_uncompress() -> ?FORALL({{_CEK, _JWK, JWE}, PlainText}, {jwk_jwe_gen(), binary()}, begin CipherText = jose_jwe:compress(PlainText, JWE), CipherText =/= PlainText andalso PlainText =:= jose_jwe:uncompress(CipherText, JWE) end). erlang-jose-1.10.1/test/jose_jwe_SUITE.erl0000644000232200023220000001740113605433351020615 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwe_SUITE). -include_lib("common_test/include/ct.hrl"). -include("jose.hrl"). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([alg_aes_kw_from_map_and_to_map/1]). -export([alg_aes_kw_key_encrypt_and_key_decrypt/1]). -export([alg_c20p_kw_from_map_and_to_map/1]). -export([alg_c20p_kw_key_encrypt_and_key_decrypt/1]). -export([alg_dir_from_map_and_to_map/1]). -export([alg_dir_key_decrypt/1]). -export([alg_dir_key_encrypt/1]). -export([alg_dir_next_cek/1]). -export([alg_ecdh_1pu_from_map_and_to_map/1]). -export([alg_ecdh_1pu_key_encrypt_and_key_decrypt/1]). -export([alg_ecdh_es_from_map_and_to_map/1]). -export([alg_ecdh_es_key_encrypt_and_key_decrypt/1]). -export([alg_pbes2_from_map_and_to_map/1]). -export([alg_pbes2_key_encrypt_and_key_decrypt/1]). -export([alg_rsa_from_map_and_to_map/1]). -export([alg_rsa_key_encrypt_and_key_decrypt/1]). -export([alg_xc20p_kw_from_map_and_to_map/1]). -export([alg_xc20p_kw_key_encrypt_and_key_decrypt/1]). -export([enc_aes_from_map_and_to_map/1]). -export([enc_aes_block_encrypt_and_block_decrypt/1]). -export([enc_c20p_from_map_and_to_map/1]). -export([enc_c20p_block_encrypt_and_block_decrypt/1]). -export([enc_xc20p_from_map_and_to_map/1]). -export([enc_xc20p_block_encrypt_and_block_decrypt/1]). -export([zip_from_map_and_to_map/1]). -export([zip_block_encrypt_and_block_decrypt/1]). -export([zip_compress_and_uncompress/1]). all() -> [ {group, jose_jwe_alg_aes_kw}, {group, jose_jwe_alg_c20p_kw}, {group, jose_jwe_alg_dir}, {group, jose_jwe_alg_ecdh_1pu}, {group, jose_jwe_alg_ecdh_es}, {group, jose_jwe_alg_pbes2}, {group, jose_jwe_alg_rsa}, {group, jose_jwe_alg_xc20p_kw}, {group, jose_jwe_enc_aes}, {group, jose_jwe_enc_c20p}, {group, jose_jwe_enc_xc20p}, {group, jose_jwe_zip} ]. groups() -> [ {jose_jwe_alg_aes_kw, [parallel], [ alg_aes_kw_from_map_and_to_map, alg_aes_kw_key_encrypt_and_key_decrypt ]}, {jose_jwe_alg_c20p_kw, [parallel], [ alg_c20p_kw_from_map_and_to_map, alg_c20p_kw_key_encrypt_and_key_decrypt ]}, {jose_jwe_alg_dir, [parallel], [ alg_dir_from_map_and_to_map, alg_dir_key_decrypt, alg_dir_key_encrypt, alg_dir_next_cek ]}, {jose_jwe_alg_ecdh_1pu, [parallel], [ alg_ecdh_1pu_from_map_and_to_map, alg_ecdh_1pu_key_encrypt_and_key_decrypt ]}, {jose_jwe_alg_ecdh_es, [parallel], [ alg_ecdh_es_from_map_and_to_map, alg_ecdh_es_key_encrypt_and_key_decrypt ]}, {jose_jwe_alg_pbes2, [parallel], [ alg_pbes2_from_map_and_to_map, alg_pbes2_key_encrypt_and_key_decrypt ]}, {jose_jwe_alg_rsa, [parallel], [ alg_rsa_from_map_and_to_map, alg_rsa_key_encrypt_and_key_decrypt ]}, {jose_jwe_alg_xc20p_kw, [parallel], [ alg_xc20p_kw_from_map_and_to_map, alg_xc20p_kw_key_encrypt_and_key_decrypt ]}, {jose_jwe_enc_aes, [parallel], [ enc_aes_from_map_and_to_map, enc_aes_block_encrypt_and_block_decrypt ]}, {jose_jwe_enc_c20p, [parallel], [ enc_c20p_from_map_and_to_map, enc_c20p_block_encrypt_and_block_decrypt ]}, {jose_jwe_enc_xc20p, [parallel], [ enc_xc20p_from_map_and_to_map, enc_xc20p_block_encrypt_and_block_decrypt ]}, {jose_jwe_zip, [parallel], [ zip_from_map_and_to_map, zip_block_encrypt_and_block_decrypt, zip_compress_and_uncompress ]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), ct_property_test:init_per_suite(Config). end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(Group, Config) -> jose_ct:start(Group, Config). end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== alg_aes_kw_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_alg_aes_kw_props:prop_from_map_and_to_map(), Config). alg_aes_kw_key_encrypt_and_key_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_aes_kw_props:prop_key_encrypt_and_key_decrypt(), Config). alg_c20p_kw_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_alg_c20p_kw_props:prop_from_map_and_to_map(), Config). alg_c20p_kw_key_encrypt_and_key_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_c20p_kw_props:prop_key_encrypt_and_key_decrypt(), Config). alg_dir_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_alg_dir_props:prop_from_map_and_to_map(), Config). alg_dir_key_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_dir_props:prop_key_decrypt(), Config). alg_dir_key_encrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_dir_props:prop_key_encrypt(), Config). alg_dir_next_cek(Config) -> ct_property_test:quickcheck( jose_jwe_alg_dir_props:prop_next_cek(), Config). alg_ecdh_1pu_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_alg_ecdh_1pu_props:prop_from_map_and_to_map(), Config). alg_ecdh_1pu_key_encrypt_and_key_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_ecdh_1pu_props:prop_key_encrypt_and_key_decrypt(), Config). alg_ecdh_es_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_alg_ecdh_es_props:prop_from_map_and_to_map(), Config). alg_ecdh_es_key_encrypt_and_key_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_ecdh_es_props:prop_key_encrypt_and_key_decrypt(), Config). alg_pbes2_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_alg_pbes2_props:prop_from_map_and_to_map(), Config). alg_pbes2_key_encrypt_and_key_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_pbes2_props:prop_key_encrypt_and_key_decrypt(), Config). alg_rsa_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_alg_rsa_props:prop_from_map_and_to_map(), Config). alg_rsa_key_encrypt_and_key_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_rsa_props:prop_key_encrypt_and_key_decrypt(), Config). alg_xc20p_kw_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_alg_xc20p_kw_props:prop_from_map_and_to_map(), Config). alg_xc20p_kw_key_encrypt_and_key_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_alg_xc20p_kw_props:prop_key_encrypt_and_key_decrypt(), Config). enc_aes_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_enc_aes_props:prop_from_map_and_to_map(), Config). enc_aes_block_encrypt_and_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_enc_aes_props:prop_block_encrypt_and_block_decrypt(), Config). enc_c20p_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_enc_c20p_props:prop_from_map_and_to_map(), Config). enc_c20p_block_encrypt_and_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_enc_c20p_props:prop_block_encrypt_and_block_decrypt(), Config). enc_xc20p_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_enc_xc20p_props:prop_from_map_and_to_map(), Config). enc_xc20p_block_encrypt_and_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_enc_xc20p_props:prop_block_encrypt_and_block_decrypt(), Config). zip_from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwe_zip_props:prop_from_map_and_to_map(), Config). zip_block_encrypt_and_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwe_zip_props:prop_block_encrypt_and_block_decrypt(), Config). zip_compress_and_uncompress(Config) -> ct_property_test:quickcheck( jose_jwe_zip_props:prop_compress_and_uncompress(), Config). erlang-jose-1.10.1/test/Dockerfile0000644000232200023220000000052013605433351017317 0ustar debalancedebalanceARG OTP_VERSION=alpine FROM erlang:${OTP_VERSION}-alpine # Setup environment ENV LANG=C.UTF-8 TERM=xterm # Add dependencies RUN apk upgrade --update musl && \ apk add --no-cache autoconf automake bash bc build-base curl git libtool make openssl python rsync unzip && \ rm -rf /var/cache/apk/* RUN mkdir /build WORKDIR /build erlang-jose-1.10.1/test/jose_jwt_SUITE.erl0000644000232200023220000000277213605433351020641 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwt_SUITE). -include_lib("common_test/include/ct.hrl"). -include("jose.hrl"). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([from_map_and_to_map/1]). -export([encrypt_and_decrypt/1]). -export([sign_and_verify/1]). all() -> [ {group, jose_jwt} ]. groups() -> [ {jose_jwt, [parallel], [ from_map_and_to_map, encrypt_and_decrypt, sign_and_verify ]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), ct_property_test:init_per_suite(Config). end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(Group, Config) -> jose_ct:start(Group, Config). end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== from_map_and_to_map(Config) -> ct_property_test:quickcheck( jose_jwt_props:prop_from_map_and_to_map(), Config). encrypt_and_decrypt(Config) -> ct_property_test:quickcheck( jose_jwt_props:prop_encrypt_and_decrypt(), Config). sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwt_props:prop_sign_and_verify(), Config). erlang-jose-1.10.1/test/jose_jwa_SUITE.erl0000644000232200023220000003075213605433351020615 0ustar debalancedebalance%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*- %% vim: ts=4 sw=4 ft=erlang noet -module(jose_jwa_SUITE). -include_lib("common_test/include/ct.hrl"). -include("jose.hrl"). %% ct. -export([all/0]). -export([groups/0]). -export([init_per_suite/1]). -export([end_per_suite/1]). -export([init_per_group/2]). -export([end_per_group/2]). %% Tests. -export([aes_cbc_block_encrypt_and_cbc_block_decrypt/1]). -export([aes_cbc_block_encrypt_and_jwa_block_decrypt/1]). -export([aes_jwa_block_encrypt_and_cbc_block_decrypt/1]). -export([aes_jwa_block_encrypt_and_ecb_block_decrypt/1]). -export([aes_jwa_block_encrypt_and_gcm_block_decrypt/1]). -export([aes_ecb_block_encrypt_and_ecb_block_decrypt/1]). -export([aes_ecb_block_encrypt_and_jwa_block_decrypt/1]). -export([aes_gcm_block_encrypt_and_gcm_block_decrypt/1]). -export([aes_gcm_block_encrypt_and_jwa_block_decrypt/1]). -export([aes_kw_128_128/1]). -export([aes_kw_128_192/1]). -export([aes_kw_128_256/1]). -export([aes_kw_192_192/1]). -export([aes_kw_192_256/1]). -export([aes_kw_256_256/1]). -export([aes_kw_wrap_and_unwrap/1]). -export([concat_kdf/1]). -export([concat_kdf_keylen/1]). -export([constant_time_compare/1]). -export([curve25519_eddsa_secret_to_public/1]). -export([curve448_eddsa_secret_to_public/1]). -export([ed25519_sign_and_verify/1]). -export([ed25519ph_sign_and_verify/1]). -export([ed448_sign_and_verify/1]). -export([ed448ph_sign_and_verify/1]). -export([pkcs1_rsaes_oaep_encrypt_and_decrypt/1]). -export([pkcs1_rsaes_oaep_encrypt_and_decrypt_with_label/1]). -export([pkcs1_rsaes_pkcs1_encrypt_and_decrypt/1]). -export([pkcs1_rsassa_pkcs1_sign_and_verify/1]). -export([pkcs1_rsassa_pss_sign_and_verify/1]). -export([pkcs1_rsassa_pss_sign_and_verify_with_salt/1]). -export([pkcs5_pbkdf1/1]). -export([pkcs5_pbkdf1_iterations/1]). -export([pkcs5_pbkdf2/1]). -export([pkcs5_pbkdf2_iterations/1]). -export([pkcs5_pbkdf2_iterations_keylen/1]). -export([pkcs7_pad_and_unpad/1]). -export([x25519_secret_to_public/1]). -export([x25519_shared_secret/1]). -export([x448_secret_to_public/1]). -export([x448_shared_secret/1]). all() -> [ constant_time_compare, {group, jose_jwa_aes}, {group, jose_jwa_aes_kw}, {group, jose_jwa_concat_kdf}, {group, jose_jwa_curve25519}, {group, jose_jwa_curve448}, {group, jose_jwa_pkcs1}, % {group, jose_jwa_pkcs5}, {group, jose_jwa_pkcs7} ]. groups() -> [ {jose_jwa_aes, [parallel], [ aes_cbc_block_encrypt_and_cbc_block_decrypt, aes_cbc_block_encrypt_and_jwa_block_decrypt, aes_jwa_block_encrypt_and_cbc_block_decrypt, aes_jwa_block_encrypt_and_ecb_block_decrypt, aes_jwa_block_encrypt_and_gcm_block_decrypt, aes_ecb_block_encrypt_and_ecb_block_decrypt, aes_ecb_block_encrypt_and_jwa_block_decrypt, aes_gcm_block_encrypt_and_gcm_block_decrypt, aes_gcm_block_encrypt_and_jwa_block_decrypt ]}, {jose_jwa_aes_kw, [parallel], [ aes_kw_128_128, aes_kw_128_192, aes_kw_128_256, aes_kw_192_192, aes_kw_192_256, aes_kw_256_256, aes_kw_wrap_and_unwrap ]}, {jose_jwa_concat_kdf, [parallel], [ concat_kdf, concat_kdf_keylen ]}, {jose_jwa_curve25519, [parallel], [ curve25519_eddsa_secret_to_public, ed25519_sign_and_verify, ed25519ph_sign_and_verify, x25519_secret_to_public, x25519_shared_secret ]}, {jose_jwa_curve448, [parallel], [ curve448_eddsa_secret_to_public, ed448_sign_and_verify, ed448ph_sign_and_verify, x448_secret_to_public, x448_shared_secret ]}, {jose_jwa_pkcs1, [parallel], [ pkcs1_rsaes_oaep_encrypt_and_decrypt, pkcs1_rsaes_oaep_encrypt_and_decrypt_with_label, pkcs1_rsaes_pkcs1_encrypt_and_decrypt, pkcs1_rsassa_pkcs1_sign_and_verify, pkcs1_rsassa_pss_sign_and_verify, pkcs1_rsassa_pss_sign_and_verify_with_salt ]}, {jose_jwa_pkcs5, [parallel], [ pkcs5_pbkdf1, pkcs5_pbkdf1_iterations, pkcs5_pbkdf2, pkcs5_pbkdf2_iterations, pkcs5_pbkdf2_iterations_keylen ]}, {jose_jwa_pkcs7, [parallel], [ pkcs7_pad_and_unpad ]} ]. init_per_suite(Config) -> application:set_env(jose, crypto_fallback, true), application:set_env(jose, unsecured_signing, true), _ = application:ensure_all_started(jose), ct_property_test:init_per_suite(Config). end_per_suite(_Config) -> _ = application:stop(jose), ok. init_per_group(Group, Config) -> jose_ct:start(Group, Config). end_per_group(_Group, Config) -> jose_ct:stop(Config), ok. %%==================================================================== %% Tests %%==================================================================== aes_cbc_block_encrypt_and_cbc_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_cbc_block_encrypt_and_cbc_block_decrypt(), Config). aes_cbc_block_encrypt_and_jwa_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_cbc_block_encrypt_and_jwa_block_decrypt(), Config). aes_jwa_block_encrypt_and_cbc_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_jwa_block_encrypt_and_cbc_block_decrypt(), Config). aes_jwa_block_encrypt_and_ecb_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_jwa_block_encrypt_and_ecb_block_decrypt(), Config). aes_jwa_block_encrypt_and_gcm_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_jwa_block_encrypt_and_gcm_block_decrypt(), Config). aes_ecb_block_encrypt_and_ecb_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_ecb_block_encrypt_and_ecb_block_decrypt(), Config). aes_ecb_block_encrypt_and_jwa_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_ecb_block_encrypt_and_jwa_block_decrypt(), Config). aes_gcm_block_encrypt_and_gcm_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_gcm_block_encrypt_and_gcm_block_decrypt(), Config). aes_gcm_block_encrypt_and_jwa_block_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_aes_props:prop_gcm_block_encrypt_and_jwa_block_decrypt(), Config). %% See [https://tools.ietf.org/html/rfc3394#section-4.1] aes_kw_128_128(_Config) -> KEK = << 16#000102030405060708090A0B0C0D0E0F:1/unsigned-big-integer-unit:128 >>, KeyData = << 16#00112233445566778899AABBCCDDEEFF:1/unsigned-big-integer-unit:128 >>, CipherText = << 16#1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5:1/unsigned-big-integer-unit:192 >>, CipherText = jose_jwa_aes_kw:wrap(KeyData, KEK), KeyData = jose_jwa_aes_kw:unwrap(CipherText, KEK), true. %% See [https://tools.ietf.org/html/rfc3394#section-4.2] aes_kw_128_192(_Config) -> KEK = << 16#000102030405060708090A0B0C0D0E0F1011121314151617:1/unsigned-big-integer-unit:192 >>, KeyData = << 16#00112233445566778899AABBCCDDEEFF:1/unsigned-big-integer-unit:128 >>, CipherText = << 16#96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D:1/unsigned-big-integer-unit:192 >>, CipherText = jose_jwa_aes_kw:wrap(KeyData, KEK), KeyData = jose_jwa_aes_kw:unwrap(CipherText, KEK), true. %% See [https://tools.ietf.org/html/rfc3394#section-4.3] aes_kw_128_256(_Config) -> KEK = << 16#000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:1/unsigned-big-integer-unit:256 >>, KeyData = << 16#00112233445566778899AABBCCDDEEFF:1/unsigned-big-integer-unit:128 >>, CipherText = << 16#64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7:1/unsigned-big-integer-unit:192 >>, CipherText = jose_jwa_aes_kw:wrap(KeyData, KEK), KeyData = jose_jwa_aes_kw:unwrap(CipherText, KEK), true. %% See [https://tools.ietf.org/html/rfc3394#section-4.4] aes_kw_192_192(_Config) -> KEK = << 16#000102030405060708090A0B0C0D0E0F1011121314151617:1/unsigned-big-integer-unit:192 >>, KeyData = << 16#00112233445566778899AABBCCDDEEFF0001020304050607:1/unsigned-big-integer-unit:192 >>, CipherText = << 16#031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2:1/unsigned-big-integer-unit:256 >>, CipherText = jose_jwa_aes_kw:wrap(KeyData, KEK), KeyData = jose_jwa_aes_kw:unwrap(CipherText, KEK), true. %% See [https://tools.ietf.org/html/rfc3394#section-4.5] aes_kw_192_256(_Config) -> KEK = << 16#000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:1/unsigned-big-integer-unit:256 >>, KeyData = << 16#00112233445566778899AABBCCDDEEFF0001020304050607:1/unsigned-big-integer-unit:192 >>, CipherText = << 16#A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1:1/unsigned-big-integer-unit:256 >>, CipherText = jose_jwa_aes_kw:wrap(KeyData, KEK), KeyData = jose_jwa_aes_kw:unwrap(CipherText, KEK), true. %% See [https://tools.ietf.org/html/rfc3394#section-4.6] aes_kw_256_256(_Config) -> KEK = << 16#000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:1/unsigned-big-integer-unit:256 >>, KeyData = << 16#00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F:1/unsigned-big-integer-unit:256 >>, CipherText = << 16#28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21:2/unsigned-big-integer-unit:160 >>, CipherText = jose_jwa_aes_kw:wrap(KeyData, KEK), KeyData = jose_jwa_aes_kw:unwrap(CipherText, KEK), true. aes_kw_wrap_and_unwrap(Config) -> ct_property_test:quickcheck( jose_jwa_aes_kw_props:prop_wrap_and_unwrap(), Config). concat_kdf(Config) -> ct_property_test:quickcheck( jose_jwa_concat_kdf_props:prop_kdf(), Config). concat_kdf_keylen(Config) -> ct_property_test:quickcheck( jose_jwa_concat_kdf_props:prop_kdf_keylen(), Config). constant_time_compare(Config) -> ct_property_test:quickcheck( jose_jwa_props:prop_constant_time_compare(), Config). curve25519_eddsa_secret_to_public(Config) -> ct_property_test:quickcheck( jose_jwa_curve25519_props:prop_eddsa_secret_to_public(), Config). curve448_eddsa_secret_to_public(Config) -> ct_property_test:quickcheck( jose_jwa_curve448_props:prop_eddsa_secret_to_public(), Config). ed25519_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwa_curve25519_props:prop_ed25519_sign_and_verify(), Config). ed25519ph_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwa_curve25519_props:prop_ed25519ph_sign_and_verify(), Config). ed448_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwa_curve448_props:prop_ed448_sign_and_verify(), Config). ed448ph_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwa_curve448_props:prop_ed448ph_sign_and_verify(), Config). pkcs1_rsaes_oaep_encrypt_and_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs1_props:prop_rsaes_oaep_encrypt_and_decrypt(), Config). pkcs1_rsaes_oaep_encrypt_and_decrypt_with_label(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs1_props:prop_rsaes_oaep_encrypt_and_decrypt_with_label(), Config). pkcs1_rsaes_pkcs1_encrypt_and_decrypt(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs1_props:prop_rsaes_pkcs1_encrypt_and_decrypt(), Config). pkcs1_rsassa_pkcs1_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs1_props:prop_rsassa_pkcs1_sign_and_verify(), Config). pkcs1_rsassa_pss_sign_and_verify(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs1_props:prop_rsassa_pss_sign_and_verify(), Config). pkcs1_rsassa_pss_sign_and_verify_with_salt(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs1_props:prop_rsassa_pss_sign_and_verify_with_salt(), Config). pkcs5_pbkdf1(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs5_props:prop_pbkdf1(), Config). pkcs5_pbkdf1_iterations(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs5_props:prop_pbkdf1_iterations(), Config). pkcs5_pbkdf2(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs5_props:prop_pbkdf2(), Config). pkcs5_pbkdf2_iterations(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs5_props:prop_pbkdf2_iterations(), Config). pkcs5_pbkdf2_iterations_keylen(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs5_props:prop_pbkdf2_iterations_keylen(), Config). pkcs7_pad_and_unpad(Config) -> ct_property_test:quickcheck( jose_jwa_pkcs7_props:prop_pad_and_unpad(), Config). x25519_secret_to_public(Config) -> ct_property_test:quickcheck( jose_jwa_curve25519_props:prop_x25519_secret_to_public(), Config). x25519_shared_secret(Config) -> ct_property_test:quickcheck( jose_jwa_curve25519_props:prop_x25519_shared_secret(), Config). x448_secret_to_public(Config) -> ct_property_test:quickcheck( jose_jwa_curve448_props:prop_x448_secret_to_public(), Config). x448_shared_secret(Config) -> ct_property_test:quickcheck( jose_jwa_curve448_props:prop_x448_shared_secret(), Config). %%%------------------------------------------------------------------- %%% Internal functions %%%------------------------------------------------------------------- erlang-jose-1.10.1/rebar.lock0000644000232200023220000000026213605433351016316 0ustar debalancedebalance{"1.1.0", [{<<"base64url">>,{pkg,<<"base64url">>,<<"0.0.1">>},0}]}. [ {pkg_hash,[ {<<"base64url">>, <<"36A90125F5948E3AFD7BE97662A1504B934DD5DAC78451CA6E9ABF85A10286BE">>}]} ]. erlang-jose-1.10.1/build.config0000644000232200023220000000143413605433351016641 0ustar debalancedebalance# Do *not* comment or remove core modules # unless you know what you are doing. # # Feel free to comment plugins out however. # Core modules. core/core core/kerl index/* core/index core/deps # Plugins that must run before Erlang code gets compiled. plugins/protobuffs # Core modules, continued. core/erlc core/docs core/rel core/test core/compat # Plugins. plugins/asciidoc plugins/bootstrap plugins/c_src plugins/ci plugins/ct plugins/dialyzer plugins/edoc plugins/erlydtl plugins/escript plugins/eunit plugins/proper plugins/relx plugins/shell plugins/sphinx plugins/syntastic plugins/triq plugins/xref # Plugins enhancing the functionality of other plugins. plugins/cover plugins/sfx # External plugins. core/plugins # Core modules which can use variables from plugins. core/deps-tools erlang-jose-1.10.1/erlang.mk0000644000232200023220000074740313605433351016171 0ustar debalancedebalance# Copyright (c) 2013-2016, Loïc Hoguin # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .PHONY: all app apps deps search rel relup docs install-docs check tests clean distclean help erlang-mk ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) export ERLANG_MK_FILENAME ERLANG_MK_VERSION = 4508aa0-dirty ERLANG_MK_WITHOUT = # Make 3.81 and 3.82 are deprecated. ifeq ($(MAKELEVEL)$(MAKE_VERSION),03.81) $(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) endif ifeq ($(MAKELEVEL)$(MAKE_VERSION),03.82) $(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) endif # Core configuration. PROJECT ?= $(notdir $(CURDIR)) PROJECT := $(strip $(PROJECT)) PROJECT_VERSION ?= rolling PROJECT_MOD ?= $(PROJECT)_app PROJECT_ENV ?= [] # Verbosity. V ?= 0 verbose_0 = @ verbose_2 = set -x; verbose = $(verbose_$(V)) ifeq ($(V),3) SHELL := $(SHELL) -x endif gen_verbose_0 = @echo " GEN " $@; gen_verbose_2 = set -x; gen_verbose = $(gen_verbose_$(V)) gen_verbose_esc_0 = @echo " GEN " $$@; gen_verbose_esc_2 = set -x; gen_verbose_esc = $(gen_verbose_esc_$(V)) # Temporary files directory. ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk export ERLANG_MK_TMP # "erl" command. ERL = erl +A0 -noinput -boot no_dot_erlang # Platform detection. ifeq ($(PLATFORM),) UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) PLATFORM = linux else ifeq ($(UNAME_S),Darwin) PLATFORM = darwin else ifeq ($(UNAME_S),SunOS) PLATFORM = solaris else ifeq ($(UNAME_S),GNU) PLATFORM = gnu else ifeq ($(UNAME_S),FreeBSD) PLATFORM = freebsd else ifeq ($(UNAME_S),NetBSD) PLATFORM = netbsd else ifeq ($(UNAME_S),OpenBSD) PLATFORM = openbsd else ifeq ($(UNAME_S),DragonFly) PLATFORM = dragonfly else ifeq ($(shell uname -o),Msys) PLATFORM = msys2 else $(error Unable to detect platform. Please open a ticket with the output of uname -a.) endif export PLATFORM endif # Core targets. all:: deps app rel # Noop to avoid a Make warning when there's nothing to do. rel:: $(verbose) : relup:: deps app check:: tests clean:: clean-crashdump clean-crashdump: ifneq ($(wildcard erl_crash.dump),) $(gen_verbose) rm -f erl_crash.dump endif distclean:: clean distclean-tmp $(ERLANG_MK_TMP): $(verbose) mkdir -p $(ERLANG_MK_TMP) distclean-tmp: $(gen_verbose) rm -rf $(ERLANG_MK_TMP) help:: $(verbose) printf "%s\n" \ "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ "Copyright (c) 2013-2016 Loïc Hoguin " \ "" \ "Usage: [V=1] $(MAKE) [target]..." \ "" \ "Core targets:" \ " all Run deps, app and rel targets in that order" \ " app Compile the project" \ " deps Fetch dependencies (if needed) and compile them" \ " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ " list-deps List dependencies recursively on stdout" \ " search q=... Search for a package in the built-in index" \ " rel Build a release for this project, if applicable" \ " docs Build the documentation for this project" \ " install-docs Install the man pages for this project" \ " check Compile and run all tests and analysis for this project" \ " tests Run the tests for this project" \ " clean Delete temporary and output files from most targets" \ " distclean Delete all temporary and output files" \ " help Display this help and exit" \ " erlang-mk Update erlang.mk to the latest version" # Core functions. empty := space := $(empty) $(empty) tab := $(empty) $(empty) comma := , define newline endef define comma_list $(subst $(space),$(comma),$(strip $(1))) endef define escape_dquotes $(subst ",\",$1) endef # Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. define erlang $(ERL) $2 -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(call escape_dquotes,$1))" -- erlang.mk endef ifeq ($(PLATFORM),msys2) core_native_path = $(shell cygpath -m $1) else core_native_path = $1 endif core_http_get = curl -Lf$(if $(filter-out 0,$(V)),,s)o $(call core_native_path,$1) $2 core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) # We skip files that contain spaces because they end up causing issues. core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) \( -type l -o -type f \) -name $(subst *,\*,$2) | grep -v " ")) core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) core_ls = $(filter-out $(1),$(shell echo $(1))) # @todo Use a solution that does not require using perl. core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) define core_render printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) endef # Automated update. ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk ERLANG_MK_COMMIT ?= ERLANG_MK_BUILD_CONFIG ?= build.config ERLANG_MK_BUILD_DIR ?= .erlang.mk.build erlang-mk: WITHOUT ?= $(ERLANG_MK_WITHOUT) erlang-mk: ifdef ERLANG_MK_COMMIT $(verbose) git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) $(verbose) cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) else $(verbose) git clone --depth 1 $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) endif $(verbose) if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi $(gen_verbose) $(MAKE) --no-print-directory -C $(ERLANG_MK_BUILD_DIR) WITHOUT='$(strip $(WITHOUT))' UPGRADE=1 $(verbose) cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk $(verbose) rm -rf $(ERLANG_MK_BUILD_DIR) $(verbose) rm -rf $(ERLANG_MK_TMP) # The erlang.mk package index is bundled in the default erlang.mk build. # Search for the string "copyright" to skip to the rest of the code. # Copyright (c) 2015-2017, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-kerl KERL_INSTALL_DIR ?= $(HOME)/erlang ifeq ($(strip $(KERL)),) KERL := $(ERLANG_MK_TMP)/kerl/kerl endif KERL_DIR = $(ERLANG_MK_TMP)/kerl export KERL KERL_GIT ?= https://github.com/kerl/kerl KERL_COMMIT ?= master KERL_MAKEFLAGS ?= OTP_GIT ?= https://github.com/erlang/otp define kerl_otp_target $(KERL_INSTALL_DIR)/$(1): $(KERL) $(verbose) if [ ! -d $$@ ]; then \ MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1); \ $(KERL) install $(1) $(KERL_INSTALL_DIR)/$(1); \ fi endef define kerl_hipe_target $(KERL_INSTALL_DIR)/$1-native: $(KERL) $(verbose) if [ ! -d $$@ ]; then \ KERL_CONFIGURE_OPTIONS=--enable-native-libs \ MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native; \ $(KERL) install $1-native $(KERL_INSTALL_DIR)/$1-native; \ fi endef $(KERL): $(KERL_DIR) $(KERL_DIR): | $(ERLANG_MK_TMP) $(gen_verbose) git clone --depth 1 $(KERL_GIT) $(ERLANG_MK_TMP)/kerl $(verbose) cd $(ERLANG_MK_TMP)/kerl && git checkout $(KERL_COMMIT) $(verbose) chmod +x $(KERL) distclean:: distclean-kerl distclean-kerl: $(gen_verbose) rm -rf $(KERL_DIR) # Allow users to select which version of Erlang/OTP to use for a project. ifneq ($(strip $(LATEST_ERLANG_OTP)),) # In some environments it is necessary to filter out master. ERLANG_OTP := $(notdir $(lastword $(sort\ $(filter-out $(KERL_INSTALL_DIR)/master $(KERL_INSTALL_DIR)/OTP_R%,\ $(filter-out %-rc1 %-rc2 %-rc3,$(wildcard $(KERL_INSTALL_DIR)/*[^-native])))))) endif ERLANG_OTP ?= ERLANG_HIPE ?= # Use kerl to enforce a specific Erlang/OTP version for a project. ifneq ($(strip $(ERLANG_OTP)),) export PATH := $(KERL_INSTALL_DIR)/$(ERLANG_OTP)/bin:$(PATH) SHELL := env PATH=$(PATH) $(SHELL) $(eval $(call kerl_otp_target,$(ERLANG_OTP))) # Build Erlang/OTP only if it doesn't already exist. ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(ERLANG_OTP))$(BUILD_ERLANG_OTP),) $(info Building Erlang/OTP $(ERLANG_OTP)... Please wait...) $(shell $(MAKE) $(KERL_INSTALL_DIR)/$(ERLANG_OTP) ERLANG_OTP=$(ERLANG_OTP) BUILD_ERLANG_OTP=1 >&2) endif else # Same for a HiPE enabled VM. ifneq ($(strip $(ERLANG_HIPE)),) export PATH := $(KERL_INSTALL_DIR)/$(ERLANG_HIPE)-native/bin:$(PATH) SHELL := env PATH=$(PATH) $(SHELL) $(eval $(call kerl_hipe_target,$(ERLANG_HIPE))) # Build Erlang/OTP only if it doesn't already exist. ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(ERLANG_HIPE)-native)$(BUILD_ERLANG_OTP),) $(info Building HiPE-enabled Erlang/OTP $(ERLANG_OTP)... Please wait...) $(shell $(MAKE) $(KERL_INSTALL_DIR)/$(ERLANG_HIPE)-native ERLANG_HIPE=$(ERLANG_HIPE) BUILD_ERLANG_OTP=1 >&2) endif endif endif PACKAGES += aberth pkg_aberth_name = aberth pkg_aberth_description = Generic BERT-RPC server in Erlang pkg_aberth_homepage = https://github.com/a13x/aberth pkg_aberth_fetch = git pkg_aberth_repo = https://github.com/a13x/aberth pkg_aberth_commit = master PACKAGES += active pkg_active_name = active pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running pkg_active_homepage = https://github.com/proger/active pkg_active_fetch = git pkg_active_repo = https://github.com/proger/active pkg_active_commit = master PACKAGES += actordb_core pkg_actordb_core_name = actordb_core pkg_actordb_core_description = ActorDB main source pkg_actordb_core_homepage = http://www.actordb.com/ pkg_actordb_core_fetch = git pkg_actordb_core_repo = https://github.com/biokoda/actordb_core pkg_actordb_core_commit = master PACKAGES += actordb_thrift pkg_actordb_thrift_name = actordb_thrift pkg_actordb_thrift_description = Thrift API for ActorDB pkg_actordb_thrift_homepage = http://www.actordb.com/ pkg_actordb_thrift_fetch = git pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift pkg_actordb_thrift_commit = master PACKAGES += aleppo pkg_aleppo_name = aleppo pkg_aleppo_description = Alternative Erlang Pre-Processor pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo pkg_aleppo_fetch = git pkg_aleppo_repo = https://github.com/ErlyORM/aleppo pkg_aleppo_commit = master PACKAGES += alog pkg_alog_name = alog pkg_alog_description = Simply the best logging framework for Erlang pkg_alog_homepage = https://github.com/siberian-fast-food/alogger pkg_alog_fetch = git pkg_alog_repo = https://github.com/siberian-fast-food/alogger pkg_alog_commit = master PACKAGES += amqp_client pkg_amqp_client_name = amqp_client pkg_amqp_client_description = RabbitMQ Erlang AMQP client pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html pkg_amqp_client_fetch = git pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git pkg_amqp_client_commit = master PACKAGES += annotations pkg_annotations_name = annotations pkg_annotations_description = Simple code instrumentation utilities pkg_annotations_homepage = https://github.com/hyperthunk/annotations pkg_annotations_fetch = git pkg_annotations_repo = https://github.com/hyperthunk/annotations pkg_annotations_commit = master PACKAGES += antidote pkg_antidote_name = antidote pkg_antidote_description = Large-scale computation without synchronisation pkg_antidote_homepage = https://syncfree.lip6.fr/ pkg_antidote_fetch = git pkg_antidote_repo = https://github.com/SyncFree/antidote pkg_antidote_commit = master PACKAGES += apns pkg_apns_name = apns pkg_apns_description = Apple Push Notification Server for Erlang pkg_apns_homepage = http://inaka.github.com/apns4erl pkg_apns_fetch = git pkg_apns_repo = https://github.com/inaka/apns4erl pkg_apns_commit = master PACKAGES += asciideck pkg_asciideck_name = asciideck pkg_asciideck_description = Asciidoc for Erlang. pkg_asciideck_homepage = https://ninenines.eu pkg_asciideck_fetch = git pkg_asciideck_repo = https://github.com/ninenines/asciideck pkg_asciideck_commit = master PACKAGES += azdht pkg_azdht_name = azdht pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang pkg_azdht_homepage = https://github.com/arcusfelis/azdht pkg_azdht_fetch = git pkg_azdht_repo = https://github.com/arcusfelis/azdht pkg_azdht_commit = master PACKAGES += backoff pkg_backoff_name = backoff pkg_backoff_description = Simple exponential backoffs in Erlang pkg_backoff_homepage = https://github.com/ferd/backoff pkg_backoff_fetch = git pkg_backoff_repo = https://github.com/ferd/backoff pkg_backoff_commit = master PACKAGES += barrel_tcp pkg_barrel_tcp_name = barrel_tcp pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp pkg_barrel_tcp_fetch = git pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp pkg_barrel_tcp_commit = master PACKAGES += basho_bench pkg_basho_bench_name = basho_bench pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. pkg_basho_bench_homepage = https://github.com/basho/basho_bench pkg_basho_bench_fetch = git pkg_basho_bench_repo = https://github.com/basho/basho_bench pkg_basho_bench_commit = master PACKAGES += bcrypt pkg_bcrypt_name = bcrypt pkg_bcrypt_description = Bcrypt Erlang / C library pkg_bcrypt_homepage = https://github.com/erlangpack/bcrypt pkg_bcrypt_fetch = git pkg_bcrypt_repo = https://github.com/erlangpack/bcrypt.git pkg_bcrypt_commit = master PACKAGES += beam pkg_beam_name = beam pkg_beam_description = BEAM emulator written in Erlang pkg_beam_homepage = https://github.com/tonyrog/beam pkg_beam_fetch = git pkg_beam_repo = https://github.com/tonyrog/beam pkg_beam_commit = master PACKAGES += beanstalk pkg_beanstalk_name = beanstalk pkg_beanstalk_description = An Erlang client for beanstalkd pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk pkg_beanstalk_fetch = git pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk pkg_beanstalk_commit = master PACKAGES += bear pkg_bear_name = bear pkg_bear_description = a set of statistics functions for erlang pkg_bear_homepage = https://github.com/boundary/bear pkg_bear_fetch = git pkg_bear_repo = https://github.com/boundary/bear pkg_bear_commit = master PACKAGES += bertconf pkg_bertconf_name = bertconf pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded pkg_bertconf_homepage = https://github.com/ferd/bertconf pkg_bertconf_fetch = git pkg_bertconf_repo = https://github.com/ferd/bertconf pkg_bertconf_commit = master PACKAGES += bifrost pkg_bifrost_name = bifrost pkg_bifrost_description = Erlang FTP Server Framework pkg_bifrost_homepage = https://github.com/thorstadt/bifrost pkg_bifrost_fetch = git pkg_bifrost_repo = https://github.com/thorstadt/bifrost pkg_bifrost_commit = master PACKAGES += binpp pkg_binpp_name = binpp pkg_binpp_description = Erlang Binary Pretty Printer pkg_binpp_homepage = https://github.com/jtendo/binpp pkg_binpp_fetch = git pkg_binpp_repo = https://github.com/jtendo/binpp pkg_binpp_commit = master PACKAGES += bisect pkg_bisect_name = bisect pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang pkg_bisect_homepage = https://github.com/knutin/bisect pkg_bisect_fetch = git pkg_bisect_repo = https://github.com/knutin/bisect pkg_bisect_commit = master PACKAGES += bitcask pkg_bitcask_name = bitcask pkg_bitcask_description = because you need another a key/value storage engine pkg_bitcask_homepage = https://github.com/basho/bitcask pkg_bitcask_fetch = git pkg_bitcask_repo = https://github.com/basho/bitcask pkg_bitcask_commit = develop PACKAGES += bitstore pkg_bitstore_name = bitstore pkg_bitstore_description = A document based ontology development environment pkg_bitstore_homepage = https://github.com/bdionne/bitstore pkg_bitstore_fetch = git pkg_bitstore_repo = https://github.com/bdionne/bitstore pkg_bitstore_commit = master PACKAGES += bootstrap pkg_bootstrap_name = bootstrap pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap pkg_bootstrap_fetch = git pkg_bootstrap_repo = https://github.com/schlagert/bootstrap pkg_bootstrap_commit = master PACKAGES += boss pkg_boss_name = boss pkg_boss_description = Erlang web MVC, now featuring Comet pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss pkg_boss_fetch = git pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss pkg_boss_commit = master PACKAGES += boss_db pkg_boss_db_name = boss_db pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db pkg_boss_db_fetch = git pkg_boss_db_repo = https://github.com/ErlyORM/boss_db pkg_boss_db_commit = master PACKAGES += brod pkg_brod_name = brod pkg_brod_description = Kafka client in Erlang pkg_brod_homepage = https://github.com/klarna/brod pkg_brod_fetch = git pkg_brod_repo = https://github.com/klarna/brod.git pkg_brod_commit = master PACKAGES += bson pkg_bson_name = bson pkg_bson_description = BSON documents in Erlang, see bsonspec.org pkg_bson_homepage = https://github.com/comtihon/bson-erlang pkg_bson_fetch = git pkg_bson_repo = https://github.com/comtihon/bson-erlang pkg_bson_commit = master PACKAGES += bullet pkg_bullet_name = bullet pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. pkg_bullet_homepage = http://ninenines.eu pkg_bullet_fetch = git pkg_bullet_repo = https://github.com/ninenines/bullet pkg_bullet_commit = master PACKAGES += cache pkg_cache_name = cache pkg_cache_description = Erlang in-memory cache pkg_cache_homepage = https://github.com/fogfish/cache pkg_cache_fetch = git pkg_cache_repo = https://github.com/fogfish/cache pkg_cache_commit = master PACKAGES += cake pkg_cake_name = cake pkg_cake_description = Really simple terminal colorization pkg_cake_homepage = https://github.com/darach/cake-erl pkg_cake_fetch = git pkg_cake_repo = https://github.com/darach/cake-erl pkg_cake_commit = master PACKAGES += carotene pkg_carotene_name = carotene pkg_carotene_description = Real-time server pkg_carotene_homepage = https://github.com/carotene/carotene pkg_carotene_fetch = git pkg_carotene_repo = https://github.com/carotene/carotene pkg_carotene_commit = master PACKAGES += cberl pkg_cberl_name = cberl pkg_cberl_description = NIF based Erlang bindings for Couchbase pkg_cberl_homepage = https://github.com/chitika/cberl pkg_cberl_fetch = git pkg_cberl_repo = https://github.com/chitika/cberl pkg_cberl_commit = master PACKAGES += cecho pkg_cecho_name = cecho pkg_cecho_description = An ncurses library for Erlang pkg_cecho_homepage = https://github.com/mazenharake/cecho pkg_cecho_fetch = git pkg_cecho_repo = https://github.com/mazenharake/cecho pkg_cecho_commit = master PACKAGES += cferl pkg_cferl_name = cferl pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client pkg_cferl_homepage = https://github.com/ddossot/cferl pkg_cferl_fetch = git pkg_cferl_repo = https://github.com/ddossot/cferl pkg_cferl_commit = master PACKAGES += chaos_monkey pkg_chaos_monkey_name = chaos_monkey pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey pkg_chaos_monkey_fetch = git pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey pkg_chaos_monkey_commit = master PACKAGES += check_node pkg_check_node_name = check_node pkg_check_node_description = Nagios Scripts for monitoring Riak pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios pkg_check_node_fetch = git pkg_check_node_repo = https://github.com/basho-labs/riak_nagios pkg_check_node_commit = master PACKAGES += chronos pkg_chronos_name = chronos pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. pkg_chronos_homepage = https://github.com/lehoff/chronos pkg_chronos_fetch = git pkg_chronos_repo = https://github.com/lehoff/chronos pkg_chronos_commit = master PACKAGES += chumak pkg_chumak_name = chumak pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. pkg_chumak_homepage = http://choven.ca pkg_chumak_fetch = git pkg_chumak_repo = https://github.com/chovencorp/chumak pkg_chumak_commit = master PACKAGES += cl pkg_cl_name = cl pkg_cl_description = OpenCL binding for Erlang pkg_cl_homepage = https://github.com/tonyrog/cl pkg_cl_fetch = git pkg_cl_repo = https://github.com/tonyrog/cl pkg_cl_commit = master PACKAGES += clique pkg_clique_name = clique pkg_clique_description = CLI Framework for Erlang pkg_clique_homepage = https://github.com/basho/clique pkg_clique_fetch = git pkg_clique_repo = https://github.com/basho/clique pkg_clique_commit = develop PACKAGES += cloudi_core pkg_cloudi_core_name = cloudi_core pkg_cloudi_core_description = CloudI internal service runtime pkg_cloudi_core_homepage = http://cloudi.org/ pkg_cloudi_core_fetch = git pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core pkg_cloudi_core_commit = master PACKAGES += cloudi_service_api_requests pkg_cloudi_service_api_requests_name = cloudi_service_api_requests pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ pkg_cloudi_service_api_requests_fetch = git pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests pkg_cloudi_service_api_requests_commit = master PACKAGES += cloudi_service_db pkg_cloudi_service_db_name = cloudi_service_db pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) pkg_cloudi_service_db_homepage = http://cloudi.org/ pkg_cloudi_service_db_fetch = git pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db pkg_cloudi_service_db_commit = master PACKAGES += cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ pkg_cloudi_service_db_cassandra_fetch = git pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_commit = master PACKAGES += cloudi_service_db_cassandra_cql pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ pkg_cloudi_service_db_cassandra_cql_fetch = git pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql pkg_cloudi_service_db_cassandra_cql_commit = master PACKAGES += cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ pkg_cloudi_service_db_couchdb_fetch = git pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_commit = master PACKAGES += cloudi_service_db_elasticsearch pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ pkg_cloudi_service_db_elasticsearch_fetch = git pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch pkg_cloudi_service_db_elasticsearch_commit = master PACKAGES += cloudi_service_db_memcached pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached pkg_cloudi_service_db_memcached_description = memcached CloudI Service pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ pkg_cloudi_service_db_memcached_fetch = git pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached pkg_cloudi_service_db_memcached_commit = master PACKAGES += cloudi_service_db_mysql pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql pkg_cloudi_service_db_mysql_description = MySQL CloudI Service pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ pkg_cloudi_service_db_mysql_fetch = git pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql pkg_cloudi_service_db_mysql_commit = master PACKAGES += cloudi_service_db_pgsql pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ pkg_cloudi_service_db_pgsql_fetch = git pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql pkg_cloudi_service_db_pgsql_commit = master PACKAGES += cloudi_service_db_riak pkg_cloudi_service_db_riak_name = cloudi_service_db_riak pkg_cloudi_service_db_riak_description = Riak CloudI Service pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ pkg_cloudi_service_db_riak_fetch = git pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak pkg_cloudi_service_db_riak_commit = master PACKAGES += cloudi_service_db_tokyotyrant pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ pkg_cloudi_service_db_tokyotyrant_fetch = git pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant pkg_cloudi_service_db_tokyotyrant_commit = master PACKAGES += cloudi_service_filesystem pkg_cloudi_service_filesystem_name = cloudi_service_filesystem pkg_cloudi_service_filesystem_description = Filesystem CloudI Service pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ pkg_cloudi_service_filesystem_fetch = git pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem pkg_cloudi_service_filesystem_commit = master PACKAGES += cloudi_service_http_client pkg_cloudi_service_http_client_name = cloudi_service_http_client pkg_cloudi_service_http_client_description = HTTP client CloudI Service pkg_cloudi_service_http_client_homepage = http://cloudi.org/ pkg_cloudi_service_http_client_fetch = git pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client pkg_cloudi_service_http_client_commit = master PACKAGES += cloudi_service_http_cowboy pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ pkg_cloudi_service_http_cowboy_fetch = git pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy pkg_cloudi_service_http_cowboy_commit = master PACKAGES += cloudi_service_http_elli pkg_cloudi_service_http_elli_name = cloudi_service_http_elli pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ pkg_cloudi_service_http_elli_fetch = git pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli pkg_cloudi_service_http_elli_commit = master PACKAGES += cloudi_service_map_reduce pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ pkg_cloudi_service_map_reduce_fetch = git pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce pkg_cloudi_service_map_reduce_commit = master PACKAGES += cloudi_service_oauth1 pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ pkg_cloudi_service_oauth1_fetch = git pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 pkg_cloudi_service_oauth1_commit = master PACKAGES += cloudi_service_queue pkg_cloudi_service_queue_name = cloudi_service_queue pkg_cloudi_service_queue_description = Persistent Queue Service pkg_cloudi_service_queue_homepage = http://cloudi.org/ pkg_cloudi_service_queue_fetch = git pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue pkg_cloudi_service_queue_commit = master PACKAGES += cloudi_service_quorum pkg_cloudi_service_quorum_name = cloudi_service_quorum pkg_cloudi_service_quorum_description = CloudI Quorum Service pkg_cloudi_service_quorum_homepage = http://cloudi.org/ pkg_cloudi_service_quorum_fetch = git pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum pkg_cloudi_service_quorum_commit = master PACKAGES += cloudi_service_router pkg_cloudi_service_router_name = cloudi_service_router pkg_cloudi_service_router_description = CloudI Router Service pkg_cloudi_service_router_homepage = http://cloudi.org/ pkg_cloudi_service_router_fetch = git pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router pkg_cloudi_service_router_commit = master PACKAGES += cloudi_service_tcp pkg_cloudi_service_tcp_name = cloudi_service_tcp pkg_cloudi_service_tcp_description = TCP CloudI Service pkg_cloudi_service_tcp_homepage = http://cloudi.org/ pkg_cloudi_service_tcp_fetch = git pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp pkg_cloudi_service_tcp_commit = master PACKAGES += cloudi_service_timers pkg_cloudi_service_timers_name = cloudi_service_timers pkg_cloudi_service_timers_description = Timers CloudI Service pkg_cloudi_service_timers_homepage = http://cloudi.org/ pkg_cloudi_service_timers_fetch = git pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers pkg_cloudi_service_timers_commit = master PACKAGES += cloudi_service_udp pkg_cloudi_service_udp_name = cloudi_service_udp pkg_cloudi_service_udp_description = UDP CloudI Service pkg_cloudi_service_udp_homepage = http://cloudi.org/ pkg_cloudi_service_udp_fetch = git pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp pkg_cloudi_service_udp_commit = master PACKAGES += cloudi_service_validate pkg_cloudi_service_validate_name = cloudi_service_validate pkg_cloudi_service_validate_description = CloudI Validate Service pkg_cloudi_service_validate_homepage = http://cloudi.org/ pkg_cloudi_service_validate_fetch = git pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate pkg_cloudi_service_validate_commit = master PACKAGES += cloudi_service_zeromq pkg_cloudi_service_zeromq_name = cloudi_service_zeromq pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ pkg_cloudi_service_zeromq_fetch = git pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq pkg_cloudi_service_zeromq_commit = master PACKAGES += cluster_info pkg_cluster_info_name = cluster_info pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app pkg_cluster_info_homepage = https://github.com/basho/cluster_info pkg_cluster_info_fetch = git pkg_cluster_info_repo = https://github.com/basho/cluster_info pkg_cluster_info_commit = master PACKAGES += color pkg_color_name = color pkg_color_description = ANSI colors for your Erlang pkg_color_homepage = https://github.com/julianduque/erlang-color pkg_color_fetch = git pkg_color_repo = https://github.com/julianduque/erlang-color pkg_color_commit = master PACKAGES += confetti pkg_confetti_name = confetti pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids pkg_confetti_homepage = https://github.com/jtendo/confetti pkg_confetti_fetch = git pkg_confetti_repo = https://github.com/jtendo/confetti pkg_confetti_commit = master PACKAGES += couchbeam pkg_couchbeam_name = couchbeam pkg_couchbeam_description = Apache CouchDB client in Erlang pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam pkg_couchbeam_fetch = git pkg_couchbeam_repo = https://github.com/benoitc/couchbeam pkg_couchbeam_commit = master PACKAGES += covertool pkg_covertool_name = covertool pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports pkg_covertool_homepage = https://github.com/idubrov/covertool pkg_covertool_fetch = git pkg_covertool_repo = https://github.com/idubrov/covertool pkg_covertool_commit = master PACKAGES += cowboy pkg_cowboy_name = cowboy pkg_cowboy_description = Small, fast and modular HTTP server. pkg_cowboy_homepage = http://ninenines.eu pkg_cowboy_fetch = git pkg_cowboy_repo = https://github.com/ninenines/cowboy pkg_cowboy_commit = 1.0.4 PACKAGES += cowdb pkg_cowdb_name = cowdb pkg_cowdb_description = Pure Key/Value database library for Erlang Applications pkg_cowdb_homepage = https://github.com/refuge/cowdb pkg_cowdb_fetch = git pkg_cowdb_repo = https://github.com/refuge/cowdb pkg_cowdb_commit = master PACKAGES += cowlib pkg_cowlib_name = cowlib pkg_cowlib_description = Support library for manipulating Web protocols. pkg_cowlib_homepage = http://ninenines.eu pkg_cowlib_fetch = git pkg_cowlib_repo = https://github.com/ninenines/cowlib pkg_cowlib_commit = 1.0.2 PACKAGES += cpg pkg_cpg_name = cpg pkg_cpg_description = CloudI Process Groups pkg_cpg_homepage = https://github.com/okeuday/cpg pkg_cpg_fetch = git pkg_cpg_repo = https://github.com/okeuday/cpg pkg_cpg_commit = master PACKAGES += cqerl pkg_cqerl_name = cqerl pkg_cqerl_description = Native Erlang CQL client for Cassandra pkg_cqerl_homepage = https://matehat.github.io/cqerl/ pkg_cqerl_fetch = git pkg_cqerl_repo = https://github.com/matehat/cqerl pkg_cqerl_commit = master PACKAGES += cr pkg_cr_name = cr pkg_cr_description = Chain Replication pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm pkg_cr_fetch = git pkg_cr_repo = https://github.com/spawnproc/cr pkg_cr_commit = master PACKAGES += cuttlefish pkg_cuttlefish_name = cuttlefish pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish pkg_cuttlefish_fetch = git pkg_cuttlefish_repo = https://github.com/basho/cuttlefish pkg_cuttlefish_commit = master PACKAGES += damocles pkg_damocles_name = damocles pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. pkg_damocles_homepage = https://github.com/lostcolony/damocles pkg_damocles_fetch = git pkg_damocles_repo = https://github.com/lostcolony/damocles pkg_damocles_commit = master PACKAGES += debbie pkg_debbie_name = debbie pkg_debbie_description = .DEB Built In Erlang pkg_debbie_homepage = https://github.com/crownedgrouse/debbie pkg_debbie_fetch = git pkg_debbie_repo = https://github.com/crownedgrouse/debbie pkg_debbie_commit = master PACKAGES += decimal pkg_decimal_name = decimal pkg_decimal_description = An Erlang decimal arithmetic library pkg_decimal_homepage = https://github.com/tim/erlang-decimal pkg_decimal_fetch = git pkg_decimal_repo = https://github.com/tim/erlang-decimal pkg_decimal_commit = master PACKAGES += detergent pkg_detergent_name = detergent pkg_detergent_description = An emulsifying Erlang SOAP library pkg_detergent_homepage = https://github.com/devinus/detergent pkg_detergent_fetch = git pkg_detergent_repo = https://github.com/devinus/detergent pkg_detergent_commit = master PACKAGES += detest pkg_detest_name = detest pkg_detest_description = Tool for running tests on a cluster of erlang nodes pkg_detest_homepage = https://github.com/biokoda/detest pkg_detest_fetch = git pkg_detest_repo = https://github.com/biokoda/detest pkg_detest_commit = master PACKAGES += dh_date pkg_dh_date_name = dh_date pkg_dh_date_description = Date formatting / parsing library for erlang pkg_dh_date_homepage = https://github.com/daleharvey/dh_date pkg_dh_date_fetch = git pkg_dh_date_repo = https://github.com/daleharvey/dh_date pkg_dh_date_commit = master PACKAGES += dirbusterl pkg_dirbusterl_name = dirbusterl pkg_dirbusterl_description = DirBuster successor in Erlang pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl pkg_dirbusterl_fetch = git pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl pkg_dirbusterl_commit = master PACKAGES += dispcount pkg_dispcount_name = dispcount pkg_dispcount_description = Erlang task dispatcher based on ETS counters. pkg_dispcount_homepage = https://github.com/ferd/dispcount pkg_dispcount_fetch = git pkg_dispcount_repo = https://github.com/ferd/dispcount pkg_dispcount_commit = master PACKAGES += dlhttpc pkg_dlhttpc_name = dlhttpc pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc pkg_dlhttpc_fetch = git pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc pkg_dlhttpc_commit = master PACKAGES += dns pkg_dns_name = dns pkg_dns_description = Erlang DNS library pkg_dns_homepage = https://github.com/aetrion/dns_erlang pkg_dns_fetch = git pkg_dns_repo = https://github.com/aetrion/dns_erlang pkg_dns_commit = master PACKAGES += dnssd pkg_dnssd_name = dnssd pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang pkg_dnssd_fetch = git pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang pkg_dnssd_commit = master PACKAGES += dynamic_compile pkg_dynamic_compile_name = dynamic_compile pkg_dynamic_compile_description = compile and load erlang modules from string input pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile pkg_dynamic_compile_fetch = git pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile pkg_dynamic_compile_commit = master PACKAGES += e2 pkg_e2_name = e2 pkg_e2_description = Library to simply writing correct OTP applications. pkg_e2_homepage = http://e2project.org pkg_e2_fetch = git pkg_e2_repo = https://github.com/gar1t/e2 pkg_e2_commit = master PACKAGES += eamf pkg_eamf_name = eamf pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf pkg_eamf_fetch = git pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf pkg_eamf_commit = master PACKAGES += eavro pkg_eavro_name = eavro pkg_eavro_description = Apache Avro encoder/decoder pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro pkg_eavro_fetch = git pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro pkg_eavro_commit = master PACKAGES += ecapnp pkg_ecapnp_name = ecapnp pkg_ecapnp_description = Cap'n Proto library for Erlang pkg_ecapnp_homepage = https://github.com/kaos/ecapnp pkg_ecapnp_fetch = git pkg_ecapnp_repo = https://github.com/kaos/ecapnp pkg_ecapnp_commit = master PACKAGES += econfig pkg_econfig_name = econfig pkg_econfig_description = simple Erlang config handler using INI files pkg_econfig_homepage = https://github.com/benoitc/econfig pkg_econfig_fetch = git pkg_econfig_repo = https://github.com/benoitc/econfig pkg_econfig_commit = master PACKAGES += edate pkg_edate_name = edate pkg_edate_description = date manipulation library for erlang pkg_edate_homepage = https://github.com/dweldon/edate pkg_edate_fetch = git pkg_edate_repo = https://github.com/dweldon/edate pkg_edate_commit = master PACKAGES += edgar pkg_edgar_name = edgar pkg_edgar_description = Erlang Does GNU AR pkg_edgar_homepage = https://github.com/crownedgrouse/edgar pkg_edgar_fetch = git pkg_edgar_repo = https://github.com/crownedgrouse/edgar pkg_edgar_commit = master PACKAGES += edis pkg_edis_name = edis pkg_edis_description = An Erlang implementation of Redis KV Store pkg_edis_homepage = http://inaka.github.com/edis/ pkg_edis_fetch = git pkg_edis_repo = https://github.com/inaka/edis pkg_edis_commit = master PACKAGES += edns pkg_edns_name = edns pkg_edns_description = Erlang/OTP DNS server pkg_edns_homepage = https://github.com/hcvst/erlang-dns pkg_edns_fetch = git pkg_edns_repo = https://github.com/hcvst/erlang-dns pkg_edns_commit = master PACKAGES += edown pkg_edown_name = edown pkg_edown_description = EDoc extension for generating Github-flavored Markdown pkg_edown_homepage = https://github.com/uwiger/edown pkg_edown_fetch = git pkg_edown_repo = https://github.com/uwiger/edown pkg_edown_commit = master PACKAGES += eep pkg_eep_name = eep pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy pkg_eep_homepage = https://github.com/virtan/eep pkg_eep_fetch = git pkg_eep_repo = https://github.com/virtan/eep pkg_eep_commit = master PACKAGES += eep_app pkg_eep_app_name = eep_app pkg_eep_app_description = Embedded Event Processing pkg_eep_app_homepage = https://github.com/darach/eep-erl pkg_eep_app_fetch = git pkg_eep_app_repo = https://github.com/darach/eep-erl pkg_eep_app_commit = master PACKAGES += efene pkg_efene_name = efene pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX pkg_efene_homepage = https://github.com/efene/efene pkg_efene_fetch = git pkg_efene_repo = https://github.com/efene/efene pkg_efene_commit = master PACKAGES += egeoip pkg_egeoip_name = egeoip pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. pkg_egeoip_homepage = https://github.com/mochi/egeoip pkg_egeoip_fetch = git pkg_egeoip_repo = https://github.com/mochi/egeoip pkg_egeoip_commit = master PACKAGES += ehsa pkg_ehsa_name = ehsa pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa pkg_ehsa_fetch = hg pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa pkg_ehsa_commit = default PACKAGES += ej pkg_ej_name = ej pkg_ej_description = Helper module for working with Erlang terms representing JSON pkg_ej_homepage = https://github.com/seth/ej pkg_ej_fetch = git pkg_ej_repo = https://github.com/seth/ej pkg_ej_commit = master PACKAGES += ejabberd pkg_ejabberd_name = ejabberd pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform pkg_ejabberd_homepage = https://github.com/processone/ejabberd pkg_ejabberd_fetch = git pkg_ejabberd_repo = https://github.com/processone/ejabberd pkg_ejabberd_commit = master PACKAGES += ejwt pkg_ejwt_name = ejwt pkg_ejwt_description = erlang library for JSON Web Token pkg_ejwt_homepage = https://github.com/artefactop/ejwt pkg_ejwt_fetch = git pkg_ejwt_repo = https://github.com/artefactop/ejwt pkg_ejwt_commit = master PACKAGES += ekaf pkg_ekaf_name = ekaf pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. pkg_ekaf_homepage = https://github.com/helpshift/ekaf pkg_ekaf_fetch = git pkg_ekaf_repo = https://github.com/helpshift/ekaf pkg_ekaf_commit = master PACKAGES += elarm pkg_elarm_name = elarm pkg_elarm_description = Alarm Manager for Erlang. pkg_elarm_homepage = https://github.com/esl/elarm pkg_elarm_fetch = git pkg_elarm_repo = https://github.com/esl/elarm pkg_elarm_commit = master PACKAGES += eleveldb pkg_eleveldb_name = eleveldb pkg_eleveldb_description = Erlang LevelDB API pkg_eleveldb_homepage = https://github.com/basho/eleveldb pkg_eleveldb_fetch = git pkg_eleveldb_repo = https://github.com/basho/eleveldb pkg_eleveldb_commit = master PACKAGES += elixir pkg_elixir_name = elixir pkg_elixir_description = Elixir is a dynamic, functional language designed for building scalable and maintainable applications pkg_elixir_homepage = https://elixir-lang.org/ pkg_elixir_fetch = git pkg_elixir_repo = https://github.com/elixir-lang/elixir pkg_elixir_commit = master PACKAGES += elli pkg_elli_name = elli pkg_elli_description = Simple, robust and performant Erlang web server pkg_elli_homepage = https://github.com/elli-lib/elli pkg_elli_fetch = git pkg_elli_repo = https://github.com/elli-lib/elli pkg_elli_commit = master PACKAGES += elvis pkg_elvis_name = elvis pkg_elvis_description = Erlang Style Reviewer pkg_elvis_homepage = https://github.com/inaka/elvis pkg_elvis_fetch = git pkg_elvis_repo = https://github.com/inaka/elvis pkg_elvis_commit = master PACKAGES += emagick pkg_emagick_name = emagick pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. pkg_emagick_homepage = https://github.com/kivra/emagick pkg_emagick_fetch = git pkg_emagick_repo = https://github.com/kivra/emagick pkg_emagick_commit = master PACKAGES += emysql pkg_emysql_name = emysql pkg_emysql_description = Stable, pure Erlang MySQL driver. pkg_emysql_homepage = https://github.com/Eonblast/Emysql pkg_emysql_fetch = git pkg_emysql_repo = https://github.com/Eonblast/Emysql pkg_emysql_commit = master PACKAGES += enm pkg_enm_name = enm pkg_enm_description = Erlang driver for nanomsg pkg_enm_homepage = https://github.com/basho/enm pkg_enm_fetch = git pkg_enm_repo = https://github.com/basho/enm pkg_enm_commit = master PACKAGES += entop pkg_entop_name = entop pkg_entop_description = A top-like tool for monitoring an Erlang node pkg_entop_homepage = https://github.com/mazenharake/entop pkg_entop_fetch = git pkg_entop_repo = https://github.com/mazenharake/entop pkg_entop_commit = master PACKAGES += epcap pkg_epcap_name = epcap pkg_epcap_description = Erlang packet capture interface using pcap pkg_epcap_homepage = https://github.com/msantos/epcap pkg_epcap_fetch = git pkg_epcap_repo = https://github.com/msantos/epcap pkg_epcap_commit = master PACKAGES += eper pkg_eper_name = eper pkg_eper_description = Erlang performance and debugging tools. pkg_eper_homepage = https://github.com/massemanet/eper pkg_eper_fetch = git pkg_eper_repo = https://github.com/massemanet/eper pkg_eper_commit = master PACKAGES += epgsql pkg_epgsql_name = epgsql pkg_epgsql_description = Erlang PostgreSQL client library. pkg_epgsql_homepage = https://github.com/epgsql/epgsql pkg_epgsql_fetch = git pkg_epgsql_repo = https://github.com/epgsql/epgsql pkg_epgsql_commit = master PACKAGES += episcina pkg_episcina_name = episcina pkg_episcina_description = A simple non intrusive resource pool for connections pkg_episcina_homepage = https://github.com/erlware/episcina pkg_episcina_fetch = git pkg_episcina_repo = https://github.com/erlware/episcina pkg_episcina_commit = master PACKAGES += eplot pkg_eplot_name = eplot pkg_eplot_description = A plot engine written in erlang. pkg_eplot_homepage = https://github.com/psyeugenic/eplot pkg_eplot_fetch = git pkg_eplot_repo = https://github.com/psyeugenic/eplot pkg_eplot_commit = master PACKAGES += epocxy pkg_epocxy_name = epocxy pkg_epocxy_description = Erlang Patterns of Concurrency pkg_epocxy_homepage = https://github.com/duomark/epocxy pkg_epocxy_fetch = git pkg_epocxy_repo = https://github.com/duomark/epocxy pkg_epocxy_commit = master PACKAGES += epubnub pkg_epubnub_name = epubnub pkg_epubnub_description = Erlang PubNub API pkg_epubnub_homepage = https://github.com/tsloughter/epubnub pkg_epubnub_fetch = git pkg_epubnub_repo = https://github.com/tsloughter/epubnub pkg_epubnub_commit = master PACKAGES += eqm pkg_eqm_name = eqm pkg_eqm_description = Erlang pub sub with supply-demand channels pkg_eqm_homepage = https://github.com/loucash/eqm pkg_eqm_fetch = git pkg_eqm_repo = https://github.com/loucash/eqm pkg_eqm_commit = master PACKAGES += eredis pkg_eredis_name = eredis pkg_eredis_description = Erlang Redis client pkg_eredis_homepage = https://github.com/wooga/eredis pkg_eredis_fetch = git pkg_eredis_repo = https://github.com/wooga/eredis pkg_eredis_commit = master PACKAGES += eredis_pool pkg_eredis_pool_name = eredis_pool pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool pkg_eredis_pool_fetch = git pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool pkg_eredis_pool_commit = master PACKAGES += erl_streams pkg_erl_streams_name = erl_streams pkg_erl_streams_description = Streams in Erlang pkg_erl_streams_homepage = https://github.com/epappas/erl_streams pkg_erl_streams_fetch = git pkg_erl_streams_repo = https://github.com/epappas/erl_streams pkg_erl_streams_commit = master PACKAGES += erlang_cep pkg_erlang_cep_name = erlang_cep pkg_erlang_cep_description = A basic CEP package written in erlang pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep pkg_erlang_cep_fetch = git pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep pkg_erlang_cep_commit = master PACKAGES += erlang_js pkg_erlang_js_name = erlang_js pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. pkg_erlang_js_homepage = https://github.com/basho/erlang_js pkg_erlang_js_fetch = git pkg_erlang_js_repo = https://github.com/basho/erlang_js pkg_erlang_js_commit = master PACKAGES += erlang_localtime pkg_erlang_localtime_name = erlang_localtime pkg_erlang_localtime_description = Erlang library for conversion from one local time to another pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime pkg_erlang_localtime_fetch = git pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime pkg_erlang_localtime_commit = master PACKAGES += erlang_smtp pkg_erlang_smtp_name = erlang_smtp pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp pkg_erlang_smtp_fetch = git pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp pkg_erlang_smtp_commit = master PACKAGES += erlang_term pkg_erlang_term_name = erlang_term pkg_erlang_term_description = Erlang Term Info pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term pkg_erlang_term_fetch = git pkg_erlang_term_repo = https://github.com/okeuday/erlang_term pkg_erlang_term_commit = master PACKAGES += erlastic_search pkg_erlastic_search_name = erlastic_search pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search pkg_erlastic_search_fetch = git pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search pkg_erlastic_search_commit = master PACKAGES += erlasticsearch pkg_erlasticsearch_name = erlasticsearch pkg_erlasticsearch_description = Erlang thrift interface to elastic_search pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch pkg_erlasticsearch_fetch = git pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch pkg_erlasticsearch_commit = master PACKAGES += erlbrake pkg_erlbrake_name = erlbrake pkg_erlbrake_description = Erlang Airbrake notification client pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake pkg_erlbrake_fetch = git pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake pkg_erlbrake_commit = master PACKAGES += erlcloud pkg_erlcloud_name = erlcloud pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) pkg_erlcloud_homepage = https://github.com/gleber/erlcloud pkg_erlcloud_fetch = git pkg_erlcloud_repo = https://github.com/gleber/erlcloud pkg_erlcloud_commit = master PACKAGES += erlcron pkg_erlcron_name = erlcron pkg_erlcron_description = Erlang cronish system pkg_erlcron_homepage = https://github.com/erlware/erlcron pkg_erlcron_fetch = git pkg_erlcron_repo = https://github.com/erlware/erlcron pkg_erlcron_commit = master PACKAGES += erldb pkg_erldb_name = erldb pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang pkg_erldb_homepage = http://erldb.org pkg_erldb_fetch = git pkg_erldb_repo = https://github.com/erldb/erldb pkg_erldb_commit = master PACKAGES += erldis pkg_erldis_name = erldis pkg_erldis_description = redis erlang client library pkg_erldis_homepage = https://github.com/cstar/erldis pkg_erldis_fetch = git pkg_erldis_repo = https://github.com/cstar/erldis pkg_erldis_commit = master PACKAGES += erldns pkg_erldns_name = erldns pkg_erldns_description = DNS server, in erlang. pkg_erldns_homepage = https://github.com/aetrion/erl-dns pkg_erldns_fetch = git pkg_erldns_repo = https://github.com/aetrion/erl-dns pkg_erldns_commit = master PACKAGES += erldocker pkg_erldocker_name = erldocker pkg_erldocker_description = Docker Remote API client for Erlang pkg_erldocker_homepage = https://github.com/proger/erldocker pkg_erldocker_fetch = git pkg_erldocker_repo = https://github.com/proger/erldocker pkg_erldocker_commit = master PACKAGES += erlfsmon pkg_erlfsmon_name = erlfsmon pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon pkg_erlfsmon_fetch = git pkg_erlfsmon_repo = https://github.com/proger/erlfsmon pkg_erlfsmon_commit = master PACKAGES += erlgit pkg_erlgit_name = erlgit pkg_erlgit_description = Erlang convenience wrapper around git executable pkg_erlgit_homepage = https://github.com/gleber/erlgit pkg_erlgit_fetch = git pkg_erlgit_repo = https://github.com/gleber/erlgit pkg_erlgit_commit = master PACKAGES += erlguten pkg_erlguten_name = erlguten pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. pkg_erlguten_homepage = https://github.com/richcarl/erlguten pkg_erlguten_fetch = git pkg_erlguten_repo = https://github.com/richcarl/erlguten pkg_erlguten_commit = master PACKAGES += erlmc pkg_erlmc_name = erlmc pkg_erlmc_description = Erlang memcached binary protocol client pkg_erlmc_homepage = https://github.com/jkvor/erlmc pkg_erlmc_fetch = git pkg_erlmc_repo = https://github.com/jkvor/erlmc pkg_erlmc_commit = master PACKAGES += erlmongo pkg_erlmongo_name = erlmongo pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo pkg_erlmongo_fetch = git pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo pkg_erlmongo_commit = master PACKAGES += erlog pkg_erlog_name = erlog pkg_erlog_description = Prolog interpreter in and for Erlang pkg_erlog_homepage = https://github.com/rvirding/erlog pkg_erlog_fetch = git pkg_erlog_repo = https://github.com/rvirding/erlog pkg_erlog_commit = master PACKAGES += erlpass pkg_erlpass_name = erlpass pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. pkg_erlpass_homepage = https://github.com/ferd/erlpass pkg_erlpass_fetch = git pkg_erlpass_repo = https://github.com/ferd/erlpass pkg_erlpass_commit = master PACKAGES += erlport pkg_erlport_name = erlport pkg_erlport_description = ErlPort - connect Erlang to other languages pkg_erlport_homepage = https://github.com/hdima/erlport pkg_erlport_fetch = git pkg_erlport_repo = https://github.com/hdima/erlport pkg_erlport_commit = master PACKAGES += erlsh pkg_erlsh_name = erlsh pkg_erlsh_description = Erlang shell tools pkg_erlsh_homepage = https://github.com/proger/erlsh pkg_erlsh_fetch = git pkg_erlsh_repo = https://github.com/proger/erlsh pkg_erlsh_commit = master PACKAGES += erlsha2 pkg_erlsha2_name = erlsha2 pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 pkg_erlsha2_fetch = git pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 pkg_erlsha2_commit = master PACKAGES += erlsom pkg_erlsom_name = erlsom pkg_erlsom_description = XML parser for Erlang pkg_erlsom_homepage = https://github.com/willemdj/erlsom pkg_erlsom_fetch = git pkg_erlsom_repo = https://github.com/willemdj/erlsom pkg_erlsom_commit = master PACKAGES += erlubi pkg_erlubi_name = erlubi pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi pkg_erlubi_fetch = git pkg_erlubi_repo = https://github.com/krestenkrab/erlubi pkg_erlubi_commit = master PACKAGES += erlvolt pkg_erlvolt_name = erlvolt pkg_erlvolt_description = VoltDB Erlang Client Driver pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang pkg_erlvolt_fetch = git pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang pkg_erlvolt_commit = master PACKAGES += erlware_commons pkg_erlware_commons_name = erlware_commons pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons pkg_erlware_commons_fetch = git pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons pkg_erlware_commons_commit = master PACKAGES += erlydtl pkg_erlydtl_name = erlydtl pkg_erlydtl_description = Django Template Language for Erlang. pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl pkg_erlydtl_fetch = git pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl pkg_erlydtl_commit = master PACKAGES += errd pkg_errd_name = errd pkg_errd_description = Erlang RRDTool library pkg_errd_homepage = https://github.com/archaelus/errd pkg_errd_fetch = git pkg_errd_repo = https://github.com/archaelus/errd pkg_errd_commit = master PACKAGES += erserve pkg_erserve_name = erserve pkg_erserve_description = Erlang/Rserve communication interface pkg_erserve_homepage = https://github.com/del/erserve pkg_erserve_fetch = git pkg_erserve_repo = https://github.com/del/erserve pkg_erserve_commit = master PACKAGES += erwa pkg_erwa_name = erwa pkg_erwa_description = A WAMP router and client written in Erlang. pkg_erwa_homepage = https://github.com/bwegh/erwa pkg_erwa_fetch = git pkg_erwa_repo = https://github.com/bwegh/erwa pkg_erwa_commit = master PACKAGES += escalus pkg_escalus_name = escalus pkg_escalus_description = An XMPP client library in Erlang for conveniently testing XMPP servers pkg_escalus_homepage = https://github.com/esl/escalus pkg_escalus_fetch = git pkg_escalus_repo = https://github.com/esl/escalus pkg_escalus_commit = master PACKAGES += espec pkg_espec_name = espec pkg_espec_description = ESpec: Behaviour driven development framework for Erlang pkg_espec_homepage = https://github.com/lucaspiller/espec pkg_espec_fetch = git pkg_espec_repo = https://github.com/lucaspiller/espec pkg_espec_commit = master PACKAGES += estatsd pkg_estatsd_name = estatsd pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite pkg_estatsd_homepage = https://github.com/RJ/estatsd pkg_estatsd_fetch = git pkg_estatsd_repo = https://github.com/RJ/estatsd pkg_estatsd_commit = master PACKAGES += etap pkg_etap_name = etap pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. pkg_etap_homepage = https://github.com/ngerakines/etap pkg_etap_fetch = git pkg_etap_repo = https://github.com/ngerakines/etap pkg_etap_commit = master PACKAGES += etest pkg_etest_name = etest pkg_etest_description = A lightweight, convention over configuration test framework for Erlang pkg_etest_homepage = https://github.com/wooga/etest pkg_etest_fetch = git pkg_etest_repo = https://github.com/wooga/etest pkg_etest_commit = master PACKAGES += etest_http pkg_etest_http_name = etest_http pkg_etest_http_description = etest Assertions around HTTP (client-side) pkg_etest_http_homepage = https://github.com/wooga/etest_http pkg_etest_http_fetch = git pkg_etest_http_repo = https://github.com/wooga/etest_http pkg_etest_http_commit = master PACKAGES += etoml pkg_etoml_name = etoml pkg_etoml_description = TOML language erlang parser pkg_etoml_homepage = https://github.com/kalta/etoml pkg_etoml_fetch = git pkg_etoml_repo = https://github.com/kalta/etoml pkg_etoml_commit = master PACKAGES += eunit pkg_eunit_name = eunit pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. pkg_eunit_homepage = https://github.com/richcarl/eunit pkg_eunit_fetch = git pkg_eunit_repo = https://github.com/richcarl/eunit pkg_eunit_commit = master PACKAGES += eunit_formatters pkg_eunit_formatters_name = eunit_formatters pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters pkg_eunit_formatters_fetch = git pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters pkg_eunit_formatters_commit = master PACKAGES += euthanasia pkg_euthanasia_name = euthanasia pkg_euthanasia_description = Merciful killer for your Erlang processes pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia pkg_euthanasia_fetch = git pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia pkg_euthanasia_commit = master PACKAGES += evum pkg_evum_name = evum pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM pkg_evum_homepage = https://github.com/msantos/evum pkg_evum_fetch = git pkg_evum_repo = https://github.com/msantos/evum pkg_evum_commit = master PACKAGES += exec pkg_exec_name = erlexec pkg_exec_description = Execute and control OS processes from Erlang/OTP. pkg_exec_homepage = http://saleyn.github.com/erlexec pkg_exec_fetch = git pkg_exec_repo = https://github.com/saleyn/erlexec pkg_exec_commit = master PACKAGES += exml pkg_exml_name = exml pkg_exml_description = XML parsing library in Erlang pkg_exml_homepage = https://github.com/paulgray/exml pkg_exml_fetch = git pkg_exml_repo = https://github.com/paulgray/exml pkg_exml_commit = master PACKAGES += exometer pkg_exometer_name = exometer pkg_exometer_description = Basic measurement objects and probe behavior pkg_exometer_homepage = https://github.com/Feuerlabs/exometer pkg_exometer_fetch = git pkg_exometer_repo = https://github.com/Feuerlabs/exometer pkg_exometer_commit = master PACKAGES += exs1024 pkg_exs1024_name = exs1024 pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 pkg_exs1024_fetch = git pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 pkg_exs1024_commit = master PACKAGES += exs64 pkg_exs64_name = exs64 pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. pkg_exs64_homepage = https://github.com/jj1bdx/exs64 pkg_exs64_fetch = git pkg_exs64_repo = https://github.com/jj1bdx/exs64 pkg_exs64_commit = master PACKAGES += exsplus116 pkg_exsplus116_name = exsplus116 pkg_exsplus116_description = Xorshift116plus for Erlang pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 pkg_exsplus116_fetch = git pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 pkg_exsplus116_commit = master PACKAGES += exsplus128 pkg_exsplus128_name = exsplus128 pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 pkg_exsplus128_fetch = git pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 pkg_exsplus128_commit = master PACKAGES += ezmq pkg_ezmq_name = ezmq pkg_ezmq_description = zMQ implemented in Erlang pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq pkg_ezmq_fetch = git pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq pkg_ezmq_commit = master PACKAGES += ezmtp pkg_ezmtp_name = ezmtp pkg_ezmtp_description = ZMTP protocol in pure Erlang. pkg_ezmtp_homepage = https://github.com/a13x/ezmtp pkg_ezmtp_fetch = git pkg_ezmtp_repo = https://github.com/a13x/ezmtp pkg_ezmtp_commit = master PACKAGES += fast_disk_log pkg_fast_disk_log_name = fast_disk_log pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log pkg_fast_disk_log_fetch = git pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log pkg_fast_disk_log_commit = master PACKAGES += feeder pkg_feeder_name = feeder pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. pkg_feeder_homepage = https://github.com/michaelnisi/feeder pkg_feeder_fetch = git pkg_feeder_repo = https://github.com/michaelnisi/feeder pkg_feeder_commit = master PACKAGES += find_crate pkg_find_crate_name = find_crate pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory pkg_find_crate_homepage = https://github.com/goertzenator/find_crate pkg_find_crate_fetch = git pkg_find_crate_repo = https://github.com/goertzenator/find_crate pkg_find_crate_commit = master PACKAGES += fix pkg_fix_name = fix pkg_fix_description = http://fixprotocol.org/ implementation. pkg_fix_homepage = https://github.com/maxlapshin/fix pkg_fix_fetch = git pkg_fix_repo = https://github.com/maxlapshin/fix pkg_fix_commit = master PACKAGES += flower pkg_flower_name = flower pkg_flower_description = FlowER - a Erlang OpenFlow development platform pkg_flower_homepage = https://github.com/travelping/flower pkg_flower_fetch = git pkg_flower_repo = https://github.com/travelping/flower pkg_flower_commit = master PACKAGES += fn pkg_fn_name = fn pkg_fn_description = Function utilities for Erlang pkg_fn_homepage = https://github.com/reiddraper/fn pkg_fn_fetch = git pkg_fn_repo = https://github.com/reiddraper/fn pkg_fn_commit = master PACKAGES += folsom pkg_folsom_name = folsom pkg_folsom_description = Expose Erlang Events and Metrics pkg_folsom_homepage = https://github.com/boundary/folsom pkg_folsom_fetch = git pkg_folsom_repo = https://github.com/boundary/folsom pkg_folsom_commit = master PACKAGES += folsom_cowboy pkg_folsom_cowboy_name = folsom_cowboy pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy pkg_folsom_cowboy_fetch = git pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy pkg_folsom_cowboy_commit = master PACKAGES += folsomite pkg_folsomite_name = folsomite pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics pkg_folsomite_homepage = https://github.com/campanja/folsomite pkg_folsomite_fetch = git pkg_folsomite_repo = https://github.com/campanja/folsomite pkg_folsomite_commit = master PACKAGES += fs pkg_fs_name = fs pkg_fs_description = Erlang FileSystem Listener pkg_fs_homepage = https://github.com/synrc/fs pkg_fs_fetch = git pkg_fs_repo = https://github.com/synrc/fs pkg_fs_commit = master PACKAGES += fuse pkg_fuse_name = fuse pkg_fuse_description = A Circuit Breaker for Erlang pkg_fuse_homepage = https://github.com/jlouis/fuse pkg_fuse_fetch = git pkg_fuse_repo = https://github.com/jlouis/fuse pkg_fuse_commit = master PACKAGES += gcm pkg_gcm_name = gcm pkg_gcm_description = An Erlang application for Google Cloud Messaging pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang pkg_gcm_fetch = git pkg_gcm_repo = https://github.com/pdincau/gcm-erlang pkg_gcm_commit = master PACKAGES += gcprof pkg_gcprof_name = gcprof pkg_gcprof_description = Garbage Collection profiler for Erlang pkg_gcprof_homepage = https://github.com/knutin/gcprof pkg_gcprof_fetch = git pkg_gcprof_repo = https://github.com/knutin/gcprof pkg_gcprof_commit = master PACKAGES += geas pkg_geas_name = geas pkg_geas_description = Guess Erlang Application Scattering pkg_geas_homepage = https://github.com/crownedgrouse/geas pkg_geas_fetch = git pkg_geas_repo = https://github.com/crownedgrouse/geas pkg_geas_commit = master PACKAGES += geef pkg_geef_name = geef pkg_geef_description = Git NEEEEF (Erlang NIF) pkg_geef_homepage = https://github.com/carlosmn/geef pkg_geef_fetch = git pkg_geef_repo = https://github.com/carlosmn/geef pkg_geef_commit = master PACKAGES += gen_coap pkg_gen_coap_name = gen_coap pkg_gen_coap_description = Generic Erlang CoAP Client/Server pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap pkg_gen_coap_fetch = git pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap pkg_gen_coap_commit = master PACKAGES += gen_cycle pkg_gen_cycle_name = gen_cycle pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle pkg_gen_cycle_fetch = git pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle pkg_gen_cycle_commit = develop PACKAGES += gen_icmp pkg_gen_icmp_name = gen_icmp pkg_gen_icmp_description = Erlang interface to ICMP sockets pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp pkg_gen_icmp_fetch = git pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp pkg_gen_icmp_commit = master PACKAGES += gen_leader pkg_gen_leader_name = gen_leader pkg_gen_leader_description = leader election behavior pkg_gen_leader_homepage = https://github.com/garret-smith/gen_leader_revival pkg_gen_leader_fetch = git pkg_gen_leader_repo = https://github.com/garret-smith/gen_leader_revival pkg_gen_leader_commit = master PACKAGES += gen_nb_server pkg_gen_nb_server_name = gen_nb_server pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server pkg_gen_nb_server_fetch = git pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server pkg_gen_nb_server_commit = master PACKAGES += gen_paxos pkg_gen_paxos_name = gen_paxos pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos pkg_gen_paxos_fetch = git pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos pkg_gen_paxos_commit = master PACKAGES += gen_rpc pkg_gen_rpc_name = gen_rpc pkg_gen_rpc_description = A scalable RPC library for Erlang-VM based languages pkg_gen_rpc_homepage = https://github.com/priestjim/gen_rpc.git pkg_gen_rpc_fetch = git pkg_gen_rpc_repo = https://github.com/priestjim/gen_rpc.git pkg_gen_rpc_commit = master PACKAGES += gen_smtp pkg_gen_smtp_name = gen_smtp pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp pkg_gen_smtp_fetch = git pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp pkg_gen_smtp_commit = master PACKAGES += gen_tracker pkg_gen_tracker_name = gen_tracker pkg_gen_tracker_description = supervisor with ets handling of children and their metadata pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker pkg_gen_tracker_fetch = git pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker pkg_gen_tracker_commit = master PACKAGES += gen_unix pkg_gen_unix_name = gen_unix pkg_gen_unix_description = Erlang Unix socket interface pkg_gen_unix_homepage = https://github.com/msantos/gen_unix pkg_gen_unix_fetch = git pkg_gen_unix_repo = https://github.com/msantos/gen_unix pkg_gen_unix_commit = master PACKAGES += geode pkg_geode_name = geode pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. pkg_geode_homepage = https://github.com/bradfordw/geode pkg_geode_fetch = git pkg_geode_repo = https://github.com/bradfordw/geode pkg_geode_commit = master PACKAGES += getopt pkg_getopt_name = getopt pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax pkg_getopt_homepage = https://github.com/jcomellas/getopt pkg_getopt_fetch = git pkg_getopt_repo = https://github.com/jcomellas/getopt pkg_getopt_commit = master PACKAGES += gettext pkg_gettext_name = gettext pkg_gettext_description = Erlang internationalization library. pkg_gettext_homepage = https://github.com/etnt/gettext pkg_gettext_fetch = git pkg_gettext_repo = https://github.com/etnt/gettext pkg_gettext_commit = master PACKAGES += giallo pkg_giallo_name = giallo pkg_giallo_description = Small and flexible web framework on top of Cowboy pkg_giallo_homepage = https://github.com/kivra/giallo pkg_giallo_fetch = git pkg_giallo_repo = https://github.com/kivra/giallo pkg_giallo_commit = master PACKAGES += gin pkg_gin_name = gin pkg_gin_description = The guards and for Erlang parse_transform pkg_gin_homepage = https://github.com/mad-cocktail/gin pkg_gin_fetch = git pkg_gin_repo = https://github.com/mad-cocktail/gin pkg_gin_commit = master PACKAGES += gitty pkg_gitty_name = gitty pkg_gitty_description = Git access in erlang pkg_gitty_homepage = https://github.com/maxlapshin/gitty pkg_gitty_fetch = git pkg_gitty_repo = https://github.com/maxlapshin/gitty pkg_gitty_commit = master PACKAGES += gold_fever pkg_gold_fever_name = gold_fever pkg_gold_fever_description = A Treasure Hunt for Erlangers pkg_gold_fever_homepage = https://github.com/inaka/gold_fever pkg_gold_fever_fetch = git pkg_gold_fever_repo = https://github.com/inaka/gold_fever pkg_gold_fever_commit = master PACKAGES += gpb pkg_gpb_name = gpb pkg_gpb_description = A Google Protobuf implementation for Erlang pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb pkg_gpb_fetch = git pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb pkg_gpb_commit = master PACKAGES += gproc pkg_gproc_name = gproc pkg_gproc_description = Extended process registry for Erlang pkg_gproc_homepage = https://github.com/uwiger/gproc pkg_gproc_fetch = git pkg_gproc_repo = https://github.com/uwiger/gproc pkg_gproc_commit = master PACKAGES += grapherl pkg_grapherl_name = grapherl pkg_grapherl_description = Create graphs of Erlang systems and programs pkg_grapherl_homepage = https://github.com/eproxus/grapherl pkg_grapherl_fetch = git pkg_grapherl_repo = https://github.com/eproxus/grapherl pkg_grapherl_commit = master PACKAGES += grpc pkg_grpc_name = grpc pkg_grpc_description = gRPC server in Erlang pkg_grpc_homepage = https://github.com/Bluehouse-Technology/grpc pkg_grpc_fetch = git pkg_grpc_repo = https://github.com/Bluehouse-Technology/grpc pkg_grpc_commit = master PACKAGES += grpc_client pkg_grpc_client_name = grpc_client pkg_grpc_client_description = gRPC client in Erlang pkg_grpc_client_homepage = https://github.com/Bluehouse-Technology/grpc_client pkg_grpc_client_fetch = git pkg_grpc_client_repo = https://github.com/Bluehouse-Technology/grpc_client pkg_grpc_client_commit = master PACKAGES += gun pkg_gun_name = gun pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. pkg_gun_homepage = http//ninenines.eu pkg_gun_fetch = git pkg_gun_repo = https://github.com/ninenines/gun pkg_gun_commit = master PACKAGES += gut pkg_gut_name = gut pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman pkg_gut_homepage = https://github.com/unbalancedparentheses/gut pkg_gut_fetch = git pkg_gut_repo = https://github.com/unbalancedparentheses/gut pkg_gut_commit = master PACKAGES += hackney pkg_hackney_name = hackney pkg_hackney_description = simple HTTP client in Erlang pkg_hackney_homepage = https://github.com/benoitc/hackney pkg_hackney_fetch = git pkg_hackney_repo = https://github.com/benoitc/hackney pkg_hackney_commit = master PACKAGES += hamcrest pkg_hamcrest_name = hamcrest pkg_hamcrest_description = Erlang port of Hamcrest pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang pkg_hamcrest_fetch = git pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang pkg_hamcrest_commit = master PACKAGES += hanoidb pkg_hanoidb_name = hanoidb pkg_hanoidb_description = Erlang LSM BTree Storage pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb pkg_hanoidb_fetch = git pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb pkg_hanoidb_commit = master PACKAGES += hottub pkg_hottub_name = hottub pkg_hottub_description = Permanent Erlang Worker Pool pkg_hottub_homepage = https://github.com/bfrog/hottub pkg_hottub_fetch = git pkg_hottub_repo = https://github.com/bfrog/hottub pkg_hottub_commit = master PACKAGES += hpack pkg_hpack_name = hpack pkg_hpack_description = HPACK Implementation for Erlang pkg_hpack_homepage = https://github.com/joedevivo/hpack pkg_hpack_fetch = git pkg_hpack_repo = https://github.com/joedevivo/hpack pkg_hpack_commit = master PACKAGES += hyper pkg_hyper_name = hyper pkg_hyper_description = Erlang implementation of HyperLogLog pkg_hyper_homepage = https://github.com/GameAnalytics/hyper pkg_hyper_fetch = git pkg_hyper_repo = https://github.com/GameAnalytics/hyper pkg_hyper_commit = master PACKAGES += i18n pkg_i18n_name = i18n pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) pkg_i18n_homepage = https://github.com/erlang-unicode/i18n pkg_i18n_fetch = git pkg_i18n_repo = https://github.com/erlang-unicode/i18n pkg_i18n_commit = master PACKAGES += ibrowse pkg_ibrowse_name = ibrowse pkg_ibrowse_description = Erlang HTTP client pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse pkg_ibrowse_fetch = git pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse pkg_ibrowse_commit = master PACKAGES += idna pkg_idna_name = idna pkg_idna_description = Erlang IDNA lib pkg_idna_homepage = https://github.com/benoitc/erlang-idna pkg_idna_fetch = git pkg_idna_repo = https://github.com/benoitc/erlang-idna pkg_idna_commit = master PACKAGES += ierlang pkg_ierlang_name = ierlang pkg_ierlang_description = An Erlang language kernel for IPython. pkg_ierlang_homepage = https://github.com/robbielynch/ierlang pkg_ierlang_fetch = git pkg_ierlang_repo = https://github.com/robbielynch/ierlang pkg_ierlang_commit = master PACKAGES += iota pkg_iota_name = iota pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code pkg_iota_homepage = https://github.com/jpgneves/iota pkg_iota_fetch = git pkg_iota_repo = https://github.com/jpgneves/iota pkg_iota_commit = master PACKAGES += irc_lib pkg_irc_lib_name = irc_lib pkg_irc_lib_description = Erlang irc client library pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib pkg_irc_lib_fetch = git pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib pkg_irc_lib_commit = master PACKAGES += ircd pkg_ircd_name = ircd pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd pkg_ircd_fetch = git pkg_ircd_repo = https://github.com/tonyg/erlang-ircd pkg_ircd_commit = master PACKAGES += iris pkg_iris_name = iris pkg_iris_description = Iris Erlang binding pkg_iris_homepage = https://github.com/project-iris/iris-erl pkg_iris_fetch = git pkg_iris_repo = https://github.com/project-iris/iris-erl pkg_iris_commit = master PACKAGES += iso8601 pkg_iso8601_name = iso8601 pkg_iso8601_description = Erlang ISO 8601 date formatter/parser pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 pkg_iso8601_fetch = git pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 pkg_iso8601_commit = master PACKAGES += jamdb_sybase pkg_jamdb_sybase_name = jamdb_sybase pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase pkg_jamdb_sybase_fetch = git pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase pkg_jamdb_sybase_commit = master PACKAGES += jerg pkg_jerg_name = jerg pkg_jerg_description = JSON Schema to Erlang Records Generator pkg_jerg_homepage = https://github.com/ddossot/jerg pkg_jerg_fetch = git pkg_jerg_repo = https://github.com/ddossot/jerg pkg_jerg_commit = master PACKAGES += jesse pkg_jesse_name = jesse pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. pkg_jesse_homepage = https://github.com/for-GET/jesse pkg_jesse_fetch = git pkg_jesse_repo = https://github.com/for-GET/jesse pkg_jesse_commit = master PACKAGES += jiffy pkg_jiffy_name = jiffy pkg_jiffy_description = JSON NIFs for Erlang. pkg_jiffy_homepage = https://github.com/davisp/jiffy pkg_jiffy_fetch = git pkg_jiffy_repo = https://github.com/davisp/jiffy pkg_jiffy_commit = master PACKAGES += jiffy_v pkg_jiffy_v_name = jiffy_v pkg_jiffy_v_description = JSON validation utility pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v pkg_jiffy_v_fetch = git pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v pkg_jiffy_v_commit = master PACKAGES += jobs pkg_jobs_name = jobs pkg_jobs_description = a Job scheduler for load regulation pkg_jobs_homepage = https://github.com/esl/jobs pkg_jobs_fetch = git pkg_jobs_repo = https://github.com/esl/jobs pkg_jobs_commit = master PACKAGES += joxa pkg_joxa_name = joxa pkg_joxa_description = A Modern Lisp for the Erlang VM pkg_joxa_homepage = https://github.com/joxa/joxa pkg_joxa_fetch = git pkg_joxa_repo = https://github.com/joxa/joxa pkg_joxa_commit = master PACKAGES += json pkg_json_name = json pkg_json_description = a high level json library for erlang (17.0+) pkg_json_homepage = https://github.com/talentdeficit/json pkg_json_fetch = git pkg_json_repo = https://github.com/talentdeficit/json pkg_json_commit = master PACKAGES += json_rec pkg_json_rec_name = json_rec pkg_json_rec_description = JSON to erlang record pkg_json_rec_homepage = https://github.com/justinkirby/json_rec pkg_json_rec_fetch = git pkg_json_rec_repo = https://github.com/justinkirby/json_rec pkg_json_rec_commit = master PACKAGES += jsone pkg_jsone_name = jsone pkg_jsone_description = An Erlang library for encoding, decoding JSON data. pkg_jsone_homepage = https://github.com/sile/jsone.git pkg_jsone_fetch = git pkg_jsone_repo = https://github.com/sile/jsone.git pkg_jsone_commit = master PACKAGES += jsonerl pkg_jsonerl_name = jsonerl pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder pkg_jsonerl_homepage = https://github.com/lambder/jsonerl pkg_jsonerl_fetch = git pkg_jsonerl_repo = https://github.com/lambder/jsonerl pkg_jsonerl_commit = master PACKAGES += jsonpath pkg_jsonpath_name = jsonpath pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath pkg_jsonpath_fetch = git pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath pkg_jsonpath_commit = master PACKAGES += jsonx pkg_jsonx_name = jsonx pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. pkg_jsonx_homepage = https://github.com/iskra/jsonx pkg_jsonx_fetch = git pkg_jsonx_repo = https://github.com/iskra/jsonx pkg_jsonx_commit = master PACKAGES += jsx pkg_jsx_name = jsx pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. pkg_jsx_homepage = https://github.com/talentdeficit/jsx pkg_jsx_fetch = git pkg_jsx_repo = https://github.com/talentdeficit/jsx pkg_jsx_commit = master PACKAGES += kafka pkg_kafka_name = kafka pkg_kafka_description = Kafka consumer and producer in Erlang pkg_kafka_homepage = https://github.com/wooga/kafka-erlang pkg_kafka_fetch = git pkg_kafka_repo = https://github.com/wooga/kafka-erlang pkg_kafka_commit = master PACKAGES += kafka_protocol pkg_kafka_protocol_name = kafka_protocol pkg_kafka_protocol_description = Kafka protocol Erlang library pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol pkg_kafka_protocol_fetch = git pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git pkg_kafka_protocol_commit = master PACKAGES += kai pkg_kai_name = kai pkg_kai_description = DHT storage by Takeshi Inoue pkg_kai_homepage = https://github.com/synrc/kai pkg_kai_fetch = git pkg_kai_repo = https://github.com/synrc/kai pkg_kai_commit = master PACKAGES += katja pkg_katja_name = katja pkg_katja_description = A simple Riemann client written in Erlang. pkg_katja_homepage = https://github.com/nifoc/katja pkg_katja_fetch = git pkg_katja_repo = https://github.com/nifoc/katja pkg_katja_commit = master PACKAGES += kdht pkg_kdht_name = kdht pkg_kdht_description = kdht is an erlang DHT implementation pkg_kdht_homepage = https://github.com/kevinlynx/kdht pkg_kdht_fetch = git pkg_kdht_repo = https://github.com/kevinlynx/kdht pkg_kdht_commit = master PACKAGES += key2value pkg_key2value_name = key2value pkg_key2value_description = Erlang 2-way map pkg_key2value_homepage = https://github.com/okeuday/key2value pkg_key2value_fetch = git pkg_key2value_repo = https://github.com/okeuday/key2value pkg_key2value_commit = master PACKAGES += keys1value pkg_keys1value_name = keys1value pkg_keys1value_description = Erlang set associative map for key lists pkg_keys1value_homepage = https://github.com/okeuday/keys1value pkg_keys1value_fetch = git pkg_keys1value_repo = https://github.com/okeuday/keys1value pkg_keys1value_commit = master PACKAGES += kinetic pkg_kinetic_name = kinetic pkg_kinetic_description = Erlang Kinesis Client pkg_kinetic_homepage = https://github.com/AdRoll/kinetic pkg_kinetic_fetch = git pkg_kinetic_repo = https://github.com/AdRoll/kinetic pkg_kinetic_commit = master PACKAGES += kjell pkg_kjell_name = kjell pkg_kjell_description = Erlang Shell pkg_kjell_homepage = https://github.com/karlll/kjell pkg_kjell_fetch = git pkg_kjell_repo = https://github.com/karlll/kjell pkg_kjell_commit = master PACKAGES += kraken pkg_kraken_name = kraken pkg_kraken_description = Distributed Pubsub Server for Realtime Apps pkg_kraken_homepage = https://github.com/Asana/kraken pkg_kraken_fetch = git pkg_kraken_repo = https://github.com/Asana/kraken pkg_kraken_commit = master PACKAGES += kucumberl pkg_kucumberl_name = kucumberl pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber pkg_kucumberl_homepage = https://github.com/openshine/kucumberl pkg_kucumberl_fetch = git pkg_kucumberl_repo = https://github.com/openshine/kucumberl pkg_kucumberl_commit = master PACKAGES += kvc pkg_kvc_name = kvc pkg_kvc_description = KVC - Key Value Coding for Erlang data structures pkg_kvc_homepage = https://github.com/etrepum/kvc pkg_kvc_fetch = git pkg_kvc_repo = https://github.com/etrepum/kvc pkg_kvc_commit = master PACKAGES += kvlists pkg_kvlists_name = kvlists pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang pkg_kvlists_homepage = https://github.com/jcomellas/kvlists pkg_kvlists_fetch = git pkg_kvlists_repo = https://github.com/jcomellas/kvlists pkg_kvlists_commit = master PACKAGES += kvs pkg_kvs_name = kvs pkg_kvs_description = Container and Iterator pkg_kvs_homepage = https://github.com/synrc/kvs pkg_kvs_fetch = git pkg_kvs_repo = https://github.com/synrc/kvs pkg_kvs_commit = master PACKAGES += lager pkg_lager_name = lager pkg_lager_description = A logging framework for Erlang/OTP. pkg_lager_homepage = https://github.com/erlang-lager/lager pkg_lager_fetch = git pkg_lager_repo = https://github.com/erlang-lager/lager pkg_lager_commit = master PACKAGES += lager_amqp_backend pkg_lager_amqp_backend_name = lager_amqp_backend pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend pkg_lager_amqp_backend_fetch = git pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend pkg_lager_amqp_backend_commit = master PACKAGES += lager_syslog pkg_lager_syslog_name = lager_syslog pkg_lager_syslog_description = Syslog backend for lager pkg_lager_syslog_homepage = https://github.com/erlang-lager/lager_syslog pkg_lager_syslog_fetch = git pkg_lager_syslog_repo = https://github.com/erlang-lager/lager_syslog pkg_lager_syslog_commit = master PACKAGES += lambdapad pkg_lambdapad_name = lambdapad pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad pkg_lambdapad_fetch = git pkg_lambdapad_repo = https://github.com/gar1t/lambdapad pkg_lambdapad_commit = master PACKAGES += lasp pkg_lasp_name = lasp pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations pkg_lasp_homepage = http://lasp-lang.org/ pkg_lasp_fetch = git pkg_lasp_repo = https://github.com/lasp-lang/lasp pkg_lasp_commit = master PACKAGES += lasse pkg_lasse_name = lasse pkg_lasse_description = SSE handler for Cowboy pkg_lasse_homepage = https://github.com/inaka/lasse pkg_lasse_fetch = git pkg_lasse_repo = https://github.com/inaka/lasse pkg_lasse_commit = master PACKAGES += ldap pkg_ldap_name = ldap pkg_ldap_description = LDAP server written in Erlang pkg_ldap_homepage = https://github.com/spawnproc/ldap pkg_ldap_fetch = git pkg_ldap_repo = https://github.com/spawnproc/ldap pkg_ldap_commit = master PACKAGES += lethink pkg_lethink_name = lethink pkg_lethink_description = erlang driver for rethinkdb pkg_lethink_homepage = https://github.com/taybin/lethink pkg_lethink_fetch = git pkg_lethink_repo = https://github.com/taybin/lethink pkg_lethink_commit = master PACKAGES += lfe pkg_lfe_name = lfe pkg_lfe_description = Lisp Flavoured Erlang (LFE) pkg_lfe_homepage = https://github.com/rvirding/lfe pkg_lfe_fetch = git pkg_lfe_repo = https://github.com/rvirding/lfe pkg_lfe_commit = master PACKAGES += ling pkg_ling_name = ling pkg_ling_description = Erlang on Xen pkg_ling_homepage = https://github.com/cloudozer/ling pkg_ling_fetch = git pkg_ling_repo = https://github.com/cloudozer/ling pkg_ling_commit = master PACKAGES += live pkg_live_name = live pkg_live_description = Automated module and configuration reloader. pkg_live_homepage = http://ninenines.eu pkg_live_fetch = git pkg_live_repo = https://github.com/ninenines/live pkg_live_commit = master PACKAGES += lmq pkg_lmq_name = lmq pkg_lmq_description = Lightweight Message Queue pkg_lmq_homepage = https://github.com/iij/lmq pkg_lmq_fetch = git pkg_lmq_repo = https://github.com/iij/lmq pkg_lmq_commit = master PACKAGES += locker pkg_locker_name = locker pkg_locker_description = Atomic distributed 'check and set' for short-lived keys pkg_locker_homepage = https://github.com/wooga/locker pkg_locker_fetch = git pkg_locker_repo = https://github.com/wooga/locker pkg_locker_commit = master PACKAGES += locks pkg_locks_name = locks pkg_locks_description = A scalable, deadlock-resolving resource locker pkg_locks_homepage = https://github.com/uwiger/locks pkg_locks_fetch = git pkg_locks_repo = https://github.com/uwiger/locks pkg_locks_commit = master PACKAGES += log4erl pkg_log4erl_name = log4erl pkg_log4erl_description = A logger for erlang in the spirit of Log4J. pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl pkg_log4erl_fetch = git pkg_log4erl_repo = https://github.com/ahmednawras/log4erl pkg_log4erl_commit = master PACKAGES += lol pkg_lol_name = lol pkg_lol_description = Lisp on erLang, and programming is fun again pkg_lol_homepage = https://github.com/b0oh/lol pkg_lol_fetch = git pkg_lol_repo = https://github.com/b0oh/lol pkg_lol_commit = master PACKAGES += lucid pkg_lucid_name = lucid pkg_lucid_description = HTTP/2 server written in Erlang pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid pkg_lucid_fetch = git pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid pkg_lucid_commit = master PACKAGES += luerl pkg_luerl_name = luerl pkg_luerl_description = Lua in Erlang pkg_luerl_homepage = https://github.com/rvirding/luerl pkg_luerl_fetch = git pkg_luerl_repo = https://github.com/rvirding/luerl pkg_luerl_commit = develop PACKAGES += luwak pkg_luwak_name = luwak pkg_luwak_description = Large-object storage interface for Riak pkg_luwak_homepage = https://github.com/basho/luwak pkg_luwak_fetch = git pkg_luwak_repo = https://github.com/basho/luwak pkg_luwak_commit = master PACKAGES += lux pkg_lux_name = lux pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands pkg_lux_homepage = https://github.com/hawk/lux pkg_lux_fetch = git pkg_lux_repo = https://github.com/hawk/lux pkg_lux_commit = master PACKAGES += machi pkg_machi_name = machi pkg_machi_description = Machi file store pkg_machi_homepage = https://github.com/basho/machi pkg_machi_fetch = git pkg_machi_repo = https://github.com/basho/machi pkg_machi_commit = master PACKAGES += mad pkg_mad_name = mad pkg_mad_description = Small and Fast Rebar Replacement pkg_mad_homepage = https://github.com/synrc/mad pkg_mad_fetch = git pkg_mad_repo = https://github.com/synrc/mad pkg_mad_commit = master PACKAGES += marina pkg_marina_name = marina pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client pkg_marina_homepage = https://github.com/lpgauth/marina pkg_marina_fetch = git pkg_marina_repo = https://github.com/lpgauth/marina pkg_marina_commit = master PACKAGES += mavg pkg_mavg_name = mavg pkg_mavg_description = Erlang :: Exponential moving average library pkg_mavg_homepage = https://github.com/EchoTeam/mavg pkg_mavg_fetch = git pkg_mavg_repo = https://github.com/EchoTeam/mavg pkg_mavg_commit = master PACKAGES += mc_erl pkg_mc_erl_name = mc_erl pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl pkg_mc_erl_fetch = git pkg_mc_erl_repo = https://github.com/clonejo/mc-erl pkg_mc_erl_commit = master PACKAGES += mcd pkg_mcd_name = mcd pkg_mcd_description = Fast memcached protocol client in pure Erlang pkg_mcd_homepage = https://github.com/EchoTeam/mcd pkg_mcd_fetch = git pkg_mcd_repo = https://github.com/EchoTeam/mcd pkg_mcd_commit = master PACKAGES += mcerlang pkg_mcerlang_name = mcerlang pkg_mcerlang_description = The McErlang model checker for Erlang pkg_mcerlang_homepage = https://github.com/fredlund/McErlang pkg_mcerlang_fetch = git pkg_mcerlang_repo = https://github.com/fredlund/McErlang pkg_mcerlang_commit = master PACKAGES += meck pkg_meck_name = meck pkg_meck_description = A mocking library for Erlang pkg_meck_homepage = https://github.com/eproxus/meck pkg_meck_fetch = git pkg_meck_repo = https://github.com/eproxus/meck pkg_meck_commit = master PACKAGES += mekao pkg_mekao_name = mekao pkg_mekao_description = SQL constructor pkg_mekao_homepage = https://github.com/ddosia/mekao pkg_mekao_fetch = git pkg_mekao_repo = https://github.com/ddosia/mekao pkg_mekao_commit = master PACKAGES += memo pkg_memo_name = memo pkg_memo_description = Erlang memoization server pkg_memo_homepage = https://github.com/tuncer/memo pkg_memo_fetch = git pkg_memo_repo = https://github.com/tuncer/memo pkg_memo_commit = master PACKAGES += merge_index pkg_merge_index_name = merge_index pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). pkg_merge_index_homepage = https://github.com/basho/merge_index pkg_merge_index_fetch = git pkg_merge_index_repo = https://github.com/basho/merge_index pkg_merge_index_commit = master PACKAGES += merl pkg_merl_name = merl pkg_merl_description = Metaprogramming in Erlang pkg_merl_homepage = https://github.com/richcarl/merl pkg_merl_fetch = git pkg_merl_repo = https://github.com/richcarl/merl pkg_merl_commit = master PACKAGES += mimerl pkg_mimerl_name = mimerl pkg_mimerl_description = library to handle mimetypes pkg_mimerl_homepage = https://github.com/benoitc/mimerl pkg_mimerl_fetch = git pkg_mimerl_repo = https://github.com/benoitc/mimerl pkg_mimerl_commit = master PACKAGES += mimetypes pkg_mimetypes_name = mimetypes pkg_mimetypes_description = Erlang MIME types library pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes pkg_mimetypes_fetch = git pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes pkg_mimetypes_commit = master PACKAGES += mixer pkg_mixer_name = mixer pkg_mixer_description = Mix in functions from other modules pkg_mixer_homepage = https://github.com/chef/mixer pkg_mixer_fetch = git pkg_mixer_repo = https://github.com/chef/mixer pkg_mixer_commit = master PACKAGES += mochiweb pkg_mochiweb_name = mochiweb pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. pkg_mochiweb_homepage = https://github.com/mochi/mochiweb pkg_mochiweb_fetch = git pkg_mochiweb_repo = https://github.com/mochi/mochiweb pkg_mochiweb_commit = master PACKAGES += mochiweb_xpath pkg_mochiweb_xpath_name = mochiweb_xpath pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath pkg_mochiweb_xpath_fetch = git pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath pkg_mochiweb_xpath_commit = master PACKAGES += mockgyver pkg_mockgyver_name = mockgyver pkg_mockgyver_description = A mocking library for Erlang pkg_mockgyver_homepage = https://github.com/klajo/mockgyver pkg_mockgyver_fetch = git pkg_mockgyver_repo = https://github.com/klajo/mockgyver pkg_mockgyver_commit = master PACKAGES += modlib pkg_modlib_name = modlib pkg_modlib_description = Web framework based on Erlang's inets httpd pkg_modlib_homepage = https://github.com/gar1t/modlib pkg_modlib_fetch = git pkg_modlib_repo = https://github.com/gar1t/modlib pkg_modlib_commit = master PACKAGES += mongodb pkg_mongodb_name = mongodb pkg_mongodb_description = MongoDB driver for Erlang pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang pkg_mongodb_fetch = git pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang pkg_mongodb_commit = master PACKAGES += mongooseim pkg_mongooseim_name = mongooseim pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform pkg_mongooseim_fetch = git pkg_mongooseim_repo = https://github.com/esl/MongooseIM pkg_mongooseim_commit = master PACKAGES += moyo pkg_moyo_name = moyo pkg_moyo_description = Erlang utility functions library pkg_moyo_homepage = https://github.com/dwango/moyo pkg_moyo_fetch = git pkg_moyo_repo = https://github.com/dwango/moyo pkg_moyo_commit = master PACKAGES += msgpack pkg_msgpack_name = msgpack pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang pkg_msgpack_fetch = git pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang pkg_msgpack_commit = master PACKAGES += mu2 pkg_mu2_name = mu2 pkg_mu2_description = Erlang mutation testing tool pkg_mu2_homepage = https://github.com/ramsay-t/mu2 pkg_mu2_fetch = git pkg_mu2_repo = https://github.com/ramsay-t/mu2 pkg_mu2_commit = master PACKAGES += mustache pkg_mustache_name = mustache pkg_mustache_description = Mustache template engine for Erlang. pkg_mustache_homepage = https://github.com/mojombo/mustache.erl pkg_mustache_fetch = git pkg_mustache_repo = https://github.com/mojombo/mustache.erl pkg_mustache_commit = master PACKAGES += myproto pkg_myproto_name = myproto pkg_myproto_description = MySQL Server Protocol in Erlang pkg_myproto_homepage = https://github.com/altenwald/myproto pkg_myproto_fetch = git pkg_myproto_repo = https://github.com/altenwald/myproto pkg_myproto_commit = master PACKAGES += mysql pkg_mysql_name = mysql pkg_mysql_description = Erlang MySQL Driver (from code.google.com) pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver pkg_mysql_fetch = git pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver pkg_mysql_commit = master PACKAGES += n2o pkg_n2o_name = n2o pkg_n2o_description = WebSocket Application Server pkg_n2o_homepage = https://github.com/5HT/n2o pkg_n2o_fetch = git pkg_n2o_repo = https://github.com/5HT/n2o pkg_n2o_commit = master PACKAGES += nat_upnp pkg_nat_upnp_name = nat_upnp pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp pkg_nat_upnp_fetch = git pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp pkg_nat_upnp_commit = master PACKAGES += neo4j pkg_neo4j_name = neo4j pkg_neo4j_description = Erlang client library for Neo4J. pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang pkg_neo4j_fetch = git pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang pkg_neo4j_commit = master PACKAGES += neotoma pkg_neotoma_name = neotoma pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. pkg_neotoma_homepage = https://github.com/seancribbs/neotoma pkg_neotoma_fetch = git pkg_neotoma_repo = https://github.com/seancribbs/neotoma pkg_neotoma_commit = master PACKAGES += newrelic pkg_newrelic_name = newrelic pkg_newrelic_description = Erlang library for sending metrics to New Relic pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang pkg_newrelic_fetch = git pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang pkg_newrelic_commit = master PACKAGES += nifty pkg_nifty_name = nifty pkg_nifty_description = Erlang NIF wrapper generator pkg_nifty_homepage = https://github.com/parapluu/nifty pkg_nifty_fetch = git pkg_nifty_repo = https://github.com/parapluu/nifty pkg_nifty_commit = master PACKAGES += nitrogen_core pkg_nitrogen_core_name = nitrogen_core pkg_nitrogen_core_description = The core Nitrogen library. pkg_nitrogen_core_homepage = http://nitrogenproject.com/ pkg_nitrogen_core_fetch = git pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core pkg_nitrogen_core_commit = master PACKAGES += nkbase pkg_nkbase_name = nkbase pkg_nkbase_description = NkBASE distributed database pkg_nkbase_homepage = https://github.com/Nekso/nkbase pkg_nkbase_fetch = git pkg_nkbase_repo = https://github.com/Nekso/nkbase pkg_nkbase_commit = develop PACKAGES += nkdocker pkg_nkdocker_name = nkdocker pkg_nkdocker_description = Erlang Docker client pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker pkg_nkdocker_fetch = git pkg_nkdocker_repo = https://github.com/Nekso/nkdocker pkg_nkdocker_commit = master PACKAGES += nkpacket pkg_nkpacket_name = nkpacket pkg_nkpacket_description = Generic Erlang transport layer pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket pkg_nkpacket_fetch = git pkg_nkpacket_repo = https://github.com/Nekso/nkpacket pkg_nkpacket_commit = master PACKAGES += nksip pkg_nksip_name = nksip pkg_nksip_description = Erlang SIP application server pkg_nksip_homepage = https://github.com/kalta/nksip pkg_nksip_fetch = git pkg_nksip_repo = https://github.com/kalta/nksip pkg_nksip_commit = master PACKAGES += nodefinder pkg_nodefinder_name = nodefinder pkg_nodefinder_description = automatic node discovery via UDP multicast pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder pkg_nodefinder_fetch = git pkg_nodefinder_repo = https://github.com/okeuday/nodefinder pkg_nodefinder_commit = master PACKAGES += nprocreg pkg_nprocreg_name = nprocreg pkg_nprocreg_description = Minimal Distributed Erlang Process Registry pkg_nprocreg_homepage = http://nitrogenproject.com/ pkg_nprocreg_fetch = git pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg pkg_nprocreg_commit = master PACKAGES += oauth pkg_oauth_name = oauth pkg_oauth_description = An Erlang OAuth 1.0 implementation pkg_oauth_homepage = https://github.com/tim/erlang-oauth pkg_oauth_fetch = git pkg_oauth_repo = https://github.com/tim/erlang-oauth pkg_oauth_commit = master PACKAGES += oauth2 pkg_oauth2_name = oauth2 pkg_oauth2_description = Erlang Oauth2 implementation pkg_oauth2_homepage = https://github.com/kivra/oauth2 pkg_oauth2_fetch = git pkg_oauth2_repo = https://github.com/kivra/oauth2 pkg_oauth2_commit = master PACKAGES += observer_cli pkg_observer_cli_name = observer_cli pkg_observer_cli_description = Visualize Erlang/Elixir Nodes On The Command Line pkg_observer_cli_homepage = http://zhongwencool.github.io/observer_cli pkg_observer_cli_fetch = git pkg_observer_cli_repo = https://github.com/zhongwencool/observer_cli pkg_observer_cli_commit = master PACKAGES += octopus pkg_octopus_name = octopus pkg_octopus_description = Small and flexible pool manager written in Erlang pkg_octopus_homepage = https://github.com/erlangbureau/octopus pkg_octopus_fetch = git pkg_octopus_repo = https://github.com/erlangbureau/octopus pkg_octopus_commit = master PACKAGES += of_protocol pkg_of_protocol_name = of_protocol pkg_of_protocol_description = OpenFlow Protocol Library for Erlang pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol pkg_of_protocol_fetch = git pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol pkg_of_protocol_commit = master PACKAGES += opencouch pkg_opencouch_name = couch pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB pkg_opencouch_homepage = https://github.com/benoitc/opencouch pkg_opencouch_fetch = git pkg_opencouch_repo = https://github.com/benoitc/opencouch pkg_opencouch_commit = master PACKAGES += openflow pkg_openflow_name = openflow pkg_openflow_description = An OpenFlow controller written in pure erlang pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow pkg_openflow_fetch = git pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow pkg_openflow_commit = master PACKAGES += openid pkg_openid_name = openid pkg_openid_description = Erlang OpenID pkg_openid_homepage = https://github.com/brendonh/erl_openid pkg_openid_fetch = git pkg_openid_repo = https://github.com/brendonh/erl_openid pkg_openid_commit = master PACKAGES += openpoker pkg_openpoker_name = openpoker pkg_openpoker_description = Genesis Texas hold'em Game Server pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker pkg_openpoker_fetch = git pkg_openpoker_repo = https://github.com/hpyhacking/openpoker pkg_openpoker_commit = master PACKAGES += otpbp pkg_otpbp_name = otpbp pkg_otpbp_description = Parse transformer for use new OTP functions in old Erlang/OTP releases (R15, R16, 17, 18, 19) pkg_otpbp_homepage = https://github.com/Ledest/otpbp pkg_otpbp_fetch = git pkg_otpbp_repo = https://github.com/Ledest/otpbp pkg_otpbp_commit = master PACKAGES += pal pkg_pal_name = pal pkg_pal_description = Pragmatic Authentication Library pkg_pal_homepage = https://github.com/manifest/pal pkg_pal_fetch = git pkg_pal_repo = https://github.com/manifest/pal pkg_pal_commit = master PACKAGES += parse_trans pkg_parse_trans_name = parse_trans pkg_parse_trans_description = Parse transform utilities for Erlang pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans pkg_parse_trans_fetch = git pkg_parse_trans_repo = https://github.com/uwiger/parse_trans pkg_parse_trans_commit = master PACKAGES += parsexml pkg_parsexml_name = parsexml pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml pkg_parsexml_fetch = git pkg_parsexml_repo = https://github.com/maxlapshin/parsexml pkg_parsexml_commit = master PACKAGES += pegjs pkg_pegjs_name = pegjs pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. pkg_pegjs_homepage = https://github.com/dmitriid/pegjs pkg_pegjs_fetch = git pkg_pegjs_repo = https://github.com/dmitriid/pegjs pkg_pegjs_commit = master PACKAGES += percept2 pkg_percept2_name = percept2 pkg_percept2_description = Concurrent profiling tool for Erlang pkg_percept2_homepage = https://github.com/huiqing/percept2 pkg_percept2_fetch = git pkg_percept2_repo = https://github.com/huiqing/percept2 pkg_percept2_commit = master PACKAGES += pgo pkg_pgo_name = pgo pkg_pgo_description = Erlang Postgres client and connection pool pkg_pgo_homepage = https://github.com/erleans/pgo.git pkg_pgo_fetch = git pkg_pgo_repo = https://github.com/erleans/pgo.git pkg_pgo_commit = master PACKAGES += pgsql pkg_pgsql_name = pgsql pkg_pgsql_description = Erlang PostgreSQL driver pkg_pgsql_homepage = https://github.com/semiocast/pgsql pkg_pgsql_fetch = git pkg_pgsql_repo = https://github.com/semiocast/pgsql pkg_pgsql_commit = master PACKAGES += pkgx pkg_pkgx_name = pkgx pkg_pkgx_description = Build .deb packages from Erlang releases pkg_pkgx_homepage = https://github.com/arjan/pkgx pkg_pkgx_fetch = git pkg_pkgx_repo = https://github.com/arjan/pkgx pkg_pkgx_commit = master PACKAGES += pkt pkg_pkt_name = pkt pkg_pkt_description = Erlang network protocol library pkg_pkt_homepage = https://github.com/msantos/pkt pkg_pkt_fetch = git pkg_pkt_repo = https://github.com/msantos/pkt pkg_pkt_commit = master PACKAGES += plain_fsm pkg_plain_fsm_name = plain_fsm pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm pkg_plain_fsm_fetch = git pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm pkg_plain_fsm_commit = master PACKAGES += plumtree pkg_plumtree_name = plumtree pkg_plumtree_description = Epidemic Broadcast Trees pkg_plumtree_homepage = https://github.com/helium/plumtree pkg_plumtree_fetch = git pkg_plumtree_repo = https://github.com/helium/plumtree pkg_plumtree_commit = master PACKAGES += pmod_transform pkg_pmod_transform_name = pmod_transform pkg_pmod_transform_description = Parse transform for parameterized modules pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform pkg_pmod_transform_fetch = git pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform pkg_pmod_transform_commit = master PACKAGES += pobox pkg_pobox_name = pobox pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang pkg_pobox_homepage = https://github.com/ferd/pobox pkg_pobox_fetch = git pkg_pobox_repo = https://github.com/ferd/pobox pkg_pobox_commit = master PACKAGES += ponos pkg_ponos_name = ponos pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang pkg_ponos_homepage = https://github.com/klarna/ponos pkg_ponos_fetch = git pkg_ponos_repo = https://github.com/klarna/ponos pkg_ponos_commit = master PACKAGES += poolboy pkg_poolboy_name = poolboy pkg_poolboy_description = A hunky Erlang worker pool factory pkg_poolboy_homepage = https://github.com/devinus/poolboy pkg_poolboy_fetch = git pkg_poolboy_repo = https://github.com/devinus/poolboy pkg_poolboy_commit = master PACKAGES += pooler pkg_pooler_name = pooler pkg_pooler_description = An OTP Process Pool Application pkg_pooler_homepage = https://github.com/seth/pooler pkg_pooler_fetch = git pkg_pooler_repo = https://github.com/seth/pooler pkg_pooler_commit = master PACKAGES += pqueue pkg_pqueue_name = pqueue pkg_pqueue_description = Erlang Priority Queues pkg_pqueue_homepage = https://github.com/okeuday/pqueue pkg_pqueue_fetch = git pkg_pqueue_repo = https://github.com/okeuday/pqueue pkg_pqueue_commit = master PACKAGES += procket pkg_procket_name = procket pkg_procket_description = Erlang interface to low level socket operations pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket pkg_procket_fetch = git pkg_procket_repo = https://github.com/msantos/procket pkg_procket_commit = master PACKAGES += prop pkg_prop_name = prop pkg_prop_description = An Erlang code scaffolding and generator system. pkg_prop_homepage = https://github.com/nuex/prop pkg_prop_fetch = git pkg_prop_repo = https://github.com/nuex/prop pkg_prop_commit = master PACKAGES += proper pkg_proper_name = proper pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. pkg_proper_homepage = http://proper.softlab.ntua.gr pkg_proper_fetch = git pkg_proper_repo = https://github.com/manopapad/proper pkg_proper_commit = master PACKAGES += props pkg_props_name = props pkg_props_description = Property structure library pkg_props_homepage = https://github.com/greyarea/props pkg_props_fetch = git pkg_props_repo = https://github.com/greyarea/props pkg_props_commit = master PACKAGES += protobuffs pkg_protobuffs_name = protobuffs pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs pkg_protobuffs_fetch = git pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs pkg_protobuffs_commit = master PACKAGES += psycho pkg_psycho_name = psycho pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. pkg_psycho_homepage = https://github.com/gar1t/psycho pkg_psycho_fetch = git pkg_psycho_repo = https://github.com/gar1t/psycho pkg_psycho_commit = master PACKAGES += purity pkg_purity_name = purity pkg_purity_description = A side-effect analyzer for Erlang pkg_purity_homepage = https://github.com/mpitid/purity pkg_purity_fetch = git pkg_purity_repo = https://github.com/mpitid/purity pkg_purity_commit = master PACKAGES += push_service pkg_push_service_name = push_service pkg_push_service_description = Push service pkg_push_service_homepage = https://github.com/hairyhum/push_service pkg_push_service_fetch = git pkg_push_service_repo = https://github.com/hairyhum/push_service pkg_push_service_commit = master PACKAGES += qdate pkg_qdate_name = qdate pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. pkg_qdate_homepage = https://github.com/choptastic/qdate pkg_qdate_fetch = git pkg_qdate_repo = https://github.com/choptastic/qdate pkg_qdate_commit = master PACKAGES += qrcode pkg_qrcode_name = qrcode pkg_qrcode_description = QR Code encoder in Erlang pkg_qrcode_homepage = https://github.com/komone/qrcode pkg_qrcode_fetch = git pkg_qrcode_repo = https://github.com/komone/qrcode pkg_qrcode_commit = master PACKAGES += quest pkg_quest_name = quest pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest pkg_quest_fetch = git pkg_quest_repo = https://github.com/eriksoe/ErlangQuest pkg_quest_commit = master PACKAGES += quickrand pkg_quickrand_name = quickrand pkg_quickrand_description = Quick Erlang Random Number Generation pkg_quickrand_homepage = https://github.com/okeuday/quickrand pkg_quickrand_fetch = git pkg_quickrand_repo = https://github.com/okeuday/quickrand pkg_quickrand_commit = master PACKAGES += rabbit pkg_rabbit_name = rabbit pkg_rabbit_description = RabbitMQ Server pkg_rabbit_homepage = https://www.rabbitmq.com/ pkg_rabbit_fetch = git pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git pkg_rabbit_commit = master PACKAGES += rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange pkg_rabbit_exchange_type_riak_fetch = git pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange pkg_rabbit_exchange_type_riak_commit = master PACKAGES += rack pkg_rack_name = rack pkg_rack_description = Rack handler for erlang pkg_rack_homepage = https://github.com/erlyvideo/rack pkg_rack_fetch = git pkg_rack_repo = https://github.com/erlyvideo/rack pkg_rack_commit = master PACKAGES += radierl pkg_radierl_name = radierl pkg_radierl_description = RADIUS protocol stack implemented in Erlang. pkg_radierl_homepage = https://github.com/vances/radierl pkg_radierl_fetch = git pkg_radierl_repo = https://github.com/vances/radierl pkg_radierl_commit = master PACKAGES += rafter pkg_rafter_name = rafter pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol pkg_rafter_homepage = https://github.com/andrewjstone/rafter pkg_rafter_fetch = git pkg_rafter_repo = https://github.com/andrewjstone/rafter pkg_rafter_commit = master PACKAGES += ranch pkg_ranch_name = ranch pkg_ranch_description = Socket acceptor pool for TCP protocols. pkg_ranch_homepage = http://ninenines.eu pkg_ranch_fetch = git pkg_ranch_repo = https://github.com/ninenines/ranch pkg_ranch_commit = 1.2.1 PACKAGES += rbeacon pkg_rbeacon_name = rbeacon pkg_rbeacon_description = LAN discovery and presence in Erlang. pkg_rbeacon_homepage = https://github.com/refuge/rbeacon pkg_rbeacon_fetch = git pkg_rbeacon_repo = https://github.com/refuge/rbeacon pkg_rbeacon_commit = master PACKAGES += rebar pkg_rebar_name = rebar pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. pkg_rebar_homepage = http://www.rebar3.org pkg_rebar_fetch = git pkg_rebar_repo = https://github.com/rebar/rebar3 pkg_rebar_commit = master PACKAGES += rebus pkg_rebus_name = rebus pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. pkg_rebus_homepage = https://github.com/olle/rebus pkg_rebus_fetch = git pkg_rebus_repo = https://github.com/olle/rebus pkg_rebus_commit = master PACKAGES += rec2json pkg_rec2json_name = rec2json pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. pkg_rec2json_homepage = https://github.com/lordnull/rec2json pkg_rec2json_fetch = git pkg_rec2json_repo = https://github.com/lordnull/rec2json pkg_rec2json_commit = master PACKAGES += recon pkg_recon_name = recon pkg_recon_description = Collection of functions and scripts to debug Erlang in production. pkg_recon_homepage = https://github.com/ferd/recon pkg_recon_fetch = git pkg_recon_repo = https://github.com/ferd/recon pkg_recon_commit = master PACKAGES += record_info pkg_record_info_name = record_info pkg_record_info_description = Convert between record and proplist pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info pkg_record_info_fetch = git pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info pkg_record_info_commit = master PACKAGES += redgrid pkg_redgrid_name = redgrid pkg_redgrid_description = automatic Erlang node discovery via redis pkg_redgrid_homepage = https://github.com/jkvor/redgrid pkg_redgrid_fetch = git pkg_redgrid_repo = https://github.com/jkvor/redgrid pkg_redgrid_commit = master PACKAGES += redo pkg_redo_name = redo pkg_redo_description = pipelined erlang redis client pkg_redo_homepage = https://github.com/jkvor/redo pkg_redo_fetch = git pkg_redo_repo = https://github.com/jkvor/redo pkg_redo_commit = master PACKAGES += reload_mk pkg_reload_mk_name = reload_mk pkg_reload_mk_description = Live reload plugin for erlang.mk. pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk pkg_reload_mk_fetch = git pkg_reload_mk_repo = https://github.com/bullno1/reload.mk pkg_reload_mk_commit = master PACKAGES += reltool_util pkg_reltool_util_name = reltool_util pkg_reltool_util_description = Erlang reltool utility functionality application pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util pkg_reltool_util_fetch = git pkg_reltool_util_repo = https://github.com/okeuday/reltool_util pkg_reltool_util_commit = master PACKAGES += relx pkg_relx_name = relx pkg_relx_description = Sane, simple release creation for Erlang pkg_relx_homepage = https://github.com/erlware/relx pkg_relx_fetch = git pkg_relx_repo = https://github.com/erlware/relx pkg_relx_commit = master PACKAGES += resource_discovery pkg_resource_discovery_name = resource_discovery pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. pkg_resource_discovery_homepage = http://erlware.org/ pkg_resource_discovery_fetch = git pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery pkg_resource_discovery_commit = master PACKAGES += restc pkg_restc_name = restc pkg_restc_description = Erlang Rest Client pkg_restc_homepage = https://github.com/kivra/restclient pkg_restc_fetch = git pkg_restc_repo = https://github.com/kivra/restclient pkg_restc_commit = master PACKAGES += rfc4627_jsonrpc pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 pkg_rfc4627_jsonrpc_fetch = git pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 pkg_rfc4627_jsonrpc_commit = master PACKAGES += riak_control pkg_riak_control_name = riak_control pkg_riak_control_description = Webmachine-based administration interface for Riak. pkg_riak_control_homepage = https://github.com/basho/riak_control pkg_riak_control_fetch = git pkg_riak_control_repo = https://github.com/basho/riak_control pkg_riak_control_commit = master PACKAGES += riak_core pkg_riak_core_name = riak_core pkg_riak_core_description = Distributed systems infrastructure used by Riak. pkg_riak_core_homepage = https://github.com/basho/riak_core pkg_riak_core_fetch = git pkg_riak_core_repo = https://github.com/basho/riak_core pkg_riak_core_commit = master PACKAGES += riak_dt pkg_riak_dt_name = riak_dt pkg_riak_dt_description = Convergent replicated datatypes in Erlang pkg_riak_dt_homepage = https://github.com/basho/riak_dt pkg_riak_dt_fetch = git pkg_riak_dt_repo = https://github.com/basho/riak_dt pkg_riak_dt_commit = master PACKAGES += riak_ensemble pkg_riak_ensemble_name = riak_ensemble pkg_riak_ensemble_description = Multi-Paxos framework in Erlang pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble pkg_riak_ensemble_fetch = git pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble pkg_riak_ensemble_commit = master PACKAGES += riak_kv pkg_riak_kv_name = riak_kv pkg_riak_kv_description = Riak Key/Value Store pkg_riak_kv_homepage = https://github.com/basho/riak_kv pkg_riak_kv_fetch = git pkg_riak_kv_repo = https://github.com/basho/riak_kv pkg_riak_kv_commit = master PACKAGES += riak_pg pkg_riak_pg_name = riak_pg pkg_riak_pg_description = Distributed process groups with riak_core. pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg pkg_riak_pg_fetch = git pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg pkg_riak_pg_commit = master PACKAGES += riak_pipe pkg_riak_pipe_name = riak_pipe pkg_riak_pipe_description = Riak Pipelines pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe pkg_riak_pipe_fetch = git pkg_riak_pipe_repo = https://github.com/basho/riak_pipe pkg_riak_pipe_commit = master PACKAGES += riak_sysmon pkg_riak_sysmon_name = riak_sysmon pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon pkg_riak_sysmon_fetch = git pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon pkg_riak_sysmon_commit = master PACKAGES += riak_test pkg_riak_test_name = riak_test pkg_riak_test_description = I'm in your cluster, testing your riaks pkg_riak_test_homepage = https://github.com/basho/riak_test pkg_riak_test_fetch = git pkg_riak_test_repo = https://github.com/basho/riak_test pkg_riak_test_commit = master PACKAGES += riakc pkg_riakc_name = riakc pkg_riakc_description = Erlang clients for Riak. pkg_riakc_homepage = https://github.com/basho/riak-erlang-client pkg_riakc_fetch = git pkg_riakc_repo = https://github.com/basho/riak-erlang-client pkg_riakc_commit = master PACKAGES += riakhttpc pkg_riakhttpc_name = riakhttpc pkg_riakhttpc_description = Riak Erlang client using the HTTP interface pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client pkg_riakhttpc_fetch = git pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client pkg_riakhttpc_commit = master PACKAGES += riaknostic pkg_riaknostic_name = riaknostic pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap pkg_riaknostic_homepage = https://github.com/basho/riaknostic pkg_riaknostic_fetch = git pkg_riaknostic_repo = https://github.com/basho/riaknostic pkg_riaknostic_commit = master PACKAGES += riakpool pkg_riakpool_name = riakpool pkg_riakpool_description = erlang riak client pool pkg_riakpool_homepage = https://github.com/dweldon/riakpool pkg_riakpool_fetch = git pkg_riakpool_repo = https://github.com/dweldon/riakpool pkg_riakpool_commit = master PACKAGES += rivus_cep pkg_rivus_cep_name = rivus_cep pkg_rivus_cep_description = Complex event processing in Erlang pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep pkg_rivus_cep_fetch = git pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep pkg_rivus_cep_commit = master PACKAGES += rlimit pkg_rlimit_name = rlimit pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent pkg_rlimit_homepage = https://github.com/jlouis/rlimit pkg_rlimit_fetch = git pkg_rlimit_repo = https://github.com/jlouis/rlimit pkg_rlimit_commit = master PACKAGES += rust_mk pkg_rust_mk_name = rust_mk pkg_rust_mk_description = Build Rust crates in an Erlang application pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk pkg_rust_mk_fetch = git pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk pkg_rust_mk_commit = master PACKAGES += safetyvalve pkg_safetyvalve_name = safetyvalve pkg_safetyvalve_description = A safety valve for your erlang node pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve pkg_safetyvalve_fetch = git pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve pkg_safetyvalve_commit = master PACKAGES += seestar pkg_seestar_name = seestar pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol pkg_seestar_homepage = https://github.com/iamaleksey/seestar pkg_seestar_fetch = git pkg_seestar_repo = https://github.com/iamaleksey/seestar pkg_seestar_commit = master PACKAGES += service pkg_service_name = service pkg_service_description = A minimal Erlang behavior for creating CloudI internal services pkg_service_homepage = http://cloudi.org/ pkg_service_fetch = git pkg_service_repo = https://github.com/CloudI/service pkg_service_commit = master PACKAGES += setup pkg_setup_name = setup pkg_setup_description = Generic setup utility for Erlang-based systems pkg_setup_homepage = https://github.com/uwiger/setup pkg_setup_fetch = git pkg_setup_repo = https://github.com/uwiger/setup pkg_setup_commit = master PACKAGES += sext pkg_sext_name = sext pkg_sext_description = Sortable Erlang Term Serialization pkg_sext_homepage = https://github.com/uwiger/sext pkg_sext_fetch = git pkg_sext_repo = https://github.com/uwiger/sext pkg_sext_commit = master PACKAGES += sfmt pkg_sfmt_name = sfmt pkg_sfmt_description = SFMT pseudo random number generator for Erlang. pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang pkg_sfmt_fetch = git pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang pkg_sfmt_commit = master PACKAGES += sgte pkg_sgte_name = sgte pkg_sgte_description = A simple Erlang Template Engine pkg_sgte_homepage = https://github.com/filippo/sgte pkg_sgte_fetch = git pkg_sgte_repo = https://github.com/filippo/sgte pkg_sgte_commit = master PACKAGES += sheriff pkg_sheriff_name = sheriff pkg_sheriff_description = Parse transform for type based validation. pkg_sheriff_homepage = http://ninenines.eu pkg_sheriff_fetch = git pkg_sheriff_repo = https://github.com/extend/sheriff pkg_sheriff_commit = master PACKAGES += shotgun pkg_shotgun_name = shotgun pkg_shotgun_description = better than just a gun pkg_shotgun_homepage = https://github.com/inaka/shotgun pkg_shotgun_fetch = git pkg_shotgun_repo = https://github.com/inaka/shotgun pkg_shotgun_commit = master PACKAGES += sidejob pkg_sidejob_name = sidejob pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang pkg_sidejob_homepage = https://github.com/basho/sidejob pkg_sidejob_fetch = git pkg_sidejob_repo = https://github.com/basho/sidejob pkg_sidejob_commit = master PACKAGES += sieve pkg_sieve_name = sieve pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang pkg_sieve_homepage = https://github.com/benoitc/sieve pkg_sieve_fetch = git pkg_sieve_repo = https://github.com/benoitc/sieve pkg_sieve_commit = master PACKAGES += sighandler pkg_sighandler_name = sighandler pkg_sighandler_description = Handle UNIX signals in Er lang pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler pkg_sighandler_fetch = git pkg_sighandler_repo = https://github.com/jkingsbery/sighandler pkg_sighandler_commit = master PACKAGES += simhash pkg_simhash_name = simhash pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. pkg_simhash_homepage = https://github.com/ferd/simhash pkg_simhash_fetch = git pkg_simhash_repo = https://github.com/ferd/simhash pkg_simhash_commit = master PACKAGES += simple_bridge pkg_simple_bridge_name = simple_bridge pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge pkg_simple_bridge_fetch = git pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge pkg_simple_bridge_commit = master PACKAGES += simple_oauth2 pkg_simple_oauth2_name = simple_oauth2 pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 pkg_simple_oauth2_fetch = git pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 pkg_simple_oauth2_commit = master PACKAGES += skel pkg_skel_name = skel pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang pkg_skel_homepage = https://github.com/ParaPhrase/skel pkg_skel_fetch = git pkg_skel_repo = https://github.com/ParaPhrase/skel pkg_skel_commit = master PACKAGES += slack pkg_slack_name = slack pkg_slack_description = Minimal slack notification OTP library. pkg_slack_homepage = https://github.com/DonBranson/slack pkg_slack_fetch = git pkg_slack_repo = https://github.com/DonBranson/slack.git pkg_slack_commit = master PACKAGES += smother pkg_smother_name = smother pkg_smother_description = Extended code coverage metrics for Erlang. pkg_smother_homepage = https://ramsay-t.github.io/Smother/ pkg_smother_fetch = git pkg_smother_repo = https://github.com/ramsay-t/Smother pkg_smother_commit = master PACKAGES += snappyer pkg_snappyer_name = snappyer pkg_snappyer_description = Snappy as nif for Erlang pkg_snappyer_homepage = https://github.com/zmstone/snappyer pkg_snappyer_fetch = git pkg_snappyer_repo = https://github.com/zmstone/snappyer.git pkg_snappyer_commit = master PACKAGES += social pkg_social_name = social pkg_social_description = Cowboy handler for social login via OAuth2 providers pkg_social_homepage = https://github.com/dvv/social pkg_social_fetch = git pkg_social_repo = https://github.com/dvv/social pkg_social_commit = master PACKAGES += spapi_router pkg_spapi_router_name = spapi_router pkg_spapi_router_description = Partially-connected Erlang clustering pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router pkg_spapi_router_fetch = git pkg_spapi_router_repo = https://github.com/spilgames/spapi-router pkg_spapi_router_commit = master PACKAGES += sqerl pkg_sqerl_name = sqerl pkg_sqerl_description = An Erlang-flavoured SQL DSL pkg_sqerl_homepage = https://github.com/hairyhum/sqerl pkg_sqerl_fetch = git pkg_sqerl_repo = https://github.com/hairyhum/sqerl pkg_sqerl_commit = master PACKAGES += srly pkg_srly_name = srly pkg_srly_description = Native Erlang Unix serial interface pkg_srly_homepage = https://github.com/msantos/srly pkg_srly_fetch = git pkg_srly_repo = https://github.com/msantos/srly pkg_srly_commit = master PACKAGES += sshrpc pkg_sshrpc_name = sshrpc pkg_sshrpc_description = Erlang SSH RPC module (experimental) pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc pkg_sshrpc_fetch = git pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc pkg_sshrpc_commit = master PACKAGES += stable pkg_stable_name = stable pkg_stable_description = Library of assorted helpers for Cowboy web server. pkg_stable_homepage = https://github.com/dvv/stable pkg_stable_fetch = git pkg_stable_repo = https://github.com/dvv/stable pkg_stable_commit = master PACKAGES += statebox pkg_statebox_name = statebox pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. pkg_statebox_homepage = https://github.com/mochi/statebox pkg_statebox_fetch = git pkg_statebox_repo = https://github.com/mochi/statebox pkg_statebox_commit = master PACKAGES += statebox_riak pkg_statebox_riak_name = statebox_riak pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak pkg_statebox_riak_fetch = git pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak pkg_statebox_riak_commit = master PACKAGES += statman pkg_statman_name = statman pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM pkg_statman_homepage = https://github.com/knutin/statman pkg_statman_fetch = git pkg_statman_repo = https://github.com/knutin/statman pkg_statman_commit = master PACKAGES += statsderl pkg_statsderl_name = statsderl pkg_statsderl_description = StatsD client (erlang) pkg_statsderl_homepage = https://github.com/lpgauth/statsderl pkg_statsderl_fetch = git pkg_statsderl_repo = https://github.com/lpgauth/statsderl pkg_statsderl_commit = master PACKAGES += stdinout_pool pkg_stdinout_pool_name = stdinout_pool pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool pkg_stdinout_pool_fetch = git pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool pkg_stdinout_pool_commit = master PACKAGES += stockdb pkg_stockdb_name = stockdb pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb pkg_stockdb_fetch = git pkg_stockdb_repo = https://github.com/maxlapshin/stockdb pkg_stockdb_commit = master PACKAGES += stripe pkg_stripe_name = stripe pkg_stripe_description = Erlang interface to the stripe.com API pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang pkg_stripe_fetch = git pkg_stripe_repo = https://github.com/mattsta/stripe-erlang pkg_stripe_commit = v1 PACKAGES += subproc pkg_subproc_name = subproc pkg_subproc_description = unix subprocess manager with {active,once|false} modes pkg_subproc_homepage = http://dozzie.jarowit.net/trac/wiki/subproc pkg_subproc_fetch = git pkg_subproc_repo = https://github.com/dozzie/subproc pkg_subproc_commit = v0.1.0 PACKAGES += supervisor3 pkg_supervisor3_name = supervisor3 pkg_supervisor3_description = OTP supervisor with additional strategies pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 pkg_supervisor3_fetch = git pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git pkg_supervisor3_commit = master PACKAGES += surrogate pkg_surrogate_name = surrogate pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. pkg_surrogate_homepage = https://github.com/skruger/Surrogate pkg_surrogate_fetch = git pkg_surrogate_repo = https://github.com/skruger/Surrogate pkg_surrogate_commit = master PACKAGES += swab pkg_swab_name = swab pkg_swab_description = General purpose buffer handling module pkg_swab_homepage = https://github.com/crownedgrouse/swab pkg_swab_fetch = git pkg_swab_repo = https://github.com/crownedgrouse/swab pkg_swab_commit = master PACKAGES += swarm pkg_swarm_name = swarm pkg_swarm_description = Fast and simple acceptor pool for Erlang pkg_swarm_homepage = https://github.com/jeremey/swarm pkg_swarm_fetch = git pkg_swarm_repo = https://github.com/jeremey/swarm pkg_swarm_commit = master PACKAGES += switchboard pkg_switchboard_name = switchboard pkg_switchboard_description = A framework for processing email using worker plugins. pkg_switchboard_homepage = https://github.com/thusfresh/switchboard pkg_switchboard_fetch = git pkg_switchboard_repo = https://github.com/thusfresh/switchboard pkg_switchboard_commit = master PACKAGES += syn pkg_syn_name = syn pkg_syn_description = A global Process Registry and Process Group manager for Erlang. pkg_syn_homepage = https://github.com/ostinelli/syn pkg_syn_fetch = git pkg_syn_repo = https://github.com/ostinelli/syn pkg_syn_commit = master PACKAGES += sync pkg_sync_name = sync pkg_sync_description = On-the-fly recompiling and reloading in Erlang. pkg_sync_homepage = https://github.com/rustyio/sync pkg_sync_fetch = git pkg_sync_repo = https://github.com/rustyio/sync pkg_sync_commit = master PACKAGES += syntaxerl pkg_syntaxerl_name = syntaxerl pkg_syntaxerl_description = Syntax checker for Erlang pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl pkg_syntaxerl_fetch = git pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl pkg_syntaxerl_commit = master PACKAGES += syslog pkg_syslog_name = syslog pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog pkg_syslog_fetch = git pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog pkg_syslog_commit = master PACKAGES += taskforce pkg_taskforce_name = taskforce pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. pkg_taskforce_homepage = https://github.com/g-andrade/taskforce pkg_taskforce_fetch = git pkg_taskforce_repo = https://github.com/g-andrade/taskforce pkg_taskforce_commit = master PACKAGES += tddreloader pkg_tddreloader_name = tddreloader pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader pkg_tddreloader_fetch = git pkg_tddreloader_repo = https://github.com/version2beta/tddreloader pkg_tddreloader_commit = master PACKAGES += tempo pkg_tempo_name = tempo pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. pkg_tempo_homepage = https://github.com/selectel/tempo pkg_tempo_fetch = git pkg_tempo_repo = https://github.com/selectel/tempo pkg_tempo_commit = master PACKAGES += ticktick pkg_ticktick_name = ticktick pkg_ticktick_description = Ticktick is an id generator for message service. pkg_ticktick_homepage = https://github.com/ericliang/ticktick pkg_ticktick_fetch = git pkg_ticktick_repo = https://github.com/ericliang/ticktick pkg_ticktick_commit = master PACKAGES += tinymq pkg_tinymq_name = tinymq pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq pkg_tinymq_fetch = git pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq pkg_tinymq_commit = master PACKAGES += tinymt pkg_tinymt_name = tinymt pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang pkg_tinymt_fetch = git pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang pkg_tinymt_commit = master PACKAGES += tirerl pkg_tirerl_name = tirerl pkg_tirerl_description = Erlang interface to Elastic Search pkg_tirerl_homepage = https://github.com/inaka/tirerl pkg_tirerl_fetch = git pkg_tirerl_repo = https://github.com/inaka/tirerl pkg_tirerl_commit = master PACKAGES += toml pkg_toml_name = toml pkg_toml_description = TOML (0.4.0) config parser pkg_toml_homepage = http://dozzie.jarowit.net/trac/wiki/TOML pkg_toml_fetch = git pkg_toml_repo = https://github.com/dozzie/toml pkg_toml_commit = v0.2.0 PACKAGES += traffic_tools pkg_traffic_tools_name = traffic_tools pkg_traffic_tools_description = Simple traffic limiting library pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools pkg_traffic_tools_fetch = git pkg_traffic_tools_repo = https://github.com/systra/traffic_tools pkg_traffic_tools_commit = master PACKAGES += trails pkg_trails_name = trails pkg_trails_description = A couple of improvements over Cowboy Routes pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ pkg_trails_fetch = git pkg_trails_repo = https://github.com/inaka/cowboy-trails pkg_trails_commit = master PACKAGES += trane pkg_trane_name = trane pkg_trane_description = SAX style broken HTML parser in Erlang pkg_trane_homepage = https://github.com/massemanet/trane pkg_trane_fetch = git pkg_trane_repo = https://github.com/massemanet/trane pkg_trane_commit = master PACKAGES += transit pkg_transit_name = transit pkg_transit_description = transit format for erlang pkg_transit_homepage = https://github.com/isaiah/transit-erlang pkg_transit_fetch = git pkg_transit_repo = https://github.com/isaiah/transit-erlang pkg_transit_commit = master PACKAGES += trie pkg_trie_name = trie pkg_trie_description = Erlang Trie Implementation pkg_trie_homepage = https://github.com/okeuday/trie pkg_trie_fetch = git pkg_trie_repo = https://github.com/okeuday/trie pkg_trie_commit = master PACKAGES += triq pkg_triq_name = triq pkg_triq_description = Trifork QuickCheck pkg_triq_homepage = https://triq.gitlab.io pkg_triq_fetch = git pkg_triq_repo = https://gitlab.com/triq/triq.git pkg_triq_commit = master PACKAGES += tunctl pkg_tunctl_name = tunctl pkg_tunctl_description = Erlang TUN/TAP interface pkg_tunctl_homepage = https://github.com/msantos/tunctl pkg_tunctl_fetch = git pkg_tunctl_repo = https://github.com/msantos/tunctl pkg_tunctl_commit = master PACKAGES += twerl pkg_twerl_name = twerl pkg_twerl_description = Erlang client for the Twitter Streaming API pkg_twerl_homepage = https://github.com/lucaspiller/twerl pkg_twerl_fetch = git pkg_twerl_repo = https://github.com/lucaspiller/twerl pkg_twerl_commit = oauth PACKAGES += twitter_erlang pkg_twitter_erlang_name = twitter_erlang pkg_twitter_erlang_description = An Erlang twitter client pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter pkg_twitter_erlang_fetch = git pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter pkg_twitter_erlang_commit = master PACKAGES += ucol_nif pkg_ucol_nif_name = ucol_nif pkg_ucol_nif_description = ICU based collation Erlang module pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif pkg_ucol_nif_fetch = git pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif pkg_ucol_nif_commit = master PACKAGES += unicorn pkg_unicorn_name = unicorn pkg_unicorn_description = Generic configuration server pkg_unicorn_homepage = https://github.com/shizzard/unicorn pkg_unicorn_fetch = git pkg_unicorn_repo = https://github.com/shizzard/unicorn pkg_unicorn_commit = master PACKAGES += unsplit pkg_unsplit_name = unsplit pkg_unsplit_description = Resolves conflicts in Mnesia after network splits pkg_unsplit_homepage = https://github.com/uwiger/unsplit pkg_unsplit_fetch = git pkg_unsplit_repo = https://github.com/uwiger/unsplit pkg_unsplit_commit = master PACKAGES += uuid pkg_uuid_name = uuid pkg_uuid_description = Erlang UUID Implementation pkg_uuid_homepage = https://github.com/okeuday/uuid pkg_uuid_fetch = git pkg_uuid_repo = https://github.com/okeuday/uuid pkg_uuid_commit = master PACKAGES += ux pkg_ux_name = ux pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) pkg_ux_homepage = https://github.com/erlang-unicode/ux pkg_ux_fetch = git pkg_ux_repo = https://github.com/erlang-unicode/ux pkg_ux_commit = master PACKAGES += vert pkg_vert_name = vert pkg_vert_description = Erlang binding to libvirt virtualization API pkg_vert_homepage = https://github.com/msantos/erlang-libvirt pkg_vert_fetch = git pkg_vert_repo = https://github.com/msantos/erlang-libvirt pkg_vert_commit = master PACKAGES += verx pkg_verx_name = verx pkg_verx_description = Erlang implementation of the libvirtd remote protocol pkg_verx_homepage = https://github.com/msantos/verx pkg_verx_fetch = git pkg_verx_repo = https://github.com/msantos/verx pkg_verx_commit = master PACKAGES += vmq_acl pkg_vmq_acl_name = vmq_acl pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker pkg_vmq_acl_homepage = https://verne.mq/ pkg_vmq_acl_fetch = git pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl pkg_vmq_acl_commit = master PACKAGES += vmq_bridge pkg_vmq_bridge_name = vmq_bridge pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker pkg_vmq_bridge_homepage = https://verne.mq/ pkg_vmq_bridge_fetch = git pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge pkg_vmq_bridge_commit = master PACKAGES += vmq_graphite pkg_vmq_graphite_name = vmq_graphite pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker pkg_vmq_graphite_homepage = https://verne.mq/ pkg_vmq_graphite_fetch = git pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite pkg_vmq_graphite_commit = master PACKAGES += vmq_passwd pkg_vmq_passwd_name = vmq_passwd pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker pkg_vmq_passwd_homepage = https://verne.mq/ pkg_vmq_passwd_fetch = git pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd pkg_vmq_passwd_commit = master PACKAGES += vmq_server pkg_vmq_server_name = vmq_server pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker pkg_vmq_server_homepage = https://verne.mq/ pkg_vmq_server_fetch = git pkg_vmq_server_repo = https://github.com/erlio/vmq_server pkg_vmq_server_commit = master PACKAGES += vmq_snmp pkg_vmq_snmp_name = vmq_snmp pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker pkg_vmq_snmp_homepage = https://verne.mq/ pkg_vmq_snmp_fetch = git pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp pkg_vmq_snmp_commit = master PACKAGES += vmq_systree pkg_vmq_systree_name = vmq_systree pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker pkg_vmq_systree_homepage = https://verne.mq/ pkg_vmq_systree_fetch = git pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree pkg_vmq_systree_commit = master PACKAGES += vmstats pkg_vmstats_name = vmstats pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. pkg_vmstats_homepage = https://github.com/ferd/vmstats pkg_vmstats_fetch = git pkg_vmstats_repo = https://github.com/ferd/vmstats pkg_vmstats_commit = master PACKAGES += walrus pkg_walrus_name = walrus pkg_walrus_description = Walrus - Mustache-like Templating pkg_walrus_homepage = https://github.com/devinus/walrus pkg_walrus_fetch = git pkg_walrus_repo = https://github.com/devinus/walrus pkg_walrus_commit = master PACKAGES += webmachine pkg_webmachine_name = webmachine pkg_webmachine_description = A REST-based system for building web applications. pkg_webmachine_homepage = https://github.com/basho/webmachine pkg_webmachine_fetch = git pkg_webmachine_repo = https://github.com/basho/webmachine pkg_webmachine_commit = master PACKAGES += websocket_client pkg_websocket_client_name = websocket_client pkg_websocket_client_description = Erlang websocket client (ws and wss supported) pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client pkg_websocket_client_fetch = git pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client pkg_websocket_client_commit = master PACKAGES += worker_pool pkg_worker_pool_name = worker_pool pkg_worker_pool_description = a simple erlang worker pool pkg_worker_pool_homepage = https://github.com/inaka/worker_pool pkg_worker_pool_fetch = git pkg_worker_pool_repo = https://github.com/inaka/worker_pool pkg_worker_pool_commit = master PACKAGES += wrangler pkg_wrangler_name = wrangler pkg_wrangler_description = Import of the Wrangler svn repository. pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html pkg_wrangler_fetch = git pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler pkg_wrangler_commit = master PACKAGES += wsock pkg_wsock_name = wsock pkg_wsock_description = Erlang library to build WebSocket clients and servers pkg_wsock_homepage = https://github.com/madtrick/wsock pkg_wsock_fetch = git pkg_wsock_repo = https://github.com/madtrick/wsock pkg_wsock_commit = master PACKAGES += xhttpc pkg_xhttpc_name = xhttpc pkg_xhttpc_description = Extensible HTTP Client for Erlang pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc pkg_xhttpc_fetch = git pkg_xhttpc_repo = https://github.com/seriyps/xhttpc pkg_xhttpc_commit = master PACKAGES += xref_runner pkg_xref_runner_name = xref_runner pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) pkg_xref_runner_homepage = https://github.com/inaka/xref_runner pkg_xref_runner_fetch = git pkg_xref_runner_repo = https://github.com/inaka/xref_runner pkg_xref_runner_commit = master PACKAGES += yamerl pkg_yamerl_name = yamerl pkg_yamerl_description = YAML 1.2 parser in pure Erlang pkg_yamerl_homepage = https://github.com/yakaz/yamerl pkg_yamerl_fetch = git pkg_yamerl_repo = https://github.com/yakaz/yamerl pkg_yamerl_commit = master PACKAGES += yamler pkg_yamler_name = yamler pkg_yamler_description = libyaml-based yaml loader for Erlang pkg_yamler_homepage = https://github.com/goertzenator/yamler pkg_yamler_fetch = git pkg_yamler_repo = https://github.com/goertzenator/yamler pkg_yamler_commit = master PACKAGES += yaws pkg_yaws_name = yaws pkg_yaws_description = Yaws webserver pkg_yaws_homepage = http://yaws.hyber.org pkg_yaws_fetch = git pkg_yaws_repo = https://github.com/klacke/yaws pkg_yaws_commit = master PACKAGES += zab_engine pkg_zab_engine_name = zab_engine pkg_zab_engine_description = zab propotocol implement by erlang pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine pkg_zab_engine_fetch = git pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine pkg_zab_engine_commit = master PACKAGES += zabbix_sender pkg_zabbix_sender_name = zabbix_sender pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender pkg_zabbix_sender_fetch = git pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git pkg_zabbix_sender_commit = master PACKAGES += zeta pkg_zeta_name = zeta pkg_zeta_description = HTTP access log parser in Erlang pkg_zeta_homepage = https://github.com/s1n4/zeta pkg_zeta_fetch = git pkg_zeta_repo = https://github.com/s1n4/zeta pkg_zeta_commit = master PACKAGES += zippers pkg_zippers_name = zippers pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers pkg_zippers_homepage = https://github.com/ferd/zippers pkg_zippers_fetch = git pkg_zippers_repo = https://github.com/ferd/zippers pkg_zippers_commit = master PACKAGES += zlists pkg_zlists_name = zlists pkg_zlists_description = Erlang lazy lists library. pkg_zlists_homepage = https://github.com/vjache/erlang-zlists pkg_zlists_fetch = git pkg_zlists_repo = https://github.com/vjache/erlang-zlists pkg_zlists_commit = master PACKAGES += zraft_lib pkg_zraft_lib_name = zraft_lib pkg_zraft_lib_description = Erlang raft consensus protocol implementation pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib pkg_zraft_lib_fetch = git pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib pkg_zraft_lib_commit = master PACKAGES += zucchini pkg_zucchini_name = zucchini pkg_zucchini_description = An Erlang INI parser pkg_zucchini_homepage = https://github.com/devinus/zucchini pkg_zucchini_fetch = git pkg_zucchini_repo = https://github.com/devinus/zucchini pkg_zucchini_commit = master # Copyright (c) 2015-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: search define pkg_print $(verbose) printf "%s\n" \ $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ "App name: $(pkg_$(1)_name)" \ "Description: $(pkg_$(1)_description)" \ "Home page: $(pkg_$(1)_homepage)" \ "Fetch with: $(pkg_$(1)_fetch)" \ "Repository: $(pkg_$(1)_repo)" \ "Commit: $(pkg_$(1)_commit)" \ "" endef search: ifdef q $(foreach p,$(PACKAGES), \ $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ $(call pkg_print,$(p)))) else $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) endif # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-deps clean-tmp-deps.log # Configuration. ifdef OTP_DEPS $(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) endif IGNORE_DEPS ?= export IGNORE_DEPS APPS_DIR ?= $(CURDIR)/apps export APPS_DIR DEPS_DIR ?= $(CURDIR)/deps export DEPS_DIR REBAR_DEPS_DIR = $(DEPS_DIR) export REBAR_DEPS_DIR REBAR_GIT ?= https://github.com/rebar/rebar REBAR_COMMIT ?= 576e12171ab8d69b048b827b92aa65d067deea01 # External "early" plugins (see core/plugins.mk for regular plugins). # They both use the core_dep_plugin macro. define core_dep_plugin ifeq ($(2),$(PROJECT)) -include $$(patsubst $(PROJECT)/%,%,$(1)) else -include $(DEPS_DIR)/$(1) $(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; endif endef DEP_EARLY_PLUGINS ?= $(foreach p,$(DEP_EARLY_PLUGINS),\ $(eval $(if $(findstring /,$p),\ $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ $(call core_dep_plugin,$p/early-plugins.mk,$p)))) dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(if $(filter hex,$(word 1,$(dep_$(1)))),$(word 2,$(dep_$(1))),$(word 3,$(dep_$(1)))),$(pkg_$(1)_commit))) LOCAL_DEPS_DIRS = $(foreach a,$(LOCAL_DEPS),$(if $(wildcard $(APPS_DIR)/$(a)),$(APPS_DIR)/$(a))) ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) # When we are calling an app directly we don't want to include it here # otherwise it'll be treated both as an apps and a top-level project. ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) ifdef ROOT_DIR ifndef IS_APP ALL_APPS_DIRS := $(filter-out $(APPS_DIR)/$(notdir $(CURDIR)),$(ALL_APPS_DIRS)) endif endif ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) ifeq ($(ERL_LIBS),) ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) else ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) endif endif export ERL_LIBS export NO_AUTOPATCH # Verbosity. dep_verbose_0 = @echo " DEP $1 ($(call dep_commit,$1))"; dep_verbose_2 = set -x; dep_verbose = $(dep_verbose_$(V)) # Optimization: don't recompile deps unless truly necessary. ifndef IS_DEP ifneq ($(MAKELEVEL),0) $(shell rm -f ebin/dep_built) endif endif # Core targets. ALL_APPS_DIRS_TO_BUILD = $(if $(LOCAL_DEPS_DIRS)$(IS_APP),$(LOCAL_DEPS_DIRS),$(ALL_APPS_DIRS)) apps:: $(ALL_APPS_DIRS) clean-tmp-deps.log | $(ERLANG_MK_TMP) # Create ebin directory for all apps to make sure Erlang recognizes them # as proper OTP applications when using -include_lib. This is a temporary # fix, a proper fix would be to compile apps/* in the right order. ifndef IS_APP ifneq ($(ALL_APPS_DIRS),) $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ mkdir -p $$dep/ebin; \ done endif endif # At the toplevel: if LOCAL_DEPS is defined with at least one local app, only # compile that list of apps. Otherwise, compile everything. # Within an app: compile all LOCAL_DEPS that are (uncompiled) local apps. ifneq ($(ALL_APPS_DIRS_TO_BUILD),) $(verbose) set -e; for dep in $(ALL_APPS_DIRS_TO_BUILD); do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ $(MAKE) -C $$dep $(if $(IS_TEST),test-build-app) IS_APP=1; \ fi \ done endif clean-tmp-deps.log: ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log $(ERLANG_MK_TMP)/deps.log endif # Erlang.mk does not rebuild dependencies after they were compiled # once. If a developer is working on the top-level project and some # dependencies at the same time, he may want to change this behavior. # There are two solutions: # 1. Set `FULL=1` so that all dependencies are visited and # recursively recompiled if necessary. # 2. Set `FORCE_REBUILD=` to the specific list of dependencies that # should be recompiled (instead of the whole set). FORCE_REBUILD ?= ifeq ($(origin FULL),undefined) ifneq ($(strip $(force_rebuild_dep)$(FORCE_REBUILD)),) define force_rebuild_dep echo "$(FORCE_REBUILD)" | grep -qw "$$(basename "$1")" endef endif endif ifneq ($(SKIP_DEPS),) deps:: else deps:: $(ALL_DEPS_DIRS) apps clean-tmp-deps.log | $(ERLANG_MK_TMP) ifneq ($(ALL_DEPS_DIRS),) $(verbose) set -e; for dep in $(ALL_DEPS_DIRS); do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ if [ -z "$(strip $(FULL))" ] $(if $(force_rebuild_dep),&& ! ($(call force_rebuild_dep,$$dep)),) && [ ! -L $$dep ] && [ -f $$dep/ebin/dep_built ]; then \ :; \ elif [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ $(MAKE) -C $$dep IS_DEP=1; \ if [ ! -L $$dep ] && [ -d $$dep/ebin ]; then touch $$dep/ebin/dep_built; fi; \ else \ echo "Error: No Makefile to build dependency $$dep." >&2; \ exit 2; \ fi \ fi \ done endif endif # Deps related targets. # @todo rename GNUmakefile and makefile into Makefile first, if they exist # While Makefile file could be GNUmakefile or makefile, # in practice only Makefile is needed so far. define dep_autopatch if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ rm -rf $(DEPS_DIR)/$1/ebin/; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ $(call dep_autopatch_erlang_mk,$(1)); \ elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ if [ -f $(DEPS_DIR)/$1/rebar.lock ]; then \ $(call dep_autopatch2,$1); \ elif [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ elif [ 0 != `grep -ci "^[^#].*rebar" $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i "^[^#].*rebar" '{}' \;`" ]; then \ $(call dep_autopatch2,$(1)); \ fi \ else \ if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ $(call dep_autopatch_noop,$(1)); \ else \ $(call dep_autopatch2,$(1)); \ fi \ fi endef define dep_autopatch2 ! test -f $(DEPS_DIR)/$1/ebin/$1.app || \ mv -n $(DEPS_DIR)/$1/ebin/$1.app $(DEPS_DIR)/$1/src/$1.app.src; \ rm -f $(DEPS_DIR)/$1/ebin/$1.app; \ if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ fi; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script -o -f $(DEPS_DIR)/$1/rebar.lock ]; then \ $(call dep_autopatch_fetch_rebar); \ $(call dep_autopatch_rebar,$(1)); \ else \ $(call dep_autopatch_gen,$(1)); \ fi endef define dep_autopatch_noop printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile endef # Replace "include erlang.mk" with a line that will load the parent Erlang.mk # if given. Do it for all 3 possible Makefile file names. ifeq ($(NO_AUTOPATCH_ERLANG_MK),) define dep_autopatch_erlang_mk for f in Makefile makefile GNUmakefile; do \ if [ -f $(DEPS_DIR)/$1/$$f ]; then \ sed -i.bak s/'include *erlang.mk'/'include $$(if $$(ERLANG_MK_FILENAME),$$(ERLANG_MK_FILENAME),erlang.mk)'/ $(DEPS_DIR)/$1/$$f; \ fi \ done endef else define dep_autopatch_erlang_mk : endef endif define dep_autopatch_gen printf "%s\n" \ "ERLC_OPTS = +debug_info" \ "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile endef # We use flock/lockf when available to avoid concurrency issues. define dep_autopatch_fetch_rebar if command -v flock >/dev/null; then \ flock $(ERLANG_MK_TMP)/rebar.lock sh -c "$(call dep_autopatch_fetch_rebar2)"; \ elif command -v lockf >/dev/null; then \ lockf $(ERLANG_MK_TMP)/rebar.lock sh -c "$(call dep_autopatch_fetch_rebar2)"; \ else \ $(call dep_autopatch_fetch_rebar2); \ fi endef define dep_autopatch_fetch_rebar2 if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ git clone -q -n -- $(REBAR_GIT) $(ERLANG_MK_TMP)/rebar; \ cd $(ERLANG_MK_TMP)/rebar; \ git checkout -q $(REBAR_COMMIT); \ ./bootstrap; \ cd -; \ fi endef define dep_autopatch_rebar if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ fi; \ $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app endef define dep_autopatch_rebar.erl application:load(rebar), application:set_env(rebar, log_level, debug), rmemo:start(), Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of {ok, Conf0} -> Conf0; _ -> [] end, {Conf, OsEnv} = fun() -> case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of false -> {Conf1, []}; true -> Bindings0 = erl_eval:new_bindings(), Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), Before = os:getenv(), {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} end end(), Write = fun (Text) -> file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) end, Escape = fun (Text) -> re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) end, Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), Write("C_SRC_DIR = /path/do/not/exist\n"), Write("C_SRC_TYPE = rebar\n"), Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), ToList = fun (V) when is_atom(V) -> atom_to_list(V); (V) when is_list(V) -> "'\\"" ++ V ++ "\\"'" end, fun() -> Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), case lists:keyfind(erl_opts, 1, Conf) of false -> ok; {_, ErlOpts} -> lists:foreach(fun ({d, D}) -> Write("ERLC_OPTS += -D" ++ ToList(D) ++ "=1\n"); ({d, DKey, DVal}) -> Write("ERLC_OPTS += -D" ++ ToList(DKey) ++ "=" ++ ToList(DVal) ++ "\n"); ({i, I}) -> Write(["ERLC_OPTS += -I ", I, "\n"]); ({platform_define, Regex, D}) -> case rebar_utils:is_arch(Regex) of true -> Write("ERLC_OPTS += -D" ++ ToList(D) ++ "=1\n"); false -> ok end; ({parse_transform, PT}) -> Write("ERLC_OPTS += +'{parse_transform, " ++ ToList(PT) ++ "}'\n"); (_) -> ok end, ErlOpts) end, Write("\n") end(), GetHexVsn = fun(N) -> case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.lock)") of {ok, Lock} -> io:format("~p~n", [Lock]), case lists:keyfind("1.1.0", 1, Lock) of {_, LockPkgs} -> io:format("~p~n", [LockPkgs]), case lists:keyfind(atom_to_binary(N, latin1), 1, LockPkgs) of {_, {pkg, _, Vsn}, _} -> io:format("~p~n", [Vsn]), {N, {hex, binary_to_list(Vsn)}}; _ -> false end; _ -> false end; _ -> false end end, SemVsn = fun ("~>" ++ S0) -> S = case S0 of " " ++ S1 -> S1; _ -> S0 end, case length([ok || $$. <- S]) of 0 -> S ++ ".0.0"; 1 -> S ++ ".0"; _ -> S end; (S) -> S end, fun() -> File = case lists:keyfind(deps, 1, Conf) of false -> []; {_, Deps} -> [begin case case Dep of N when is_atom(N) -> GetHexVsn(N); {N, S} when is_atom(N), is_list(S) -> {N, {hex, SemVsn(S)}}; {_, S, {pkg, N}} -> {N, {hex, S}}; {N, S} when is_tuple(S) -> {N, S}; {N, _, S} -> {N, S}; {N, _, S, _} -> {N, S}; _ -> false end of false -> ok; {Name, Source} -> {Method, Repo, Commit} = case Source of {hex, V} -> {hex, V, undefined}; {git, R} -> {git, R, master}; {M, R, {branch, C}} -> {M, R, C}; {M, R, {ref, C}} -> {M, R, C}; {M, R, {tag, C}} -> {M, R, C}; {M, R, C} -> {M, R, C} end, Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) end end || Dep <- Deps] end end(), fun() -> case lists:keyfind(erl_first_files, 1, Conf) of false -> ok; {_, Files} -> Names = [[" ", case lists:reverse(F) of "lre." ++ Elif -> lists:reverse(Elif); "lrx." ++ Elif -> lists:reverse(Elif); "lry." ++ Elif -> lists:reverse(Elif); Elif -> lists:reverse(Elif) end] || "src/" ++ F <- Files], Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) end end(), Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), Write("\npreprocess::\n"), Write("\npre-deps::\n"), Write("\npre-app::\n"), PatchHook = fun(Cmd) -> Cmd2 = re:replace(Cmd, "^([g]?make)(.*)( -C.*)", "\\\\1\\\\3\\\\2", [{return, list}]), case Cmd2 of "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); _ -> Escape(Cmd) end end, fun() -> case lists:keyfind(pre_hooks, 1, Conf) of false -> ok; {_, Hooks} -> [case H of {'get-deps', Cmd} -> Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); {compile, Cmd} -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); {Regex, compile, Cmd} -> case rebar_utils:is_arch(Regex) of true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); false -> ok end; _ -> ok end || H <- Hooks] end end(), ShellToMk = fun(V0) -> V1 = re:replace(V0, "[$$][(]", "$$\(shell ", [global]), V = re:replace(V1, "([$$])(?![(])(\\\\w*)", "\\\\1(\\\\2)", [global]), re:replace(V, "-Werror\\\\b", "", [{return, list}, global]) end, PortSpecs = fun() -> case lists:keyfind(port_specs, 1, Conf) of false -> case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of false -> []; true -> [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] end; {_, Specs} -> lists:flatten([case S of {Output, Input} -> {ShellToMk(Output), Input, []}; {Regex, Output, Input} -> case rebar_utils:is_arch(Regex) of true -> {ShellToMk(Output), Input, []}; false -> [] end; {Regex, Output, Input, [{env, Env}]} -> case rebar_utils:is_arch(Regex) of true -> {ShellToMk(Output), Input, Env}; false -> [] end end || S <- Specs]) end end(), PortSpecWrite = fun (Text) -> file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) end, case PortSpecs of [] -> ok; _ -> Write("\npre-app::\n\t@$$\(MAKE) --no-print-directory -f c_src/Makefile.erlang.mk\n"), PortSpecWrite(io_lib:format("ERL_CFLAGS ?= -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lerl_interface -lei\n", [code:lib_dir(erl_interface, lib)])), [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], FilterEnv = fun(Env) -> lists:flatten([case E of {_, _} -> E; {Regex, K, V} -> case rebar_utils:is_arch(Regex) of true -> {K, V}; false -> [] end end || E <- Env]) end, MergeEnv = fun(Env) -> lists:foldl(fun ({K, V}, Acc) -> case lists:keyfind(K, 1, Acc) of false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] end end, [], Env) end, PortEnv = case lists:keyfind(port_env, 1, Conf) of false -> []; {_, PortEnv0} -> FilterEnv(PortEnv0) end, PortSpec = fun ({Output, Input0, Env}) -> filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), Input = [[" ", I] || I <- Input0], PortSpecWrite([ [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], case $(PLATFORM) of darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; _ -> "" end, "\n\nall:: ", Output, "\n\t@:\n\n", "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", [[Output, ": ", K, " += ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], Output, ": $$\(foreach ext,.c .C .cc .cpp,", "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", case {filename:extension(Output), $(PLATFORM)} of {[], _} -> "\n"; {_, darwin} -> "\n"; _ -> " -shared\n" end]) end, [PortSpec(S) || S <- PortSpecs] end, fun() -> case lists:keyfind(plugins, 1, Conf) of false -> ok; {_, Plugins0} -> Plugins = [P || P <- Plugins0, is_tuple(P)], case lists:keyfind('lfe-compile', 1, Plugins) of false -> ok; _ -> Write("\nBUILD_DEPS = lfe lfe.mk\ndep_lfe.mk = git https://github.com/ninenines/lfe.mk master\nDEP_PLUGINS = lfe.mk\n") end end end(), Write("\ninclude $$\(if $$\(ERLANG_MK_FILENAME),$$\(ERLANG_MK_FILENAME),erlang.mk)"), RunPlugin = fun(Plugin, Step) -> case erlang:function_exported(Plugin, Step, 2) of false -> ok; true -> c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), dict:store(base_dir, "", dict:new())}, undefined), io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) end end, fun() -> case lists:keyfind(plugins, 1, Conf) of false -> ok; {_, Plugins0} -> Plugins = [P || P <- Plugins0, is_atom(P)], [begin case lists:keyfind(deps, 1, Conf) of false -> ok; {_, Deps} -> case lists:keyfind(P, 1, Deps) of false -> ok; _ -> Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), code:add_patha(Path ++ "/ebin") end end end || P <- Plugins], [case code:load_file(P) of {module, P} -> ok; _ -> case lists:keyfind(plugin_dir, 1, Conf) of false -> ok; {_, PluginsDir} -> ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", {ok, P, Bin} = compile:file(ErlFile, [binary]), {module, P} = code:load_binary(P, ErlFile, Bin) end end || P <- Plugins], [RunPlugin(P, preprocess) || P <- Plugins], [RunPlugin(P, pre_compile) || P <- Plugins], [RunPlugin(P, compile) || P <- Plugins] end end(), halt() endef define dep_autopatch_appsrc_script.erl AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", AppSrcScript = AppSrc ++ ".script", {ok, Conf0} = file:consult(AppSrc), Bindings0 = erl_eval:new_bindings(), Bindings1 = erl_eval:add_binding('CONFIG', Conf0, Bindings0), Bindings = erl_eval:add_binding('SCRIPT', AppSrcScript, Bindings1), Conf = case file:script(AppSrcScript, Bindings) of {ok, [C]} -> C; {ok, C} -> C end, ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), halt() endef define dep_autopatch_appsrc.erl AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, case filelib:is_regular(AppSrcIn) of false -> ok; true -> {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), L1 = lists:keystore(modules, 1, L0, {modules, []}), L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, lists:droplast(os:cmd("git -C $(DEPS_DIR)/$1 describe --dirty --tags --always"))}); {_, {cmd, _}} -> lists:keyreplace(vsn, 1, L1, {vsn, "cmd"}); _ -> L1 end, L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end end, halt() endef define dep_fetch_git git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); endef define dep_fetch_git-subfolder mkdir -p $(ERLANG_MK_TMP)/git-subfolder; \ git clone -q -n -- $(call dep_repo,$1) \ $(ERLANG_MK_TMP)/git-subfolder/$(call dep_name,$1); \ cd $(ERLANG_MK_TMP)/git-subfolder/$(call dep_name,$1) \ && git checkout -q $(call dep_commit,$1); \ ln -s $(ERLANG_MK_TMP)/git-subfolder/$(call dep_name,$1)/$(word 4,$(dep_$(1))) \ $(DEPS_DIR)/$(call dep_name,$1); endef define dep_fetch_git-submodule git submodule update --init -- $(DEPS_DIR)/$1; endef define dep_fetch_hg hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); endef define dep_fetch_svn svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); endef define dep_fetch_cp cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); endef define dep_fetch_ln ln -s $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); endef # Hex only has a package version. No need to look in the Erlang.mk packages. define dep_fetch_hex mkdir -p $(ERLANG_MK_TMP)/hex $(DEPS_DIR)/$1; \ $(call core_http_get,$(ERLANG_MK_TMP)/hex/$1.tar,\ https://repo.hex.pm/tarballs/$1-$(strip $(word 2,$(dep_$1))).tar); \ tar -xOf $(ERLANG_MK_TMP)/hex/$1.tar contents.tar.gz | tar -C $(DEPS_DIR)/$1 -xzf -; endef define dep_fetch_fail echo "Error: Unknown or invalid dependency: $(1)." >&2; \ exit 78; endef # Kept for compatibility purposes with older Erlang.mk configuration. define dep_fetch_legacy $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); endef define dep_fetch $(if $(dep_$(1)), \ $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ $(word 1,$(dep_$(1))), \ $(if $(IS_DEP),legacy,fail)), \ $(if $(filter $(1),$(PACKAGES)), \ $(pkg_$(1)_fetch), \ fail)) endef define dep_target $(DEPS_DIR)/$(call dep_name,$1): | $(ERLANG_MK_TMP) $(eval DEP_NAME := $(call dep_name,$1)) $(eval DEP_STR := $(if $(filter $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)." >&2; \ exit 17; \ fi $(verbose) mkdir -p $(DEPS_DIR) $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ echo " AUTO " $(DEP_STR); \ cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ fi - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ echo " CONF " $(DEP_STR); \ cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ fi ifeq ($(filter $(1),$(NO_AUTOPATCH)),) $(verbose) $$(MAKE) --no-print-directory autopatch-$(DEP_NAME) endif .PHONY: autopatch-$(call dep_name,$1) autopatch-$(call dep_name,$1):: $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ echo " PATCH Downloading rabbitmq-codegen"; \ git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ fi; \ if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ echo " PATCH Downloading rabbitmq-server"; \ git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ fi; \ ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ echo " PATCH Downloading rabbitmq-codegen"; \ git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ fi \ elif [ "$1" = "elixir" -a "$(ELIXIR_PATCH)" ]; then \ ln -s lib/elixir/ebin $(DEPS_DIR)/elixir/; \ else \ $$(call dep_autopatch,$(call dep_name,$1)) \ fi endef $(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) ifndef IS_APP clean:: clean-apps clean-apps: $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ $(MAKE) -C $$dep clean IS_APP=1; \ done distclean:: distclean-apps distclean-apps: $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ $(MAKE) -C $$dep distclean IS_APP=1; \ done endif ifndef SKIP_DEPS distclean:: distclean-deps distclean-deps: $(gen_verbose) rm -rf $(DEPS_DIR) endif # Forward-declare variables used in core/deps-tools.mk. This is required # in case plugins use them. ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log # Copyright (c) 2015-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. # Verbosity. proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); proto_verbose = $(proto_verbose_$(V)) # Core targets. ifneq ($(wildcard src/),) PROTO_FILES := $(filter %.proto,$(ALL_SRC_FILES)) ERL_FILES += $(addprefix src/,$(patsubst %.proto,%_pb.erl,$(notdir $(PROTO_FILES)))) ifeq ($(PROTO_FILES),) $(ERLANG_MK_TMP)/last-makefile-change-protobuffs: $(verbose) : else # Rebuild proto files when the Makefile changes. # We exclude $(PROJECT).d to avoid a circular dependency. $(ERLANG_MK_TMP)/last-makefile-change-protobuffs: $(filter-out $(PROJECT).d,$(MAKEFILE_LIST)) | $(ERLANG_MK_TMP) $(verbose) if test -f $@; then \ touch $(PROTO_FILES); \ fi $(verbose) touch $@ $(PROJECT).d:: $(ERLANG_MK_TMP)/last-makefile-change-protobuffs endif ifeq ($(filter gpb,$(BUILD_DEPS) $(DEPS)),) define compile_proto.erl [begin protobuffs_compile:generate_source(F, [ {output_include_dir, "./include"}, {output_src_dir, "./src"}]) end || F <- string:tokens("$1", " ")], halt(). endef else define compile_proto.erl [begin gpb_compile:file(F, [ {include_as_lib, true}, {module_name_suffix, "_pb"}, {o_hrl, "./include"}, {o_erl, "./src"}]) end || F <- string:tokens("$1", " ")], halt(). endef endif ifneq ($(PROTO_FILES),) $(PROJECT).d:: $(PROTO_FILES) $(verbose) mkdir -p ebin/ include/ $(if $(strip $?),$(proto_verbose) $(call erlang,$(call compile_proto.erl,$?))) endif endif # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-app # Configuration. ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec COMPILE_FIRST ?= COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) ERLC_EXCLUDE ?= ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) ERLC_ASN1_OPTS ?= ERLC_MIB_OPTS ?= COMPILE_MIB_FIRST ?= COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) # Verbosity. app_verbose_0 = @echo " APP " $(PROJECT); app_verbose_2 = set -x; app_verbose = $(app_verbose_$(V)) appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; appsrc_verbose_2 = set -x; appsrc_verbose = $(appsrc_verbose_$(V)) makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; makedep_verbose_2 = set -x; makedep_verbose = $(makedep_verbose_$(V)) erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ $(filter %.erl %.core,$(?F))); erlc_verbose_2 = set -x; erlc_verbose = $(erlc_verbose_$(V)) xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); xyrl_verbose_2 = set -x; xyrl_verbose = $(xyrl_verbose_$(V)) asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); asn1_verbose_2 = set -x; asn1_verbose = $(asn1_verbose_$(V)) mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); mib_verbose_2 = set -x; mib_verbose = $(mib_verbose_$(V)) ifneq ($(wildcard src/),) # Targets. app:: $(if $(wildcard ebin/test),clean) deps $(verbose) $(MAKE) --no-print-directory $(PROJECT).d $(verbose) $(MAKE) --no-print-directory app-build ifeq ($(wildcard src/$(PROJECT_MOD).erl),) define app_file {application, '$(PROJECT)', [ {description, "$(PROJECT_DESCRIPTION)"}, {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, []}, {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(foreach dep,$(DEPS),$(call dep_name,$(dep))))]}, {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) ]}. endef else define app_file {application, '$(PROJECT)', [ {description, "$(PROJECT_DESCRIPTION)"}, {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(foreach dep,$(DEPS),$(call dep_name,$(dep))))]}, {mod, {$(PROJECT_MOD), []}}, {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) ]}. endef endif app-build: ebin/$(PROJECT).app $(verbose) : # Source files. ALL_SRC_FILES := $(sort $(call core_find,src/,*)) ERL_FILES := $(filter %.erl,$(ALL_SRC_FILES)) CORE_FILES := $(filter %.core,$(ALL_SRC_FILES)) # ASN.1 files. ifneq ($(wildcard asn1/),) ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) define compile_asn1 $(verbose) mkdir -p include/ $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(ERLC_ASN1_OPTS) $(1) $(verbose) mv asn1/*.erl src/ -$(verbose) mv asn1/*.hrl include/ $(verbose) mv asn1/*.asn1db include/ endef $(PROJECT).d:: $(ASN1_FILES) $(if $(strip $?),$(call compile_asn1,$?)) endif # SNMP MIB files. ifneq ($(wildcard mibs/),) MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) $(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) $(verbose) mkdir -p include/ priv/mibs/ $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) endif # Leex and Yecc files. XRL_FILES := $(filter %.xrl,$(ALL_SRC_FILES)) XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) ERL_FILES += $(XRL_ERL_FILES) YRL_FILES := $(filter %.yrl,$(ALL_SRC_FILES)) YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) ERL_FILES += $(YRL_ERL_FILES) $(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $(YRL_ERLC_OPTS) $?) # Erlang and Core Erlang files. define makedep.erl E = ets:new(makedep, [bag]), G = digraph:new([acyclic]), ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), DepsDir = "$(call core_native_path,$(DEPS_DIR))", AppsDir = "$(call core_native_path,$(APPS_DIR))", DepsDirsSrc = "$(if $(wildcard $(DEPS_DIR)/*/src), $(call core_native_path,$(wildcard $(DEPS_DIR)/*/src)))", DepsDirsInc = "$(if $(wildcard $(DEPS_DIR)/*/include), $(call core_native_path,$(wildcard $(DEPS_DIR)/*/include)))", AppsDirsSrc = "$(if $(wildcard $(APPS_DIR)/*/src), $(call core_native_path,$(wildcard $(APPS_DIR)/*/src)))", AppsDirsInc = "$(if $(wildcard $(APPS_DIR)/*/include), $(call core_native_path,$(wildcard $(APPS_DIR)/*/include)))", DepsDirs = lists:usort(string:tokens(DepsDirsSrc++DepsDirsInc, " ")), AppsDirs = lists:usort(string:tokens(AppsDirsSrc++AppsDirsInc, " ")), Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], Add = fun (Mod, Dep) -> case lists:keyfind(Dep, 1, Modules) of false -> ok; {_, DepFile} -> {_, ModFile} = lists:keyfind(Mod, 1, Modules), ets:insert(E, {ModFile, DepFile}), digraph:add_vertex(G, Mod), digraph:add_vertex(G, Dep), digraph:add_edge(G, Mod, Dep) end end, AddHd = fun (F, Mod, DepFile) -> case file:open(DepFile, [read]) of {error, enoent} -> ok; {ok, Fd} -> {_, ModFile} = lists:keyfind(Mod, 1, Modules), case ets:match(E, {ModFile, DepFile}) of [] -> ets:insert(E, {ModFile, DepFile}), F(F, Fd, Mod,0); _ -> ok end end end, SearchHrl = fun F(_Hrl, []) -> {error,enoent}; F(Hrl, [Dir|Dirs]) -> HrlF = filename:join([Dir,Hrl]), case filelib:is_file(HrlF) of true -> {ok, HrlF}; false -> F(Hrl,Dirs) end end, Attr = fun (_F, Mod, behavior, Dep) -> Add(Mod, Dep); (_F, Mod, behaviour, Dep) -> Add(Mod, Dep); (_F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); (_F, Mod, compile, Opts) when is_list(Opts) -> case proplists:get_value(parse_transform, Opts) of undefined -> ok; Dep -> Add(Mod, Dep) end; (F, Mod, include, Hrl) -> case SearchHrl(Hrl, ["src", "include",AppsDir,DepsDir]++AppsDirs++DepsDirs) of {ok, FoundHrl} -> AddHd(F, Mod, FoundHrl); {error, _} -> false end; (F, Mod, include_lib, Hrl) -> case SearchHrl(Hrl, ["src", "include",AppsDir,DepsDir]++AppsDirs++DepsDirs) of {ok, FoundHrl} -> AddHd(F, Mod, FoundHrl); {error, _} -> false end; (F, Mod, import, {Imp, _}) -> IsFile = case lists:keyfind(Imp, 1, Modules) of false -> false; {_, FilePath} -> filelib:is_file(FilePath) end, case IsFile of false -> ok; true -> Add(Mod, Imp) end; (_, _, _, _) -> ok end, MakeDepend = fun (F, Fd, Mod, StartLocation) -> {ok, Filename} = file:pid2name(Fd), case io:parse_erl_form(Fd, undefined, StartLocation) of {ok, AbsData, EndLocation} -> case AbsData of {attribute, _, Key, Value} -> Attr(F, Mod, Key, Value), F(F, Fd, Mod, EndLocation); _ -> F(F, Fd, Mod, EndLocation) end; {eof, _ } -> file:close(Fd); {error, ErrorDescription } -> file:close(Fd); {error, ErrorInfo, ErrorLocation} -> F(F, Fd, Mod, ErrorLocation) end, ok end, [begin Mod = list_to_atom(filename:basename(F, ".erl")), case file:open(F, [read]) of {ok, Fd} -> MakeDepend(MakeDepend, Fd, Mod,0); {error, enoent} -> ok end end || F <- ErlFiles], Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], TargetPath = fun(Target) -> case lists:keyfind(Target, 1, Modules) of false -> ""; {_, DepFile} -> DirSubname = tl(string:tokens(filename:dirname(DepFile), "/")), string:join(DirSubname ++ [atom_to_list(Target)], "/") end end, ok = file:write_file("$(1)", unicode:characters_to_binary([ "# Generated by Erlang.mk. Edit at your own risk!\n\n", [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], "\nCOMPILE_FIRST +=", [[" ", TargetPath(CF)] || CF <- CompileFirst], "\n" ])), halt() endef ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) $(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) endif ifeq ($(IS_APP)$(IS_DEP),) ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) # Rebuild everything when the Makefile changes. $(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) | $(ERLANG_MK_TMP) $(verbose) if test -f $@; then \ touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ touch -c $(PROJECT).d; \ fi $(verbose) touch $@ $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change endif endif $(PROJECT).d:: $(verbose) : include $(wildcard $(PROJECT).d) ebin/$(PROJECT).app:: ebin/ ebin/: $(verbose) mkdir -p ebin/ define compile_erl $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) endef define validate_app_file case file:consult("ebin/$(PROJECT).app") of {ok, _} -> halt(); _ -> halt(1) end endef ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) # Older git versions do not have the --first-parent flag. Do without in that case. $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null \ || git describe --dirty --abbrev=7 --tags --always 2>/dev/null || true)) $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) ifeq ($(wildcard src/$(PROJECT).app.src),) $(app_verbose) printf '$(subst %,%%,$(subst $(newline),\n,$(subst ','\'',$(call app_file,$(GITDESCRIBE),$(MODULES)))))' \ > ebin/$(PROJECT).app $(verbose) if ! $(call erlang,$(call validate_app_file)); then \ echo "The .app file produced is invalid. Please verify the value of PROJECT_ENV." >&2; \ exit 1; \ fi else $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk documentation for instructions." >&2; \ exit 1; \ fi $(appsrc_verbose) cat src/$(PROJECT).app.src \ | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ > ebin/$(PROJECT).app endif clean:: clean-app clean-app: $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) endif # Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: docs-deps # Configuration. ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) # Targets. $(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) ifneq ($(SKIP_DEPS),) doc-deps: else doc-deps: $(ALL_DOC_DEPS_DIRS) $(verbose) set -e; for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done endif # Copyright (c) 2015-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rel-deps # Configuration. ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) # Targets. $(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) ifneq ($(SKIP_DEPS),) rel-deps: else rel-deps: $(ALL_REL_DEPS_DIRS) $(verbose) set -e; for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif # Copyright (c) 2015-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: test-deps test-dir test-build clean-test-dir # Configuration. TEST_DIR ?= $(CURDIR)/test ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard TEST_ERLC_OPTS += -DTEST=1 # Targets. $(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) ifneq ($(SKIP_DEPS),) test-deps: else test-deps: $(ALL_TEST_DEPS_DIRS) $(verbose) set -e; for dep in $(ALL_TEST_DEPS_DIRS) ; do \ if [ -z "$(strip $(FULL))" ] && [ ! -L $$dep ] && [ -f $$dep/ebin/dep_built ]; then \ :; \ else \ $(MAKE) -C $$dep IS_DEP=1; \ if [ ! -L $$dep ] && [ -d $$dep/ebin ]; then touch $$dep/ebin/dep_built; fi; \ fi \ done endif ifneq ($(wildcard $(TEST_DIR)),) test-dir: $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -o $(TEST_DIR) \ -pa ebin/ -I include/ $(call core_find,$(TEST_DIR)/,*.erl) endif test-build:: IS_TEST=1 test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) test-build:: $(if $(wildcard src),$(if $(wildcard ebin/test),,clean)) $(if $(IS_APP),,deps test-deps) # We already compiled everything when IS_APP=1. ifndef IS_APP ifneq ($(wildcard $(TEST_DIR)),) $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" endif ifneq ($(wildcard src),) $(verbose) $(MAKE) --no-print-directory $(PROJECT).d ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" $(verbose) $(MAKE) --no-print-directory app-build ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" $(gen_verbose) touch ebin/test endif endif # Roughly the same as test-build, but when IS_APP=1. # We only care about compiling the current application. ifdef IS_APP test-build-app:: ERLC_OPTS=$(TEST_ERLC_OPTS) test-build-app:: deps test-deps ifneq ($(wildcard $(TEST_DIR)),) $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" endif ifneq ($(wildcard src),) $(verbose) $(MAKE) --no-print-directory $(PROJECT).d ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" $(verbose) $(MAKE) --no-print-directory app-build ERLC_OPTS="$(call escape_dquotes,$(TEST_ERLC_OPTS))" $(gen_verbose) touch ebin/test endif endif clean:: clean-test-dir clean-test-dir: ifneq ($(wildcard $(TEST_DIR)/*.beam),) $(gen_verbose) rm -f $(TEST_DIR)/*.beam endif # Copyright (c) 2015-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rebar.config # We strip out -Werror because we don't want to fail due to # warnings when used as a dependency. compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') define compat_convert_erlc_opts $(if $(filter-out -Werror,$1),\ $(if $(findstring +,$1),\ $(shell echo $1 | cut -b 2-))) endef define compat_erlc_opts_to_list [$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] endef define compat_rebar_config {deps, [ $(call comma_list,$(foreach d,$(DEPS),\ $(if $(filter hex,$(call dep_fetch,$d)),\ {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) ]}. {erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. endef rebar.config: $(gen_verbose) $(call core_render,compat_rebar_config,rebar.config) # Copyright (c) 2015-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. ifeq ($(filter asciideck,$(DEPS) $(DOC_DEPS)),asciideck) .PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc-guide distclean-asciidoc-manual # Core targets. docs:: asciidoc distclean:: distclean-asciidoc-guide distclean-asciidoc-manual # Plugin-specific targets. asciidoc: asciidoc-guide asciidoc-manual # User guide. ifeq ($(wildcard doc/src/guide/book.asciidoc),) asciidoc-guide: else asciidoc-guide: distclean-asciidoc-guide doc-deps a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ distclean-asciidoc-guide: $(gen_verbose) rm -rf doc/html/ doc/guide.pdf endif # Man pages. ASCIIDOC_MANUAL_FILES := $(wildcard doc/src/manual/*.asciidoc) ifeq ($(ASCIIDOC_MANUAL_FILES),) asciidoc-manual: else # Configuration. MAN_INSTALL_PATH ?= /usr/local/share/man MAN_SECTIONS ?= 3 7 MAN_PROJECT ?= $(shell echo $(PROJECT) | sed 's/^./\U&\E/') MAN_VERSION ?= $(PROJECT_VERSION) # Plugin-specific targets. define asciidoc2man.erl try [begin io:format(" ADOC ~s~n", [F]), ok = asciideck:to_manpage(asciideck:parse_file(F), #{ compress => gzip, outdir => filename:dirname(F), extra2 => "$(MAN_PROJECT) $(MAN_VERSION)", extra3 => "$(MAN_PROJECT) Function Reference" }) end || F <- [$(shell echo $(addprefix $(comma)\",$(addsuffix \",$1)) | sed 's/^.//')]], halt(0) catch C:E -> io:format("Exception ~p:~p~nStacktrace: ~p~n", [C, E, erlang:get_stacktrace()]), halt(1) end. endef asciidoc-manual:: doc-deps asciidoc-manual:: $(ASCIIDOC_MANUAL_FILES) $(gen_verbose) $(call erlang,$(call asciidoc2man.erl,$?)) $(verbose) $(foreach s,$(MAN_SECTIONS),mkdir -p doc/man$s/ && mv doc/src/manual/*.$s.gz doc/man$s/;) install-docs:: install-asciidoc install-asciidoc: asciidoc-manual $(foreach s,$(MAN_SECTIONS),\ mkdir -p $(MAN_INSTALL_PATH)/man$s/ && \ install -g `id -g` -o `id -u` -m 0644 doc/man$s/*.gz $(MAN_INSTALL_PATH)/man$s/;) distclean-asciidoc-manual: $(gen_verbose) rm -rf $(addprefix doc/man,$(MAN_SECTIONS)) endif endif # Copyright (c) 2014-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates # Core targets. help:: $(verbose) printf "%s\n" "" \ "Bootstrap targets:" \ " bootstrap Generate a skeleton of an OTP application" \ " bootstrap-lib Generate a skeleton of an OTP library" \ " bootstrap-rel Generate the files needed to build a release" \ " new-app in=NAME Create a new local OTP application NAME" \ " new-lib in=NAME Create a new local OTP library NAME" \ " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ " list-templates List available templates" # Bootstrap templates. define bs_appsrc {application, $p, [ {description, ""}, {vsn, "0.1.0"}, {id, "git"}, {modules, []}, {registered, []}, {applications, [ kernel, stdlib ]}, {mod, {$p_app, []}}, {env, []} ]}. endef define bs_appsrc_lib {application, $p, [ {description, ""}, {vsn, "0.1.0"}, {id, "git"}, {modules, []}, {registered, []}, {applications, [ kernel, stdlib ]} ]}. endef # To prevent autocompletion issues with ZSH, we add "include erlang.mk" # separately during the actual bootstrap. define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project PROJECT_VERSION = 0.1.0 $(if $(SP), # Whitespace to be used when creating files from templates. SP = $(SP) ) endef define bs_apps_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project PROJECT_VERSION = 0.1.0 $(if $(SP), # Whitespace to be used when creating files from templates. SP = $(SP) ) # Make sure we know where the applications are located. ROOT_DIR ?= $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app) APPS_DIR ?= .. DEPS_DIR ?= $(call core_relpath,$(DEPS_DIR),$(APPS_DIR)/app) include $$(ROOT_DIR)/erlang.mk endef define bs_app -module($p_app). -behaviour(application). -export([start/2]). -export([stop/1]). start(_Type, _Args) -> $p_sup:start_link(). stop(_State) -> ok. endef define bs_relx_config {release, {$p_release, "1"}, [$p, sasl, runtime_tools]}. {extended_start_script, true}. {sys_config, "config/sys.config"}. {vm_args, "config/vm.args"}. endef define bs_sys_config [ ]. endef define bs_vm_args -name $p@127.0.0.1 -setcookie $p -heart endef # Normal templates. define tpl_supervisor -module($(n)). -behaviour(supervisor). -export([start_link/0]). -export([init/1]). start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). init([]) -> Procs = [], {ok, {{one_for_one, 1, 5}, Procs}}. endef define tpl_gen_server -module($(n)). -behaviour(gen_server). %% API. -export([start_link/0]). %% gen_server. -export([init/1]). -export([handle_call/3]). -export([handle_cast/2]). -export([handle_info/2]). -export([terminate/2]). -export([code_change/3]). -record(state, { }). %% API. -spec start_link() -> {ok, pid()}. start_link() -> gen_server:start_link(?MODULE, [], []). %% gen_server. init([]) -> {ok, #state{}}. handle_call(_Request, _From, State) -> {reply, ignored, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. endef define tpl_module -module($(n)). -export([]). endef define tpl_cowboy_http -module($(n)). -behaviour(cowboy_http_handler). -export([init/3]). -export([handle/2]). -export([terminate/3]). -record(state, { }). init(_, Req, _Opts) -> {ok, Req, #state{}}. handle(Req, State=#state{}) -> {ok, Req2} = cowboy_req:reply(200, Req), {ok, Req2, State}. terminate(_Reason, _Req, _State) -> ok. endef define tpl_gen_fsm -module($(n)). -behaviour(gen_fsm). %% API. -export([start_link/0]). %% gen_fsm. -export([init/1]). -export([state_name/2]). -export([handle_event/3]). -export([state_name/3]). -export([handle_sync_event/4]). -export([handle_info/3]). -export([terminate/3]). -export([code_change/4]). -record(state, { }). %% API. -spec start_link() -> {ok, pid()}. start_link() -> gen_fsm:start_link(?MODULE, [], []). %% gen_fsm. init([]) -> {ok, state_name, #state{}}. state_name(_Event, StateData) -> {next_state, state_name, StateData}. handle_event(_Event, StateName, StateData) -> {next_state, StateName, StateData}. state_name(_Event, _From, StateData) -> {reply, ignored, state_name, StateData}. handle_sync_event(_Event, _From, StateName, StateData) -> {reply, ignored, StateName, StateData}. handle_info(_Info, StateName, StateData) -> {next_state, StateName, StateData}. terminate(_Reason, _StateName, _StateData) -> ok. code_change(_OldVsn, StateName, StateData, _Extra) -> {ok, StateName, StateData}. endef define tpl_gen_statem -module($(n)). -behaviour(gen_statem). %% API. -export([start_link/0]). %% gen_statem. -export([callback_mode/0]). -export([init/1]). -export([state_name/3]). -export([handle_event/4]). -export([terminate/3]). -export([code_change/4]). -record(state, { }). %% API. -spec start_link() -> {ok, pid()}. start_link() -> gen_statem:start_link(?MODULE, [], []). %% gen_statem. callback_mode() -> state_functions. init([]) -> {ok, state_name, #state{}}. state_name(_EventType, _EventData, StateData) -> {next_state, state_name, StateData}. handle_event(_EventType, _EventData, StateName, StateData) -> {next_state, StateName, StateData}. terminate(_Reason, _StateName, _StateData) -> ok. code_change(_OldVsn, StateName, StateData, _Extra) -> {ok, StateName, StateData}. endef define tpl_cowboy_loop -module($(n)). -behaviour(cowboy_loop_handler). -export([init/3]). -export([info/3]). -export([terminate/3]). -record(state, { }). init(_, Req, _Opts) -> {loop, Req, #state{}, 5000, hibernate}. info(_Info, Req, State) -> {loop, Req, State, hibernate}. terminate(_Reason, _Req, _State) -> ok. endef define tpl_cowboy_rest -module($(n)). -export([init/3]). -export([content_types_provided/2]). -export([get_html/2]). init(_, _Req, _Opts) -> {upgrade, protocol, cowboy_rest}. content_types_provided(Req, State) -> {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. get_html(Req, State) -> {<<"This is REST!">>, Req, State}. endef define tpl_cowboy_ws -module($(n)). -behaviour(cowboy_websocket_handler). -export([init/3]). -export([websocket_init/3]). -export([websocket_handle/3]). -export([websocket_info/3]). -export([websocket_terminate/3]). -record(state, { }). init(_, _, _) -> {upgrade, protocol, cowboy_websocket}. websocket_init(_, Req, _Opts) -> Req2 = cowboy_req:compact(Req), {ok, Req2, #state{}}. websocket_handle({text, Data}, Req, State) -> {reply, {text, Data}, Req, State}; websocket_handle({binary, Data}, Req, State) -> {reply, {binary, Data}, Req, State}; websocket_handle(_Frame, Req, State) -> {ok, Req, State}. websocket_info(_Info, Req, State) -> {ok, Req, State}. websocket_terminate(_Reason, _Req, _State) -> ok. endef define tpl_ranch_protocol -module($(n)). -behaviour(ranch_protocol). -export([start_link/4]). -export([init/4]). -type opts() :: []. -export_type([opts/0]). -record(state, { socket :: inet:socket(), transport :: module() }). start_link(Ref, Socket, Transport, Opts) -> Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), {ok, Pid}. -spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. init(Ref, Socket, Transport, _Opts) -> ok = ranch:accept_ack(Ref), loop(#state{socket=Socket, transport=Transport}). loop(State) -> loop(State). endef # Plugin-specific targets. ifndef WS ifdef SP WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) else WS = $(tab) endif endif bootstrap: ifneq ($(wildcard src/),) $(error Error: src/ directory already exists) endif $(eval p := $(PROJECT)) $(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\ $(error Error: Invalid characters in the application name)) $(eval n := $(PROJECT)_sup) $(verbose) $(call core_render,bs_Makefile,Makefile) $(verbose) echo "include erlang.mk" >> Makefile $(verbose) mkdir src/ ifdef LEGACY $(verbose) $(call core_render,bs_appsrc,src/$(PROJECT).app.src) endif $(verbose) $(call core_render,bs_app,src/$(PROJECT)_app.erl) $(verbose) $(call core_render,tpl_supervisor,src/$(PROJECT)_sup.erl) bootstrap-lib: ifneq ($(wildcard src/),) $(error Error: src/ directory already exists) endif $(eval p := $(PROJECT)) $(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\ $(error Error: Invalid characters in the application name)) $(verbose) $(call core_render,bs_Makefile,Makefile) $(verbose) echo "include erlang.mk" >> Makefile $(verbose) mkdir src/ ifdef LEGACY $(verbose) $(call core_render,bs_appsrc_lib,src/$(PROJECT).app.src) endif bootstrap-rel: ifneq ($(wildcard relx.config),) $(error Error: relx.config already exists) endif ifneq ($(wildcard config/),) $(error Error: config/ directory already exists) endif $(eval p := $(PROJECT)) $(verbose) $(call core_render,bs_relx_config,relx.config) $(verbose) mkdir config/ $(verbose) $(call core_render,bs_sys_config,config/sys.config) $(verbose) $(call core_render,bs_vm_args,config/vm.args) new-app: ifndef in $(error Usage: $(MAKE) new-app in=APP) endif ifneq ($(wildcard $(APPS_DIR)/$in),) $(error Error: Application $in already exists) endif $(eval p := $(in)) $(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\ $(error Error: Invalid characters in the application name)) $(eval n := $(in)_sup) $(verbose) mkdir -p $(APPS_DIR)/$p/src/ $(verbose) $(call core_render,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) ifdef LEGACY $(verbose) $(call core_render,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) endif $(verbose) $(call core_render,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) $(verbose) $(call core_render,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) new-lib: ifndef in $(error Usage: $(MAKE) new-lib in=APP) endif ifneq ($(wildcard $(APPS_DIR)/$in),) $(error Error: Application $in already exists) endif $(eval p := $(in)) $(if $(shell echo $p | LC_ALL=C grep -x "[a-z0-9_]*"),,\ $(error Error: Invalid characters in the application name)) $(verbose) mkdir -p $(APPS_DIR)/$p/src/ $(verbose) $(call core_render,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) ifdef LEGACY $(verbose) $(call core_render,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) endif new: ifeq ($(wildcard src/)$(in),) $(error Error: src/ directory does not exist) endif ifndef t $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif ifndef n $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif ifdef in $(verbose) $(call core_render,tpl_$(t),$(APPS_DIR)/$(in)/src/$(n).erl) else $(verbose) $(call core_render,tpl_$(t),src/$(n).erl) endif list-templates: $(verbose) @echo Available templates: $(verbose) printf " %s\n" $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) # Copyright (c) 2014-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-c_src distclean-c_src-env # Configuration. C_SRC_DIR ?= $(CURDIR)/c_src C_SRC_ENV ?= $(C_SRC_DIR)/env.mk C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) C_SRC_TYPE ?= shared # System type and C compiler/flags. ifeq ($(PLATFORM),msys2) C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll else C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= C_SRC_OUTPUT_SHARED_EXTENSION ?= .so endif ifeq ($(C_SRC_TYPE),shared) C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) else C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) endif ifeq ($(PLATFORM),msys2) # We hardcode the compiler used on MSYS2. The default CC=cc does # not produce working code. The "gcc" MSYS2 package also doesn't. CC = /mingw64/bin/gcc export CC CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes CXXFLAGS ?= -O3 -finline-functions -Wall else ifeq ($(PLATFORM),darwin) CC ?= cc CFLAGS ?= -O3 -std=c99 -arch x86_64 -Wall -Wmissing-prototypes CXXFLAGS ?= -O3 -arch x86_64 -Wall LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress else ifeq ($(PLATFORM),freebsd) CC ?= cc CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes CXXFLAGS ?= -O3 -finline-functions -Wall else ifeq ($(PLATFORM),linux) CC ?= gcc CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes CXXFLAGS ?= -O3 -finline-functions -Wall endif ifneq ($(PLATFORM),msys2) CFLAGS += -fPIC CXXFLAGS += -fPIC endif CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei # Verbosity. c_verbose_0 = @echo " C " $(?F); c_verbose = $(c_verbose_$(V)) cpp_verbose_0 = @echo " CPP " $(?F); cpp_verbose = $(cpp_verbose_$(V)) link_verbose_0 = @echo " LD " $(@F); link_verbose = $(link_verbose_$(V)) # Targets. ifeq ($(wildcard $(C_SRC_DIR)),) else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) app:: app-c_src test-build:: app-c_src app-c_src: $(MAKE) -C $(C_SRC_DIR) clean:: $(MAKE) -C $(C_SRC_DIR) clean else ifeq ($(SOURCES),) SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) endif OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) $(C_SRC_OUTPUT_FILE): $(OBJECTS) $(verbose) mkdir -p priv/ $(link_verbose) $(CC) $(OBJECTS) \ $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ -o $(C_SRC_OUTPUT_FILE) $(OBJECTS): $(MAKEFILE_LIST) $(C_SRC_ENV) %.o: %.c $(COMPILE_C) $(OUTPUT_OPTION) $< %.o: %.cc $(COMPILE_CPP) $(OUTPUT_OPTION) $< %.o: %.C $(COMPILE_CPP) $(OUTPUT_OPTION) $< %.o: %.cpp $(COMPILE_CPP) $(OUTPUT_OPTION) $< clean:: clean-c_src clean-c_src: $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) endif ifneq ($(wildcard $(C_SRC_DIR)),) ERL_ERTS_DIR = $(shell $(ERL) -eval 'io:format("~s~n", [code:lib_dir(erts)]), halt().') $(C_SRC_ENV): $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ io_lib:format( \ \"# Generated by Erlang.mk. Edit at your own risk!~n~n\" \ \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ \"ERL_INTERFACE_LIB_DIR ?= ~s~n\" \ \"ERTS_DIR ?= $(ERL_ERTS_DIR)~n\", \ [code:root_dir(), erlang:system_info(version), \ code:lib_dir(erl_interface, include), \ code:lib_dir(erl_interface, lib)])), \ halt()." distclean:: distclean-c_src-env distclean-c_src-env: $(gen_verbose) rm -f $(C_SRC_ENV) -include $(C_SRC_ENV) ifneq ($(ERL_ERTS_DIR),$(ERTS_DIR)) $(shell rm -f $(C_SRC_ENV)) endif endif # Templates. define bs_c_nif #include "erl_nif.h" static int loads = 0; static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { /* Initialize private data. */ *priv_data = NULL; loads++; return 0; } static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) { /* Convert the private data to the new version. */ *priv_data = *old_priv_data; loads++; return 0; } static void unload(ErlNifEnv* env, void* priv_data) { if (loads == 1) { /* Destroy the private data. */ } loads--; } static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if (enif_is_atom(env, argv[0])) { return enif_make_tuple2(env, enif_make_atom(env, "hello"), argv[0]); } return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "badarg")); } static ErlNifFunc nif_funcs[] = { {"hello", 1, hello} }; ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) endef define bs_erl_nif -module($n). -export([hello/1]). -on_load(on_load/0). on_load() -> PrivDir = case code:priv_dir(?MODULE) of {error, _} -> AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), filename:join(AppPath, "priv"); Path -> Path end, erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). hello(_) -> erlang:nif_error({not_loaded, ?MODULE}). endef new-nif: ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) $(error Error: $(C_SRC_DIR)/$n.c already exists) endif ifneq ($(wildcard src/$n.erl),) $(error Error: src/$n.erl already exists) endif ifndef n $(error Usage: $(MAKE) new-nif n=NAME [in=APP]) endif ifdef in $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= else $(verbose) mkdir -p $(C_SRC_DIR) src/ $(verbose) $(call core_render,bs_c_nif,$(C_SRC_DIR)/$n.c) $(verbose) $(call core_render,bs_erl_nif,src/$n.erl) endif # Copyright (c) 2015-2017, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: ci ci-prepare ci-setup CI_OTP ?= CI_HIPE ?= CI_ERLLVM ?= ifeq ($(CI_VM),native) ERLC_OPTS += +native TEST_ERLC_OPTS += +native else ifeq ($(CI_VM),erllvm) ERLC_OPTS += +native +'{hipe, [to_llvm]}' TEST_ERLC_OPTS += +native +'{hipe, [to_llvm]}' endif ifeq ($(strip $(CI_OTP) $(CI_HIPE) $(CI_ERLLVM)),) ci:: else ci:: $(addprefix ci-,$(CI_OTP) $(addsuffix -native,$(CI_HIPE)) $(addsuffix -erllvm,$(CI_ERLLVM))) ci-prepare: $(addprefix $(KERL_INSTALL_DIR)/,$(CI_OTP) $(addsuffix -native,$(CI_HIPE))) ci-setup:: $(verbose) : ci-extra:: $(verbose) : ci_verbose_0 = @echo " CI " $(1); ci_verbose = $(ci_verbose_$(V)) define ci_target ci-$1: $(KERL_INSTALL_DIR)/$2 $(verbose) $(MAKE) --no-print-directory clean $(ci_verbose) \ PATH="$(KERL_INSTALL_DIR)/$2/bin:$(PATH)" \ CI_OTP_RELEASE="$1" \ CT_OPTS="-label $1" \ CI_VM="$3" \ $(MAKE) ci-setup tests $(verbose) $(MAKE) --no-print-directory ci-extra endef $(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp),$(otp),otp))) $(foreach otp,$(CI_HIPE),$(eval $(call ci_target,$(otp)-native,$(otp)-native,native))) $(foreach otp,$(CI_ERLLVM),$(eval $(call ci_target,$(otp)-erllvm,$(otp)-native,erllvm))) $(foreach otp,$(filter-out $(ERLANG_OTP),$(CI_OTP)),$(eval $(call kerl_otp_target,$(otp)))) $(foreach otp,$(filter-out $(ERLANG_HIPE),$(sort $(CI_HIPE) $(CI_ERLLLVM))),$(eval $(call kerl_hipe_target,$(otp)))) help:: $(verbose) printf "%s\n" "" \ "Continuous Integration targets:" \ " ci Run '$(MAKE) tests' on all configured Erlang versions." \ "" \ "The CI_OTP variable must be defined with the Erlang versions" \ "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" endif # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: ct apps-ct distclean-ct # Configuration. CT_OPTS ?= ifneq ($(wildcard $(TEST_DIR)),) ifndef CT_SUITES CT_SUITES := $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) endif endif CT_SUITES ?= CT_LOGS_DIR ?= $(CURDIR)/logs # Core targets. tests:: ct ifndef KEEP_LOGS distclean:: distclean-ct endif help:: $(verbose) printf "%s\n" "" \ "Common_test targets:" \ " ct Run all the common_test suites for this project" \ "" \ "All your common_test suites have their associated targets." \ "A suite named http_SUITE can be ran using the ct-http target." # Plugin-specific targets. CT_RUN = ct_run \ -no_auto_compile \ -noinput \ -pa $(CURDIR)/ebin $(TEST_DIR) \ -dir $(TEST_DIR) \ -logdir $(CT_LOGS_DIR) ifeq ($(CT_SUITES),) ct: $(if $(IS_APP)$(ROOT_DIR),,apps-ct) else # We do not run tests if we are in an apps/* with no test directory. ifneq ($(IS_APP)$(wildcard $(TEST_DIR)),1) ct: test-build $(if $(IS_APP)$(ROOT_DIR),,apps-ct) $(verbose) mkdir -p $(CT_LOGS_DIR) $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) endif endif ifneq ($(ALL_APPS_DIRS),) define ct_app_target apps-ct-$1: test-build $$(MAKE) -C $1 ct IS_APP=1 endef $(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) apps-ct: $(addprefix apps-ct-,$(ALL_APPS_DIRS)) endif ifdef t ifeq (,$(findstring :,$t)) CT_EXTRA = -group $t else t_words = $(subst :, ,$t) CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) endif else ifdef c CT_EXTRA = -case $c else CT_EXTRA = endif endif define ct_suite_target ct-$(1): test-build $(verbose) mkdir -p $(CT_LOGS_DIR) $(gen_verbose_esc) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) endef $(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) distclean-ct: $(gen_verbose) rm -rf $(CT_LOGS_DIR) # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: plt distclean-plt dialyze # Configuration. DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt export DIALYZER_PLT PLT_APPS ?= DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs DIALYZER_PLT_OPTS ?= # Core targets. check:: dialyze distclean:: distclean-plt help:: $(verbose) printf "%s\n" "" \ "Dialyzer targets:" \ " plt Build a PLT file for this project" \ " dialyze Analyze the project using Dialyzer" # Plugin-specific targets. define filter_opts.erl Opts = init:get_plain_arguments(), {Filtered, _} = lists:foldl(fun (O, {Os, true}) -> {[O|Os], false}; (O = "-D", {Os, _}) -> {[O|Os], true}; (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; (O = "-I", {Os, _}) -> {[O|Os], true}; (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; (O = "-pa", {Os, _}) -> {[O|Os], true}; (_, Acc) -> Acc end, {[], false}, Opts), io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), halt(). endef # DIALYZER_PLT is a variable understood directly by Dialyzer. # # We append the path to erts at the end of the PLT. This works # because the PLT file is in the external term format and the # function binary_to_term/1 ignores any trailing data. $(DIALYZER_PLT): deps app $(eval DEPS_LOG := $(shell test -f $(ERLANG_MK_TMP)/deps.log && \ while read p; do test -d $$p/ebin && echo $$p/ebin; done <$(ERLANG_MK_TMP)/deps.log)) $(verbose) dialyzer --build_plt $(DIALYZER_PLT_OPTS) --apps \ erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS_LOG) || test $$? -eq 2 $(verbose) $(ERL) -eval 'io:format("~n~s~n", [code:lib_dir(erts)]), halt().' >> $@ plt: $(DIALYZER_PLT) distclean-plt: $(gen_verbose) rm -f $(DIALYZER_PLT) ifneq ($(wildcard $(DIALYZER_PLT)),) dialyze: $(if $(filter --src,$(DIALYZER_DIRS)),,deps app) $(verbose) if ! tail -n1 $(DIALYZER_PLT) | \ grep -q "^`$(ERL) -eval 'io:format("~s", [code:lib_dir(erts)]), halt().'`$$"; then \ rm $(DIALYZER_PLT); \ $(MAKE) plt; \ fi else dialyze: $(DIALYZER_PLT) endif $(verbose) dialyzer --no_native `$(ERL) \ -eval "$(subst $(newline),,$(call escape_dquotes,$(call filter_opts.erl)))" \ -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) $(if $(wildcard ebin/),-pa ebin/) # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-edoc edoc # Configuration. EDOC_OPTS ?= EDOC_SRC_DIRS ?= EDOC_OUTPUT ?= doc define edoc.erl SrcPaths = lists:foldl(fun(P, Acc) -> filelib:wildcard(atom_to_list(P) ++ "/{src,c_src}") ++ Acc end, [], [$(call comma_list,$(patsubst %,'%',$(call core_native_path,$(EDOC_SRC_DIRS))))]), DefaultOpts = [{dir, "$(EDOC_OUTPUT)"}, {source_path, SrcPaths}, {subpackages, false}], edoc:application($(1), ".", [$(2)] ++ DefaultOpts), halt(0). endef # Core targets. ifneq ($(strip $(EDOC_SRC_DIRS)$(wildcard doc/overview.edoc)),) docs:: edoc endif distclean:: distclean-edoc # Plugin-specific targets. edoc: distclean-edoc doc-deps $(gen_verbose) $(call erlang,$(call edoc.erl,$(PROJECT),$(EDOC_OPTS))) distclean-edoc: $(gen_verbose) rm -f $(EDOC_OUTPUT)/*.css $(EDOC_OUTPUT)/*.html $(EDOC_OUTPUT)/*.png $(EDOC_OUTPUT)/edoc-info # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. # Configuration. DTL_FULL_PATH ?= DTL_PATH ?= templates/ DTL_PREFIX ?= DTL_SUFFIX ?= _dtl DTL_OPTS ?= # Verbosity. dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); dtl_verbose = $(dtl_verbose_$(V)) # Core targets. DTL_PATH := $(abspath $(DTL_PATH)) DTL_FILES := $(sort $(call core_find,$(DTL_PATH),*.dtl)) ifneq ($(DTL_FILES),) DTL_NAMES = $(addprefix $(DTL_PREFIX),$(addsuffix $(DTL_SUFFIX),$(DTL_FILES:$(DTL_PATH)/%.dtl=%))) DTL_MODULES = $(if $(DTL_FULL_PATH),$(subst /,_,$(DTL_NAMES)),$(notdir $(DTL_NAMES))) BEAM_FILES += $(addsuffix .beam,$(addprefix ebin/,$(DTL_MODULES))) ifneq ($(words $(DTL_FILES)),0) # Rebuild templates when the Makefile changes. $(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) | $(ERLANG_MK_TMP) $(verbose) if test -f $@; then \ touch $(DTL_FILES); \ fi $(verbose) touch $@ ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl endif define erlydtl_compile.erl [begin Module0 = case "$(strip $(DTL_FULL_PATH))" of "" -> filename:basename(F, ".dtl"); _ -> "$(call core_native_path,$(DTL_PATH))/" ++ F2 = filename:rootname(F, ".dtl"), re:replace(F2, "/", "_", [{return, list}, global]) end, Module = list_to_atom("$(DTL_PREFIX)" ++ string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors]) of ok -> ok; {ok, _} -> ok end end || F <- string:tokens("$(1)", " ")], halt(). endef ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ $(if $(strip $?),\ $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$(call core_native_path,$?)),\ -pa ebin/)) endif # Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2014, Dave Cottlehuber # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-escript escript escript-zip # Configuration. ESCRIPT_NAME ?= $(PROJECT) ESCRIPT_FILE ?= $(ESCRIPT_NAME) ESCRIPT_SHEBANG ?= /usr/bin/env escript ESCRIPT_COMMENT ?= This is an -*- erlang -*- file ESCRIPT_EMU_ARGS ?= -escript main $(ESCRIPT_NAME) ESCRIPT_ZIP ?= 7z a -tzip -mx=9 -mtc=off $(if $(filter-out 0,$(V)),,> /dev/null) ESCRIPT_ZIP_FILE ?= $(ERLANG_MK_TMP)/escript.zip # Core targets. distclean:: distclean-escript help:: $(verbose) printf "%s\n" "" \ "Escript targets:" \ " escript Build an executable escript archive" \ # Plugin-specific targets. escript-zip:: FULL=1 escript-zip:: deps app $(verbose) mkdir -p $(dir $(ESCRIPT_ZIP)) $(verbose) rm -f $(ESCRIPT_ZIP_FILE) $(gen_verbose) cd .. && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) $(PROJECT)/ebin/* ifneq ($(DEPS),) $(verbose) cd $(DEPS_DIR) && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) \ $(subst $(DEPS_DIR)/,,$(addsuffix /*,$(wildcard \ $(addsuffix /ebin,$(shell cat $(ERLANG_MK_TMP)/deps.log))))) endif escript:: escript-zip $(gen_verbose) printf "%s\n" \ "#!$(ESCRIPT_SHEBANG)" \ "%% $(ESCRIPT_COMMENT)" \ "%%! $(ESCRIPT_EMU_ARGS)" > $(ESCRIPT_FILE) $(verbose) cat $(ESCRIPT_ZIP_FILE) >> $(ESCRIPT_FILE) $(verbose) chmod +x $(ESCRIPT_FILE) distclean-escript: $(gen_verbose) rm -f $(ESCRIPT_FILE) # Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, Enrique Fernandez # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: eunit apps-eunit # Configuration EUNIT_OPTS ?= EUNIT_ERL_OPTS ?= # Core targets. tests:: eunit help:: $(verbose) printf "%s\n" "" \ "EUnit targets:" \ " eunit Run all the EUnit tests for this project" # Plugin-specific targets. define eunit.erl $(call cover.erl) CoverSetup(), case eunit:test($1, [$(EUNIT_OPTS)]) of ok -> ok; error -> halt(2) end, CoverExport("$(call core_native_path,$(COVER_DATA_DIR))/eunit.coverdata"), halt() endef EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(CURDIR)/ebin ifdef t ifeq (,$(findstring :,$(t))) eunit: test-build cover-data-dir $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) else eunit: test-build cover-data-dir $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) endif else EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') eunit: test-build $(if $(IS_APP)$(ROOT_DIR),,apps-eunit) cover-data-dir ifneq ($(wildcard src/ $(TEST_DIR)),) $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) endif ifneq ($(ALL_APPS_DIRS),) apps-eunit: test-build $(verbose) eunit_retcode=0 ; for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; \ [ $$? -ne 0 ] && eunit_retcode=1 ; done ; \ exit $$eunit_retcode endif endif # Copyright (c) 2015-2017, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. ifeq ($(filter proper,$(DEPS) $(TEST_DEPS)),proper) .PHONY: proper # Targets. tests:: proper define proper_check.erl $(call cover.erl) code:add_pathsa([ "$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)", "$(call core_native_path,$(TEST_DIR))"]), Module = fun(M) -> [true] =:= lists:usort([ case atom_to_list(F) of "prop_" ++ _ -> io:format("Testing ~p:~p/0~n", [M, F]), proper:quickcheck(M:F(), nocolors); _ -> true end || {F, 0} <- M:module_info(exports)]) end, try begin CoverSetup(), Res = case $(1) of all -> [true] =:= lists:usort([Module(M) || M <- [$(call comma_list,$(3))]]); module -> Module($(2)); function -> proper:quickcheck($(2), nocolors) end, CoverExport("$(COVER_DATA_DIR)/proper.coverdata"), Res end of true -> halt(0); _ -> halt(1) catch error:undef -> io:format("Undefined property or module?~n~p~n", [erlang:get_stacktrace()]), halt(0) end. endef ifdef t ifeq (,$(findstring :,$(t))) proper: test-build cover-data-dir $(verbose) $(call erlang,$(call proper_check.erl,module,$(t))) else proper: test-build cover-data-dir $(verbose) echo Testing $(t)/0 $(verbose) $(call erlang,$(call proper_check.erl,function,$(t)())) endif else proper: test-build cover-data-dir $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(wildcard ebin/*.beam) $(call core_find,$(TEST_DIR)/,*.beam)))))) $(gen_verbose) $(call erlang,$(call proper_check.erl,all,undefined,$(MODULES))) endif endif # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: relx-rel relx-relup distclean-relx-rel run # Configuration. RELX ?= $(ERLANG_MK_TMP)/relx RELX_CONFIG ?= $(CURDIR)/relx.config RELX_URL ?= https://erlang.mk/res/relx-v3.27.0 RELX_OPTS ?= RELX_OUTPUT_DIR ?= _rel RELX_REL_EXT ?= RELX_TAR ?= 1 ifdef SFX RELX_TAR = 1 endif ifeq ($(firstword $(RELX_OPTS)),-o) RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) else RELX_OPTS += -o $(RELX_OUTPUT_DIR) endif # Core targets. ifeq ($(IS_DEP),) ifneq ($(wildcard $(RELX_CONFIG)),) rel:: relx-rel relup:: relx-relup endif endif distclean:: distclean-relx-rel # Plugin-specific targets. $(RELX): | $(ERLANG_MK_TMP) $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) $(verbose) chmod +x $(RELX) relx-rel: $(RELX) rel-deps app $(verbose) $(RELX) $(if $(filter 1,$V),-V 3) -c $(RELX_CONFIG) $(RELX_OPTS) release $(verbose) $(MAKE) relx-post-rel ifeq ($(RELX_TAR),1) $(verbose) $(RELX) $(if $(filter 1,$V),-V 3) -c $(RELX_CONFIG) $(RELX_OPTS) tar endif relx-relup: $(RELX) rel-deps app $(verbose) $(RELX) $(if $(filter 1,$V),-V 3) -c $(RELX_CONFIG) $(RELX_OPTS) release $(MAKE) relx-post-rel $(verbose) $(RELX) $(if $(filter 1,$V),-V 3) -c $(RELX_CONFIG) $(RELX_OPTS) relup $(if $(filter 1,$(RELX_TAR)),tar) distclean-relx-rel: $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) # Default hooks. relx-post-rel:: $(verbose) : # Run target. ifeq ($(wildcard $(RELX_CONFIG)),) run:: else define get_relx_release.erl {ok, Config} = file:consult("$(call core_native_path,$(RELX_CONFIG))"), {release, {Name, Vsn0}, _} = lists:keyfind(release, 1, Config), Vsn = case Vsn0 of {cmd, Cmd} -> os:cmd(Cmd); semver -> ""; {semver, _} -> ""; VsnStr -> Vsn0 end, Extended = case lists:keyfind(extended_start_script, 1, Config) of {_, true} -> "1"; _ -> "" end, io:format("~s ~s ~s", [Name, Vsn, Extended]), halt(0). endef RELX_REL := $(shell $(call erlang,$(get_relx_release.erl))) RELX_REL_NAME := $(word 1,$(RELX_REL)) RELX_REL_VSN := $(word 2,$(RELX_REL)) RELX_REL_CMD := $(if $(word 3,$(RELX_REL)),console) ifeq ($(PLATFORM),msys2) RELX_REL_EXT := .cmd endif run:: all $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) $(RELX_REL_CMD) ifdef RELOAD rel:: $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) ping $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) \ eval "io:format(\"~p~n\", [c:lm()])" endif help:: $(verbose) printf "%s\n" "" \ "Relx targets:" \ " run Compile the project, build the release and run it" endif # Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, M Robert Martin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: shell # Configuration. SHELL_ERL ?= erl SHELL_PATHS ?= $(CURDIR)/ebin $(TEST_DIR) SHELL_OPTS ?= ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) # Core targets help:: $(verbose) printf "%s\n" "" \ "Shell targets:" \ " shell Run an erlang shell with SHELL_OPTS or reasonable default" # Plugin-specific targets. $(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) ifneq ($(SKIP_DEPS),) build-shell-deps: else build-shell-deps: $(ALL_SHELL_DEPS_DIRS) $(verbose) set -e; for dep in $(ALL_SHELL_DEPS_DIRS) ; do \ if [ -z "$(strip $(FULL))" ] && [ ! -L $$dep ] && [ -f $$dep/ebin/dep_built ]; then \ :; \ else \ $(MAKE) -C $$dep IS_DEP=1; \ if [ ! -L $$dep ] && [ -d $$dep/ebin ]; then touch $$dep/ebin/dep_built; fi; \ fi \ done endif shell:: build-shell-deps $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) # Copyright 2017, Stanislaw Klekot # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-sphinx sphinx # Configuration. SPHINX_BUILD ?= sphinx-build SPHINX_SOURCE ?= doc SPHINX_CONFDIR ?= SPHINX_FORMATS ?= html SPHINX_DOCTREES ?= $(ERLANG_MK_TMP)/sphinx.doctrees SPHINX_OPTS ?= #sphinx_html_opts = #sphinx_html_output = html #sphinx_man_opts = #sphinx_man_output = man #sphinx_latex_opts = #sphinx_latex_output = latex # Helpers. sphinx_build_0 = @echo " SPHINX" $1; $(SPHINX_BUILD) -N -q sphinx_build_1 = $(SPHINX_BUILD) -N sphinx_build_2 = set -x; $(SPHINX_BUILD) sphinx_build = $(sphinx_build_$(V)) define sphinx.build $(call sphinx_build,$1) -b $1 -d $(SPHINX_DOCTREES) $(if $(SPHINX_CONFDIR),-c $(SPHINX_CONFDIR)) $(SPHINX_OPTS) $(sphinx_$1_opts) -- $(SPHINX_SOURCE) $(call sphinx.output,$1) endef define sphinx.output $(if $(sphinx_$1_output),$(sphinx_$1_output),$1) endef # Targets. ifneq ($(wildcard $(if $(SPHINX_CONFDIR),$(SPHINX_CONFDIR),$(SPHINX_SOURCE))/conf.py),) docs:: sphinx distclean:: distclean-sphinx endif help:: $(verbose) printf "%s\n" "" \ "Sphinx targets:" \ " sphinx Generate Sphinx documentation." \ "" \ "ReST sources and 'conf.py' file are expected in directory pointed by" \ "SPHINX_SOURCE ('doc' by default). SPHINX_FORMATS lists formats to build (only" \ "'html' format is generated by default); target directory can be specified by" \ 'setting sphinx_$${format}_output, for example: sphinx_html_output = output/html' \ "Additional Sphinx options can be set in SPHINX_OPTS." # Plugin-specific targets. sphinx: $(foreach F,$(SPHINX_FORMATS),$(call sphinx.build,$F)) distclean-sphinx: $(gen_verbose) rm -rf $(filter-out $(SPHINX_SOURCE),$(foreach F,$(SPHINX_FORMATS),$(call sphinx.output,$F))) # Copyright (c) 2017, Jean-Sébastien Pédron # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: show-ERL_LIBS show-ERLC_OPTS show-TEST_ERLC_OPTS show-ERL_LIBS: @echo $(ERL_LIBS) show-ERLC_OPTS: @$(foreach opt,$(ERLC_OPTS) -pa ebin -I include,echo "$(opt)";) show-TEST_ERLC_OPTS: @$(foreach opt,$(TEST_ERLC_OPTS) -pa ebin -I include,echo "$(opt)";) # Copyright (c) 2015-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) .PHONY: triq # Targets. tests:: triq define triq_check.erl $(call cover.erl) code:add_pathsa([ "$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)", "$(call core_native_path,$(TEST_DIR))"]), try begin CoverSetup(), Res = case $(1) of all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); module -> triq:check($(2)); function -> triq:check($(2)) end, CoverExport("$(COVER_DATA_DIR)/triq.coverdata"), Res end of true -> halt(0); _ -> halt(1) catch error:undef -> io:format("Undefined property or module?~n~p~n", [erlang:get_stacktrace()]), halt(0) end. endef ifdef t ifeq (,$(findstring :,$(t))) triq: test-build cover-data-dir $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) else triq: test-build cover-data-dir $(verbose) echo Testing $(t)/0 $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) endif else triq: test-build cover-data-dir $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(wildcard ebin/*.beam) $(call core_find,$(TEST_DIR)/,*.beam)))))) $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) endif endif # Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Erlang Solutions Ltd. # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: xref distclean-xref # Configuration. ifeq ($(XREF_CONFIG),) XREFR_ARGS := else XREFR_ARGS := -c $(XREF_CONFIG) endif XREFR ?= $(CURDIR)/xrefr export XREFR XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/1.1.0/xrefr # Core targets. help:: $(verbose) printf '%s\n' '' \ 'Xref targets:' \ ' xref Run Xrefr using $$XREF_CONFIG as config file if defined' distclean:: distclean-xref # Plugin-specific targets. $(XREFR): $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) $(verbose) chmod +x $(XREFR) xref: deps app $(XREFR) $(gen_verbose) $(XREFR) $(XREFR_ARGS) distclean-xref: $(gen_verbose) rm -rf $(XREFR) # Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. COVER_REPORT_DIR ?= cover COVER_DATA_DIR ?= $(COVER_REPORT_DIR) ifdef COVER COVER_APPS ?= $(notdir $(ALL_APPS_DIRS)) COVER_DEPS ?= endif # Code coverage for Common Test. ifdef COVER ifdef CT_RUN ifneq ($(wildcard $(TEST_DIR)),) test-build:: $(TEST_DIR)/ct.cover.spec $(TEST_DIR)/ct.cover.spec: cover-data-dir $(gen_verbose) printf "%s\n" \ "{incl_app, '$(PROJECT)', details}." \ "{incl_dirs, '$(PROJECT)', [\"$(call core_native_path,$(CURDIR)/ebin)\" \ $(foreach a,$(COVER_APPS),$(comma) \"$(call core_native_path,$(APPS_DIR)/$a/ebin)\") \ $(foreach d,$(COVER_DEPS),$(comma) \"$(call core_native_path,$(DEPS_DIR)/$d/ebin)\")]}." \ '{export,"$(call core_native_path,$(abspath $(COVER_DATA_DIR))/ct.coverdata)"}.' > $@ CT_RUN += -cover $(TEST_DIR)/ct.cover.spec endif endif endif # Code coverage for other tools. ifdef COVER define cover.erl CoverSetup = fun() -> Dirs = ["$(call core_native_path,$(CURDIR)/ebin)" $(foreach a,$(COVER_APPS),$(comma) "$(call core_native_path,$(APPS_DIR)/$a/ebin)") $(foreach d,$(COVER_DEPS),$(comma) "$(call core_native_path,$(DEPS_DIR)/$d/ebin)")], [begin case filelib:is_dir(Dir) of false -> false; true -> case cover:compile_beam_directory(Dir) of {error, _} -> halt(1); _ -> true end end end || Dir <- Dirs] end, CoverExport = fun(Filename) -> cover:export(Filename) end, endef else define cover.erl CoverSetup = fun() -> ok end, CoverExport = fun(_) -> ok end, endef endif # Core targets ifdef COVER ifneq ($(COVER_REPORT_DIR),) tests:: $(verbose) $(MAKE) --no-print-directory cover-report endif cover-data-dir: | $(COVER_DATA_DIR) $(COVER_DATA_DIR): $(verbose) mkdir -p $(COVER_DATA_DIR) else cover-data-dir: endif clean:: coverdata-clean ifneq ($(COVER_REPORT_DIR),) distclean:: cover-report-clean endif help:: $(verbose) printf "%s\n" "" \ "Cover targets:" \ " cover-report Generate a HTML coverage report from previously collected" \ " cover data." \ " all.coverdata Merge all coverdata files into all.coverdata." \ "" \ "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ "target tests additionally generates a HTML coverage report from the combined" \ "coverdata files from each of these testing tools. HTML reports can be disabled" \ "by setting COVER_REPORT_DIR to empty." # Plugin specific targets COVERDATA = $(filter-out $(COVER_DATA_DIR)/all.coverdata,$(wildcard $(COVER_DATA_DIR)/*.coverdata)) .PHONY: coverdata-clean coverdata-clean: $(gen_verbose) rm -f $(COVER_DATA_DIR)/*.coverdata $(TEST_DIR)/ct.cover.spec # Merge all coverdata files into one. define cover_export.erl $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) cover:export("$(COVER_DATA_DIR)/$@"), halt(0). endef all.coverdata: $(COVERDATA) cover-data-dir $(gen_verbose) $(call erlang,$(cover_export.erl)) # These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to # empty if you want the coverdata files but not the HTML report. ifneq ($(COVER_REPORT_DIR),) .PHONY: cover-report-clean cover-report cover-report-clean: $(gen_verbose) rm -rf $(COVER_REPORT_DIR) ifneq ($(COVER_REPORT_DIR),$(COVER_DATA_DIR)) $(if $(shell ls -A $(COVER_DATA_DIR)/),,$(verbose) rmdir $(COVER_DATA_DIR)) endif ifeq ($(COVERDATA),) cover-report: else # Modules which include eunit.hrl always contain one line without coverage # because eunit defines test/0 which is never called. We compensate for this. EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ grep -H -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) define cover_report.erl $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) Ms = cover:imported_modules(), [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) ++ ".COVER.html", [html]) || M <- Ms], Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], EunitHrlMods = [$(EUNIT_HRL_MODS)], Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), TotalN = lists:sum([N || {_, {_, N}} <- Report1]), Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, TotalPerc = Perc(TotalY, TotalN), {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), io:format(F, "~n" "~n" "Coverage report~n" "~n", []), io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), io:format(F, "~n", []), [io:format(F, "" "~n", [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", io:format(F, "
ModuleCoverage
~p~p%
~n" "

Generated using ~s and erlang.mk on ~s.

~n" "", [How, Date]), halt(). endef cover-report: $(verbose) mkdir -p $(COVER_REPORT_DIR) $(gen_verbose) $(call erlang,$(cover_report.erl)) endif endif # ifneq ($(COVER_REPORT_DIR),) # Copyright (c) 2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: sfx ifdef RELX_REL ifdef SFX # Configuration. SFX_ARCHIVE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/$(RELX_REL_NAME)-$(RELX_REL_VSN).tar.gz SFX_OUTPUT_FILE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME).run # Core targets. rel:: sfx # Plugin-specific targets. define sfx_stub #!/bin/sh TMPDIR=`mktemp -d` ARCHIVE=`awk '/^__ARCHIVE_BELOW__$$/ {print NR + 1; exit 0;}' $$0` FILENAME=$$(basename $$0) REL=$${FILENAME%.*} tail -n+$$ARCHIVE $$0 | tar -xzf - -C $$TMPDIR $$TMPDIR/bin/$$REL console RET=$$? rm -rf $$TMPDIR exit $$RET __ARCHIVE_BELOW__ endef sfx: $(verbose) $(call core_render,sfx_stub,$(SFX_OUTPUT_FILE)) $(gen_verbose) cat $(SFX_ARCHIVE) >> $(SFX_OUTPUT_FILE) $(verbose) chmod +x $(SFX_OUTPUT_FILE) endif endif # Copyright (c) 2013-2017, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. # External plugins. DEP_PLUGINS ?= $(foreach p,$(DEP_PLUGINS),\ $(eval $(if $(findstring /,$p),\ $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ $(call core_dep_plugin,$p/plugins.mk,$p)))) help:: help-plugins help-plugins:: $(verbose) : # Copyright (c) 2013-2015, Loïc Hoguin # Copyright (c) 2015-2016, Jean-Sébastien Pédron # This file is part of erlang.mk and subject to the terms of the ISC License. # Fetch dependencies recursively (without building them). .PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ fetch-shell-deps .PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) ifneq ($(SKIP_DEPS),) $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(verbose) :> $@ else # By default, we fetch "normal" dependencies. They are also included no # matter the type of requested dependencies. # # $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). $(ERLANG_MK_RECURSIVE_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(LOCAL_DEPS_DIRS) $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) # Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of # dependencies with a single target. ifneq ($(filter doc,$(DEP_TYPES)),) $(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) endif ifneq ($(filter rel,$(DEP_TYPES)),) $(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) endif ifneq ($(filter test,$(DEP_TYPES)),) $(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) endif ifneq ($(filter shell,$(DEP_TYPES)),) $(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) endif ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps-$(shell echo $$PPID).log) $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): | $(ERLANG_MK_TMP) ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) endif $(verbose) set -e; for dep in $^ ; do \ if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk|.*ERLANG_MK_FILENAME.*)$$" \ $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ $(MAKE) -C $$dep fetch-deps \ IS_DEP=1 \ ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ fi \ fi \ done ifeq ($(IS_APP)$(IS_DEP),) $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | \ uniq > $(ERLANG_MK_RECURSIVE_TMP_LIST).sorted $(verbose) cmp -s $(ERLANG_MK_RECURSIVE_TMP_LIST).sorted $@ \ || mv $(ERLANG_MK_RECURSIVE_TMP_LIST).sorted $@ $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST).sorted $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) endif endif # ifneq ($(SKIP_DEPS),) # List dependencies recursively. .PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ list-shell-deps list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: $(verbose) cat $^ erlang-jose-1.10.1/LICENSE.md0000644000232200023220000000215513605433351015760 0ustar debalancedebalanceThe MIT License (MIT) ===================== Copyright (c) 2014-2019, Andrew Bennett Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.