Current section
Files
Jump to
Current section
Files
src/gose@key.erl
-module(gose@key).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gose/key.gleam").
-export([new_key/1, is_private_key/1, material/1, material_octet_secret/1, material_rsa/1, material_ec/1, material_eddsa/1, material_xdh/1, from_der/1, from_eddsa_bits/2, from_eddsa_public_bits/2, from_octet_bits/1, from_pem/1, from_xdh_bits/2, from_xdh_public_bits/2, generate_ec/1, generate_eddsa/1, generate_hmac_key/1, generate_enc_key/1, generate_aes_kw_key/1, generate_chacha20_kw_key/0, generate_rsa/1, generate_xdh/1, ec_public_key_from_coordinates/3, with_alg/2, with_kid/2, with_kid_bits/2, validate_key_use_ops/2, with_key_ops/2, with_key_use/2, alg/1, ec_curve/1, ec_public_key/1, ec_public_key_coordinates/1, eddsa_curve/1, eddsa_public_key/1, key_ops/1, key_type/1, key_use/1, kid/1, octet_key_size/1, rsa_public_key/1, xdh_curve/1, xdh_public_key/1, public_key/1, to_der/1, to_octet_bits/1, to_pem/1, build/5, validate_rfc8037_key_use_public/2]).
-export_type([key_use/0, key_op/0, alg/0, rsa_key_material/0, ec_key_material/0, eddsa_key_material/0, xdh_key_material/0, key_material/0, key_type/0, key/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Format-neutral key type for JOSE and COSE operations.\n"
"\n"
" Use `gose/jose/jwk` for JSON (JWK) serialization and `gose/cose/key`\n"
" for CBOR (COSE_Key) serialization.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import gose/key\n"
" import kryptos/ec\n"
"\n"
" // Generate an EC key and attach metadata\n"
" let k =\n"
" key.generate_ec(ec.P256)\n"
" |> key.with_kid(\"my-signing-key\")\n"
" ```\n"
"\n"
" ## Supported Key Types\n"
"\n"
" - Symmetric keys (octet sequences) for HMAC and direct encryption\n"
" - RSA keys for signing and encryption\n"
" - Elliptic Curve keys (P-256, P-384, P-521, secp256k1)\n"
" - EdDSA keys (Ed25519, Ed448) for signing\n"
" - XDH keys (X25519, X448) for key agreement\n"
).
-type key_use() :: signing | encrypting.
-type key_op() :: sign |
verify |
encrypt |
decrypt |
wrap_key |
unwrap_key |
derive_key |
derive_bits.
-type alg() :: {signing_alg, gose@algorithm:signing_alg()} |
{key_encryption_alg, gose@algorithm:key_encryption_alg()} |
{content_alg, gose@algorithm:content_alg()}.
-type rsa_key_material() :: {rsa_private,
kryptos@rsa:private_key(),
kryptos@rsa:public_key()} |
{rsa_public, kryptos@rsa:public_key()}.
-type ec_key_material() :: {ec_private,
kryptos@ec:private_key(),
kryptos@ec:public_key(),
kryptos@ec:curve()} |
{ec_public, kryptos@ec:public_key(), kryptos@ec:curve()}.
-type eddsa_key_material() :: {eddsa_private,
kryptos@eddsa:private_key(),
kryptos@eddsa:public_key(),
kryptos@eddsa:curve()} |
{eddsa_public, kryptos@eddsa:public_key(), kryptos@eddsa:curve()}.
-type xdh_key_material() :: {xdh_private,
kryptos@xdh:private_key(),
kryptos@xdh:public_key(),
kryptos@xdh:curve()} |
{xdh_public, kryptos@xdh:public_key(), kryptos@xdh:curve()}.
-type key_material() :: {octet_key, bitstring()} |
{rsa, rsa_key_material()} |
{ec, ec_key_material()} |
{eddsa, eddsa_key_material()} |
{xdh, xdh_key_material()}.
-type key_type() :: oct_key_type | rsa_key_type | ec_key_type | okp_key_type.
-opaque key(KSR) :: {key,
key_material(),
gleam@option:option(KSR),
gleam@option:option(key_use()),
gleam@option:option(list(key_op())),
gleam@option:option(alg())}.
-file("src/gose/key.gleam", 147).
?DOC(false).
-spec new_key(key_material()) -> key(any()).
new_key(Material) ->
{key, Material, none, none, none, none}.
-file("src/gose/key.gleam", 158).
?DOC(false).
-spec is_private_key(key(any())) -> boolean().
is_private_key(Key) ->
case erlang:element(2, Key) of
{octet_key, _} ->
true;
{rsa, {rsa_private, _, _}} ->
true;
{rsa, {rsa_public, _}} ->
false;
{ec, {ec_private, _, _, _}} ->
true;
{ec, {ec_public, _, _}} ->
false;
{eddsa, {eddsa_private, _, _, _}} ->
true;
{eddsa, {eddsa_public, _, _}} ->
false;
{xdh, {xdh_private, _, _, _}} ->
true;
{xdh, {xdh_public, _, _}} ->
false
end.
-file("src/gose/key.gleam", 174).
?DOC(false).
-spec material(key(any())) -> key_material().
material(Key) ->
erlang:element(2, Key).
-file("src/gose/key.gleam", 179).
?DOC(false).
-spec material_octet_secret(key_material()) -> {ok, bitstring()} |
{error, gose:gose_error()}.
material_octet_secret(Mat) ->
case Mat of
{octet_key, Secret} ->
{ok, Secret};
{rsa, _} ->
{error, {invalid_state, <<"expected octet key"/utf8>>}};
{ec, _} ->
{error, {invalid_state, <<"expected octet key"/utf8>>}};
{eddsa, _} ->
{error, {invalid_state, <<"expected octet key"/utf8>>}};
{xdh, _} ->
{error, {invalid_state, <<"expected octet key"/utf8>>}}
end.
-file("src/gose/key.gleam", 190).
?DOC(false).
-spec material_rsa(key_material()) -> {ok, rsa_key_material()} |
{error, gose:gose_error()}.
material_rsa(Mat) ->
case Mat of
{rsa, Rsa} ->
{ok, Rsa};
{octet_key, _} ->
{error, {invalid_state, <<"expected RSA key"/utf8>>}};
{ec, _} ->
{error, {invalid_state, <<"expected RSA key"/utf8>>}};
{eddsa, _} ->
{error, {invalid_state, <<"expected RSA key"/utf8>>}};
{xdh, _} ->
{error, {invalid_state, <<"expected RSA key"/utf8>>}}
end.
-file("src/gose/key.gleam", 199).
?DOC(false).
-spec material_ec(key_material()) -> {ok, ec_key_material()} |
{error, gose:gose_error()}.
material_ec(Mat) ->
case Mat of
{ec, Ec} ->
{ok, Ec};
{octet_key, _} ->
{error, {invalid_state, <<"expected EC key"/utf8>>}};
{rsa, _} ->
{error, {invalid_state, <<"expected EC key"/utf8>>}};
{eddsa, _} ->
{error, {invalid_state, <<"expected EC key"/utf8>>}};
{xdh, _} ->
{error, {invalid_state, <<"expected EC key"/utf8>>}}
end.
-file("src/gose/key.gleam", 208).
?DOC(false).
-spec material_eddsa(key_material()) -> {ok, eddsa_key_material()} |
{error, gose:gose_error()}.
material_eddsa(Mat) ->
case Mat of
{eddsa, Eddsa} ->
{ok, Eddsa};
{octet_key, _} ->
{error, {invalid_state, <<"expected EdDSA key"/utf8>>}};
{rsa, _} ->
{error, {invalid_state, <<"expected EdDSA key"/utf8>>}};
{ec, _} ->
{error, {invalid_state, <<"expected EdDSA key"/utf8>>}};
{xdh, _} ->
{error, {invalid_state, <<"expected EdDSA key"/utf8>>}}
end.
-file("src/gose/key.gleam", 219).
?DOC(false).
-spec material_xdh(key_material()) -> {ok, xdh_key_material()} |
{error, gose:gose_error()}.
material_xdh(Mat) ->
case Mat of
{xdh, Xdh} ->
{ok, Xdh};
{octet_key, _} ->
{error, {invalid_state, <<"expected XDH key"/utf8>>}};
{rsa, _} ->
{error, {invalid_state, <<"expected XDH key"/utf8>>}};
{ec, _} ->
{error, {invalid_state, <<"expected XDH key"/utf8>>}};
{eddsa, _} ->
{error, {invalid_state, <<"expected XDH key"/utf8>>}}
end.
-file("src/gose/key.gleam", 243).
-spec ec_private_key({kryptos@ec:private_key(), kryptos@ec:public_key()}) -> key(any()).
ec_private_key(Pair) ->
{Private, Public} = Pair,
Curve = kryptos_ffi:ec_private_key_curve(Private),
new_key({ec, {ec_private, Private, Public, Curve}}).
-file("src/gose/key.gleam", 249).
-spec ec_public_key_internal(kryptos@ec:public_key()) -> key(any()).
ec_public_key_internal(Public) ->
Curve = kryptos_ffi:ec_public_key_curve(Public),
new_key({ec, {ec_public, Public, Curve}}).
-file("src/gose/key.gleam", 254).
-spec eddsa_private_key(
{kryptos@eddsa:private_key(), kryptos@eddsa:public_key()}
) -> key(any()).
eddsa_private_key(Pair) ->
{Private, Public} = Pair,
Curve = kryptos_ffi:eddsa_private_key_curve(Private),
new_key({eddsa, {eddsa_private, Private, Public, Curve}}).
-file("src/gose/key.gleam", 260).
-spec eddsa_public_key_internal(kryptos@eddsa:public_key()) -> key(any()).
eddsa_public_key_internal(Public) ->
Curve = kryptos_ffi:eddsa_public_key_curve(Public),
new_key({eddsa, {eddsa_public, Public, Curve}}).
-file("src/gose/key.gleam", 265).
-spec rsa_private_key_internal(
{kryptos@rsa:private_key(), kryptos@rsa:public_key()}
) -> key(any()).
rsa_private_key_internal(Pair) ->
{Private, Public} = Pair,
new_key({rsa, {rsa_private, Private, Public}}).
-file("src/gose/key.gleam", 270).
-spec rsa_public_key_internal(kryptos@rsa:public_key()) -> key(any()).
rsa_public_key_internal(Public) ->
new_key({rsa, {rsa_public, Public}}).
-file("src/gose/key.gleam", 274).
-spec xdh_private_key({kryptos@xdh:private_key(), kryptos@xdh:public_key()}) -> key(any()).
xdh_private_key(Pair) ->
{Private, Public} = Pair,
Curve = kryptos_ffi:xdh_private_key_curve(Private),
new_key({xdh, {xdh_private, Private, Public, Curve}}).
-file("src/gose/key.gleam", 280).
-spec xdh_public_key_internal(kryptos@xdh:public_key()) -> key(any()).
xdh_public_key_internal(Public) ->
Curve = kryptos_ffi:xdh_public_key_curve(Public),
new_key({xdh, {xdh_public, Public, Curve}}).
-file("src/gose/key.gleam", 285).
-spec parse_ec_der(bitstring()) -> {ok, key(any())} | {error, nil}.
parse_ec_der(Der) ->
_pipe = kryptos_ffi:ec_import_private_key_der(Der),
_pipe@1 = gleam@result:map(_pipe, fun ec_private_key/1),
gleam@result:lazy_or(
_pipe@1,
fun() -> _pipe@2 = kryptos_ffi:ec_import_public_key_der(Der),
gleam@result:map(_pipe@2, fun ec_public_key_internal/1) end
).
-file("src/gose/key.gleam", 293).
-spec parse_eddsa_der(bitstring()) -> {ok, key(any())} | {error, nil}.
parse_eddsa_der(Der) ->
_pipe = kryptos_ffi:eddsa_import_private_key_der(Der),
_pipe@1 = gleam@result:map(_pipe, fun eddsa_private_key/1),
gleam@result:lazy_or(
_pipe@1,
fun() -> _pipe@2 = kryptos_ffi:eddsa_import_public_key_der(Der),
gleam@result:map(_pipe@2, fun eddsa_public_key_internal/1) end
).
-file("src/gose/key.gleam", 301).
-spec parse_rsa_der(bitstring()) -> {ok, key(any())} | {error, nil}.
parse_rsa_der(Der) ->
_pipe = kryptos_ffi:rsa_import_private_key_der(Der, pkcs8),
_pipe@1 = gleam@result:map(_pipe, fun rsa_private_key_internal/1),
_pipe@3 = gleam@result:lazy_or(
_pipe@1,
fun() -> _pipe@2 = kryptos_ffi:rsa_import_private_key_der(Der, pkcs1),
gleam@result:map(_pipe@2, fun rsa_private_key_internal/1) end
),
_pipe@5 = gleam@result:lazy_or(
_pipe@3,
fun() -> _pipe@4 = kryptos_ffi:rsa_import_public_key_der(Der, spki),
gleam@result:map(_pipe@4, fun rsa_public_key_internal/1) end
),
gleam@result:lazy_or(
_pipe@5,
fun() ->
_pipe@6 = kryptos_ffi:rsa_import_public_key_der(Der, rsa_public_key),
gleam@result:map(_pipe@6, fun rsa_public_key_internal/1)
end
).
-file("src/gose/key.gleam", 317).
-spec parse_xdh_der(bitstring()) -> {ok, key(any())} | {error, nil}.
parse_xdh_der(Der) ->
_pipe = kryptos_ffi:xdh_import_private_key_der(Der),
_pipe@1 = gleam@result:map(_pipe, fun xdh_private_key/1),
gleam@result:lazy_or(
_pipe@1,
fun() -> _pipe@2 = kryptos_ffi:xdh_import_public_key_der(Der),
gleam@result:map(_pipe@2, fun xdh_public_key_internal/1) end
).
-file("src/gose/key.gleam", 231).
?DOC(
" Create a key from DER-encoded data.\n"
"\n"
" Auto-detects key type (RSA, EC, EdDSA, XDH) and format (PKCS#1, PKCS#8, SPKI).\n"
" Supports both private and public keys.\n"
).
-spec from_der(bitstring()) -> {ok, key(any())} | {error, gose:gose_error()}.
from_der(Der) ->
_pipe = parse_rsa_der(Der),
_pipe@1 = gleam@result:lazy_or(_pipe, fun() -> parse_eddsa_der(Der) end),
_pipe@2 = gleam@result:lazy_or(_pipe@1, fun() -> parse_xdh_der(Der) end),
_pipe@3 = gleam@result:lazy_or(_pipe@2, fun() -> parse_ec_der(Der) end),
gleam@result:map_error(
_pipe@3,
fun(_) ->
{parse_error,
<<"invalid DER: not a recognized RSA, EC, EdDSA, or XDH key format"/utf8>>}
end
).
-file("src/gose/key.gleam", 329).
?DOC(
" Create an EdDSA key pair from raw private key bytes.\n"
"\n"
" The public key is derived from the private key.\n"
" This is the inverse of `to_octet_bits` for EdDSA private keys.\n"
).
-spec from_eddsa_bits(kryptos@eddsa:curve(), bitstring()) -> {ok, key(any())} |
{error, gose:gose_error()}.
from_eddsa_bits(Curve, Private_bits) ->
_pipe = kryptos_ffi:eddsa_private_key_from_bytes(Curve, Private_bits),
_pipe@1 = gleam@result:map(
_pipe,
fun(Pair) ->
{Private, Public} = Pair,
new_key({eddsa, {eddsa_private, Private, Public, Curve}})
end
),
gleam@result:replace_error(
_pipe@1,
{parse_error, <<"invalid EdDSA private key bits"/utf8>>}
).
-file("src/gose/key.gleam", 344).
?DOC(
" Create an EdDSA public key from raw bytes.\n"
"\n"
" This is the inverse of `to_octet_bits` for EdDSA public keys.\n"
).
-spec from_eddsa_public_bits(kryptos@eddsa:curve(), bitstring()) -> {ok,
key(any())} |
{error, gose:gose_error()}.
from_eddsa_public_bits(Curve, Public_bits) ->
_pipe = kryptos_ffi:eddsa_public_key_from_bytes(Curve, Public_bits),
_pipe@1 = gleam@result:map(
_pipe,
fun(Public) -> new_key({eddsa, {eddsa_public, Public, Curve}}) end
),
gleam@result:replace_error(
_pipe@1,
{parse_error, <<"invalid EdDSA public key bits"/utf8>>}
).
-file("src/gose/key.gleam", 364).
?DOC(
" Create a symmetric key from raw bytes.\n"
"\n"
" Used for HMAC signing (HS256/384/512) and direct encryption.\n"
" Returns an error if the secret is empty.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let secret = crypto.random_bytes(32)\n"
" let assert Ok(key) = key.from_octet_bits(secret)\n"
" ```\n"
).
-spec from_octet_bits(bitstring()) -> {ok, key(any())} |
{error, gose:gose_error()}.
from_octet_bits(Secret) ->
case erlang:byte_size(Secret) of
0 ->
{error, {invalid_state, <<"oct key must not be empty"/utf8>>}};
_ ->
{ok, new_key({octet_key, Secret})}
end.
-file("src/gose/key.gleam", 387).
-spec parse_ec_pem(binary()) -> {ok, key(any())} | {error, nil}.
parse_ec_pem(Pem) ->
_pipe = kryptos_ffi:ec_import_private_key_pem(Pem),
_pipe@1 = gleam@result:map(_pipe, fun ec_private_key/1),
gleam@result:lazy_or(
_pipe@1,
fun() -> _pipe@2 = kryptos_ffi:ec_import_public_key_pem(Pem),
gleam@result:map(_pipe@2, fun ec_public_key_internal/1) end
).
-file("src/gose/key.gleam", 395).
-spec parse_eddsa_pem(binary()) -> {ok, key(any())} | {error, nil}.
parse_eddsa_pem(Pem) ->
_pipe = kryptos_ffi:eddsa_import_private_key_pem(Pem),
_pipe@1 = gleam@result:map(_pipe, fun eddsa_private_key/1),
gleam@result:lazy_or(
_pipe@1,
fun() -> _pipe@2 = kryptos_ffi:eddsa_import_public_key_pem(Pem),
gleam@result:map(_pipe@2, fun eddsa_public_key_internal/1) end
).
-file("src/gose/key.gleam", 403).
-spec parse_rsa_pem(binary()) -> {ok, key(any())} | {error, nil}.
parse_rsa_pem(Pem) ->
_pipe = kryptos_ffi:rsa_import_private_key_pem(Pem, pkcs8),
_pipe@1 = gleam@result:map(_pipe, fun rsa_private_key_internal/1),
_pipe@3 = gleam@result:lazy_or(
_pipe@1,
fun() -> _pipe@2 = kryptos_ffi:rsa_import_private_key_pem(Pem, pkcs1),
gleam@result:map(_pipe@2, fun rsa_private_key_internal/1) end
),
_pipe@5 = gleam@result:lazy_or(
_pipe@3,
fun() -> _pipe@4 = kryptos_ffi:rsa_import_public_key_pem(Pem, spki),
gleam@result:map(_pipe@4, fun rsa_public_key_internal/1) end
),
gleam@result:lazy_or(
_pipe@5,
fun() ->
_pipe@6 = kryptos_ffi:rsa_import_public_key_pem(Pem, rsa_public_key),
gleam@result:map(_pipe@6, fun rsa_public_key_internal/1)
end
).
-file("src/gose/key.gleam", 419).
-spec parse_xdh_pem(binary()) -> {ok, key(any())} | {error, nil}.
parse_xdh_pem(Pem) ->
_pipe = kryptos_ffi:xdh_import_private_key_pem(Pem),
_pipe@1 = gleam@result:map(_pipe, fun xdh_private_key/1),
gleam@result:lazy_or(
_pipe@1,
fun() -> _pipe@2 = kryptos_ffi:xdh_import_public_key_pem(Pem),
gleam@result:map(_pipe@2, fun xdh_public_key_internal/1) end
).
-file("src/gose/key.gleam", 375).
?DOC(
" Create a key from PEM-encoded data.\n"
"\n"
" Auto-detects key type (RSA, EC, EdDSA, XDH) and format (PKCS#1, PKCS#8, SPKI).\n"
" Supports both private and public keys.\n"
).
-spec from_pem(binary()) -> {ok, key(any())} | {error, gose:gose_error()}.
from_pem(Pem) ->
_pipe = parse_rsa_pem(Pem),
_pipe@1 = gleam@result:lazy_or(_pipe, fun() -> parse_eddsa_pem(Pem) end),
_pipe@2 = gleam@result:lazy_or(_pipe@1, fun() -> parse_xdh_pem(Pem) end),
_pipe@3 = gleam@result:lazy_or(_pipe@2, fun() -> parse_ec_pem(Pem) end),
gleam@result:map_error(
_pipe@3,
fun(_) ->
{parse_error,
<<"invalid PEM: not a recognized RSA, EC, EdDSA, or XDH key format"/utf8>>}
end
).
-file("src/gose/key.gleam", 431).
?DOC(
" Create an XDH key pair from raw private key bytes.\n"
"\n"
" The public key is derived from the private key.\n"
" This is the inverse of `to_octet_bits` for XDH private keys.\n"
).
-spec from_xdh_bits(kryptos@xdh:curve(), bitstring()) -> {ok, key(any())} |
{error, gose:gose_error()}.
from_xdh_bits(Curve, Private_bits) ->
_pipe = kryptos_ffi:xdh_private_key_from_bytes(Curve, Private_bits),
_pipe@1 = gleam@result:map(
_pipe,
fun(Pair) ->
{Private, Public} = Pair,
new_key({xdh, {xdh_private, Private, Public, Curve}})
end
),
gleam@result:replace_error(
_pipe@1,
{parse_error, <<"invalid XDH private key bits"/utf8>>}
).
-file("src/gose/key.gleam", 446).
?DOC(
" Create an XDH public key from raw bytes.\n"
"\n"
" This is the inverse of `to_octet_bits` for XDH public keys.\n"
).
-spec from_xdh_public_bits(kryptos@xdh:curve(), bitstring()) -> {ok, key(any())} |
{error, gose:gose_error()}.
from_xdh_public_bits(Curve, Public_bits) ->
_pipe = kryptos_ffi:xdh_public_key_from_bytes(Curve, Public_bits),
_pipe@1 = gleam@result:map(
_pipe,
fun(Public) -> new_key({xdh, {xdh_public, Public, Curve}}) end
),
gleam@result:replace_error(
_pipe@1,
{parse_error, <<"invalid XDH public key bits"/utf8>>}
).
-file("src/gose/key.gleam", 458).
?DOC(
" Generate a new EC key pair for the given curve.\n"
"\n"
" Supported curves: P256, P384, P521, Secp256k1.\n"
).
-spec generate_ec(kryptos@ec:curve()) -> key(any()).
generate_ec(Curve) ->
{Private, Public} = kryptos_ffi:ec_generate_key_pair(Curve),
new_key({ec, {ec_private, Private, Public, Curve}}).
-file("src/gose/key.gleam", 466).
?DOC(
" Generate a new EdDSA key pair for the given curve.\n"
"\n"
" Supported curves: Ed25519, Ed448.\n"
).
-spec generate_eddsa(kryptos@eddsa:curve()) -> key(any()).
generate_eddsa(Curve) ->
{Private, Public} = kryptos_ffi:eddsa_generate_key_pair(Curve),
new_key({eddsa, {eddsa_private, Private, Public, Curve}}).
-file("src/gose/key.gleam", 477).
?DOC(
" Generate a symmetric key for HMAC signing.\n"
"\n"
" The key size is derived from the algorithm:\n"
" - `HmacSha256` → 32 bytes\n"
" - `HmacSha384` → 48 bytes\n"
" - `HmacSha512` → 64 bytes\n"
).
-spec generate_hmac_key(gose@algorithm:hmac_alg()) -> key(any()).
generate_hmac_key(Alg) ->
Size = gose@algorithm:hmac_alg_key_size(Alg),
Secret = kryptos_ffi:random_bytes(Size),
new_key({octet_key, Secret}).
-file("src/gose/key.gleam", 494).
?DOC(
" Generate a symmetric key for JWE content encryption.\n"
"\n"
" The key size is derived from the encryption algorithm:\n"
" - `AesGcm(Aes128)` → 16 bytes\n"
" - `AesGcm(Aes192)` → 24 bytes\n"
" - `AesGcm(Aes256)` → 32 bytes\n"
" - `AesCbcHmac(Aes128)` → 32 bytes (16 + 16 for MAC)\n"
" - `AesCbcHmac(Aes192)` → 48 bytes (24 + 24 for MAC)\n"
" - `AesCbcHmac(Aes256)` → 64 bytes (32 + 32 for MAC)\n"
" - `ChaCha20Poly1305` → 32 bytes\n"
" - `XChaCha20Poly1305` → 32 bytes\n"
).
-spec generate_enc_key(gose@algorithm:content_alg()) -> key(any()).
generate_enc_key(Enc) ->
Size = gose@algorithm:content_alg_key_size(Enc),
Secret = kryptos_ffi:random_bytes(Size),
new_key({octet_key, Secret}).
-file("src/gose/key.gleam", 506).
?DOC(
" Generate a symmetric key for AES Key Wrap.\n"
"\n"
" The key size is derived from the AES variant:\n"
" - `Aes128` → 16 bytes\n"
" - `Aes192` → 24 bytes\n"
" - `Aes256` → 32 bytes\n"
).
-spec generate_aes_kw_key(gose@algorithm:aes_key_size()) -> key(any()).
generate_aes_kw_key(Size) ->
Byte_count = gose@algorithm:aes_key_size(Size),
Secret = kryptos_ffi:random_bytes(Byte_count),
new_key({octet_key, Secret}).
-file("src/gose/key.gleam", 515).
?DOC(
" Generate a symmetric key for ChaCha20-Poly1305 Key Wrap (C20PKW / XC20PKW).\n"
"\n"
" Always generates a 32-byte key, as both ChaCha20 and XChaCha20 use 256-bit keys.\n"
).
-spec generate_chacha20_kw_key() -> key(any()).
generate_chacha20_kw_key() ->
Secret = kryptos_ffi:random_bytes(32),
new_key({octet_key, Secret}).
-file("src/gose/key.gleam", 523).
?DOC(
" Generate a new RSA key pair with the given key size in bits.\n"
" Common sizes are 2048, 3072, and 4096. Keys smaller than 2048\n"
" bits are not recommended for security.\n"
).
-spec generate_rsa(integer()) -> {ok, key(any())} | {error, gose:gose_error()}.
generate_rsa(Bits) ->
case kryptos@rsa:generate_key_pair(Bits) of
{ok, {Private, Public}} ->
{ok, new_key({rsa, {rsa_private, Private, Public}})};
{error, _} ->
{error, {crypto_error, <<"RSA key generation failed"/utf8>>}}
end.
-file("src/gose/key.gleam", 534).
?DOC(
" Generate a new XDH key pair for key agreement.\n"
"\n"
" Supported curves: X25519, X448.\n"
).
-spec generate_xdh(kryptos@xdh:curve()) -> key(any()).
generate_xdh(Curve) ->
{Private, Public} = kryptos_ffi:xdh_generate_key_pair(Curve),
new_key({xdh, {xdh_private, Private, Public, Curve}}).
-file("src/gose/key.gleam", 540).
?DOC(" Create an EC public key from curve and x,y coordinates (big-endian bytes).\n").
-spec ec_public_key_from_coordinates(
kryptos@ec:curve(),
bitstring(),
bitstring()
) -> {ok, key(any())} | {error, gose:gose_error()}.
ec_public_key_from_coordinates(Curve, X, Y) ->
_pipe = gose@internal@utils:ec_public_key_from_coordinates(Curve, X, Y),
gleam@result:map(
_pipe,
fun(Public) -> new_key({ec, {ec_public, Public, Curve}}) end
).
-file("src/gose/key.gleam", 550).
?DOC(" Set the algorithm (`alg`) metadata parameter on a key.\n").
-spec with_alg(key(KXC), alg()) -> key(KXC).
with_alg(Key, Alg) ->
{key,
erlang:element(2, Key),
erlang:element(3, Key),
erlang:element(4, Key),
erlang:element(5, Key),
{some, Alg}}.
-file("src/gose/key.gleam", 597).
?DOC(
" Validate key use against RFC 8037 curve restrictions.\n"
" - EdDSA keys (Ed25519/Ed448): only `sig` allowed\n"
" - XDH keys (X25519/X448): only `enc` allowed\n"
).
-spec validate_rfc8037_key_use(key_material(), gleam@option:option(key_use())) -> {ok,
nil} |
{error, gose:gose_error()}.
validate_rfc8037_key_use(Material, Use_) ->
case {Material, Use_} of
{{eddsa, _}, {some, encrypting}} ->
{error,
{invalid_state,
<<"EdDSA keys (Ed25519/Ed448) cannot be used for encryption"/utf8>>}};
{{xdh, _}, {some, signing}} ->
{error,
{invalid_state,
<<"XDH keys (X25519/X448) cannot be used for signing"/utf8>>}};
{_, _} ->
{ok, nil}
end.
-file("src/gose/key.gleam", 615).
?DOC(" Set the key ID (`kid`) metadata parameter on a key.\n").
-spec with_kid(key(any()), binary()) -> key(binary()).
with_kid(Key, Kid) ->
{key,
erlang:element(2, Key),
{some, Kid},
erlang:element(4, Key),
erlang:element(5, Key),
erlang:element(6, Key)}.
-file("src/gose/key.gleam", 623).
?DOC(
" Set the key ID (`kid`) metadata parameter on a key using raw bytes.\n"
"\n"
" In COSE (RFC 9052), kid is a bstr that may contain arbitrary bytes.\n"
" For JWK interoperability where kid is a JSON string, use `with_kid`.\n"
).
-spec with_kid_bits(key(any()), bitstring()) -> key(bitstring()).
with_kid_bits(Key, Kid) ->
{key,
erlang:element(2, Key),
{some, Kid},
erlang:element(4, Key),
erlang:element(5, Key),
erlang:element(6, Key)}.
-file("src/gose/key.gleam", 627).
-spec is_signing_op(key_op()) -> boolean().
is_signing_op(Op) ->
case Op of
sign ->
true;
verify ->
true;
encrypt ->
false;
decrypt ->
false;
wrap_key ->
false;
unwrap_key ->
false;
derive_key ->
false;
derive_bits ->
false
end.
-file("src/gose/key.gleam", 634).
-spec is_encrypting_op(key_op()) -> boolean().
is_encrypting_op(Op) ->
case Op of
encrypt ->
true;
decrypt ->
true;
wrap_key ->
true;
unwrap_key ->
true;
derive_key ->
true;
derive_bits ->
true;
sign ->
false;
verify ->
false
end.
-file("src/gose/key.gleam", 642).
?DOC(false).
-spec validate_key_use_ops(
gleam@option:option(key_use()),
gleam@option:option(list(key_op()))
) -> {ok, nil} | {error, gose:gose_error()}.
validate_key_use_ops(Key_use, Key_ops) ->
case {Key_use, Key_ops} of
{none, _} ->
{ok, nil};
{_, none} ->
{ok, nil};
{{some, signing}, {some, Ops}} ->
case gleam@list:all(Ops, fun is_signing_op/1) of
true ->
{ok, nil};
false ->
{error,
{invalid_state,
<<"key_ops incompatible with use=sig"/utf8>>}}
end;
{{some, encrypting}, {some, Ops@1}} ->
case gleam@list:all(Ops@1, fun is_encrypting_op/1) of
true ->
{ok, nil};
false ->
{error,
{invalid_state,
<<"key_ops incompatible with use=enc"/utf8>>}}
end
end.
-file("src/gose/key.gleam", 562).
?DOC(
" Set the key operations parameter.\n"
"\n"
" Per RFC 7517, the values should be consistent with `key_use` if both are present:\n"
" - `Signing` use implies `Sign` and/or `Verify` operations\n"
" - `Encrypting` use implies `Encrypt`, `Decrypt`, `WrapKey`, `UnwrapKey`, `DeriveKey`, `DeriveBits`\n"
"\n"
" Returns an error if the list is empty, contains duplicates, or is\n"
" incompatible with the key's existing `key_use`.\n"
).
-spec with_key_ops(key(KXF), list(key_op())) -> {ok, key(KXF)} |
{error, gose:gose_error()}.
with_key_ops(Key, Ops) ->
case Ops of
[] ->
{error, {invalid_state, <<"key_ops must not be empty"/utf8>>}};
_ ->
gleam@bool:guard(
gleam@list:unique(Ops) /= Ops,
{error,
{invalid_state,
<<"key_ops must not contain duplicates"/utf8>>}},
fun() ->
_pipe = validate_key_use_ops(
erlang:element(4, Key),
{some, Ops}
),
gleam@result:replace(
_pipe,
{key,
erlang:element(2, Key),
erlang:element(3, Key),
erlang:element(4, Key),
{some, Ops},
erlang:element(6, Key)}
)
end
)
end.
-file("src/gose/key.gleam", 585).
?DOC(
" Set the public key use parameter.\n"
"\n"
" Returns an error if the key already has `key_ops` that are incompatible with\n"
" the specified use, or if the use is incompatible with the key type per RFC\n"
" 8037 (EdDSA keys can only be used for signing, XDH keys can only be used for\n"
" encryption).\n"
).
-spec with_key_use(key(KXL), key_use()) -> {ok, key(KXL)} |
{error, gose:gose_error()}.
with_key_use(Key, Use_) ->
gleam@result:'try'(
validate_key_use_ops({some, Use_}, erlang:element(5, Key)),
fun(_) ->
gleam@result:'try'(
validate_rfc8037_key_use(erlang:element(2, Key), {some, Use_}),
fun(_) ->
{ok,
{key,
erlang:element(2, Key),
erlang:element(3, Key),
{some, Use_},
erlang:element(5, Key),
erlang:element(6, Key)}}
end
)
end
).
-file("src/gose/key.gleam", 662).
?DOC(" Get the algorithm (`alg`) parameter.\n").
-spec alg(key(any())) -> {ok, alg()} | {error, nil}.
alg(Key) ->
gleam@option:to_result(erlang:element(6, Key), nil).
-file("src/gose/key.gleam", 669).
?DOC(
" Get the curve used by an EC key.\n"
"\n"
" Returns an error if the key is not an EC key.\n"
).
-spec ec_curve(key(any())) -> {ok, kryptos@ec:curve()} |
{error, gose:gose_error()}.
ec_curve(Key) ->
_pipe = material_ec(erlang:element(2, Key)),
gleam@result:map(_pipe, fun(Ec) -> case Ec of
{ec_private, _, _, Curve} ->
Curve;
{ec_public, _, Curve} ->
Curve
end end).
-file("src/gose/key.gleam", 684).
?DOC(
" Extract the EC public key.\n"
"\n"
" Works with both EC private keys (extracts the public component)\n"
" and EC public keys.\n"
"\n"
" Returns an error if the key is not an EC key.\n"
).
-spec ec_public_key(key(any())) -> {ok, kryptos@ec:public_key()} |
{error, gose:gose_error()}.
ec_public_key(Key) ->
_pipe = material_ec(erlang:element(2, Key)),
gleam@result:map(_pipe, fun(Ec) -> case Ec of
{ec_private, _, Public, _} ->
Public;
{ec_public, K, _} ->
K
end end).
-file("src/gose/key.gleam", 700).
?DOC(
" Get the x and y coordinates from an EC public key.\n"
"\n"
" The coordinates are returned as raw big-endian bytes, padded to\n"
" the coordinate size for the curve.\n"
"\n"
" Returns an error if the key is not an EC key.\n"
).
-spec ec_public_key_coordinates(key(any())) -> {ok, {bitstring(), bitstring()}} |
{error, gose:gose_error()}.
ec_public_key_coordinates(Key) ->
gleam@result:'try'(
ec_public_key(Key),
fun(Public) ->
gleam@result:'try'(
ec_curve(Key),
fun(Curve) ->
gose@internal@utils:ec_public_key_coordinates(Public, Curve)
end
)
end
).
-file("src/gose/key.gleam", 711).
?DOC(
" Get the curve used by an EdDSA key.\n"
"\n"
" Returns an error if the key is not an EdDSA key.\n"
).
-spec eddsa_curve(key(any())) -> {ok, kryptos@eddsa:curve()} |
{error, gose:gose_error()}.
eddsa_curve(Key) ->
_pipe = material_eddsa(erlang:element(2, Key)),
gleam@result:map(_pipe, fun(Eddsa) -> case Eddsa of
{eddsa_private, _, _, Curve} ->
Curve;
{eddsa_public, _, Curve} ->
Curve
end end).
-file("src/gose/key.gleam", 726).
?DOC(
" Extract the EdDSA public key.\n"
"\n"
" Works with both EdDSA private keys (extracts the public component)\n"
" and EdDSA public keys.\n"
"\n"
" Returns an error if the key is not an EdDSA key.\n"
).
-spec eddsa_public_key(key(any())) -> {ok, kryptos@eddsa:public_key()} |
{error, gose:gose_error()}.
eddsa_public_key(Key) ->
_pipe = material_eddsa(erlang:element(2, Key)),
gleam@result:map(_pipe, fun(Eddsa) -> case Eddsa of
{eddsa_private, _, Public, _} ->
Public;
{eddsa_public, K, _} ->
K
end end).
-file("src/gose/key.gleam", 739).
?DOC(" Get the key operations parameter.\n").
-spec key_ops(key(any())) -> {ok, list(key_op())} | {error, nil}.
key_ops(Key) ->
gleam@option:to_result(erlang:element(5, Key), nil).
-file("src/gose/key.gleam", 744).
?DOC(" Get the key type (kty) for this key.\n").
-spec key_type(key(any())) -> key_type().
key_type(Key) ->
case erlang:element(2, Key) of
{octet_key, _} ->
oct_key_type;
{rsa, _} ->
rsa_key_type;
{ec, _} ->
ec_key_type;
{eddsa, _} ->
okp_key_type;
{xdh, _} ->
okp_key_type
end.
-file("src/gose/key.gleam", 754).
?DOC(" Get the public key use parameter.\n").
-spec key_use(key(any())) -> {ok, key_use()} | {error, nil}.
key_use(Key) ->
gleam@option:to_result(erlang:element(4, Key), nil).
-file("src/gose/key.gleam", 763).
?DOC(
" Get the key ID (kid) parameter.\n"
"\n"
" The return type depends on the key's kid type parameter:\n"
" - `Key(String)` (from JWK) → `Result(String, Nil)`\n"
" - `Key(BitArray)` (from COSE) → `Result(BitArray, Nil)`\n"
).
-spec kid(key(KZN)) -> {ok, KZN} | {error, nil}.
kid(Key) ->
gleam@option:to_result(erlang:element(3, Key), nil).
-file("src/gose/key.gleam", 770).
?DOC(
" Get the size of an octet (symmetric) key in bytes.\n"
"\n"
" Returns an error if the key is not an octet key.\n"
).
-spec octet_key_size(key(any())) -> {ok, integer()} | {error, gose:gose_error()}.
octet_key_size(Key) ->
case material_octet_secret(erlang:element(2, Key)) of
{ok, Secret} ->
{ok, erlang:byte_size(Secret)};
{error, _} ->
{error, {invalid_state, <<"key is not an octet key"/utf8>>}}
end.
-file("src/gose/key.gleam", 783).
?DOC(
" Extract the RSA public key.\n"
"\n"
" Works with both RSA private keys (extracts the public component)\n"
" and RSA public keys.\n"
"\n"
" Returns an error if the key is not an RSA key.\n"
).
-spec rsa_public_key(key(any())) -> {ok, kryptos@rsa:public_key()} |
{error, gose:gose_error()}.
rsa_public_key(Key) ->
_pipe = material_rsa(erlang:element(2, Key)),
gleam@result:map(_pipe, fun(Rsa) -> case Rsa of
{rsa_private, _, Public} ->
Public;
{rsa_public, K} ->
K
end end).
-file("src/gose/key.gleam", 796).
?DOC(
" Get the curve used by an XDH key.\n"
"\n"
" Returns an error if the key is not an XDH key.\n"
).
-spec xdh_curve(key(any())) -> {ok, kryptos@xdh:curve()} |
{error, gose:gose_error()}.
xdh_curve(Key) ->
_pipe = material_xdh(erlang:element(2, Key)),
gleam@result:map(_pipe, fun(Xdh) -> case Xdh of
{xdh_private, _, _, Curve} ->
Curve;
{xdh_public, _, Curve} ->
Curve
end end).
-file("src/gose/key.gleam", 811).
?DOC(
" Extract the XDH public key (X25519/X448).\n"
"\n"
" Works with both XDH private keys (extracts the public component)\n"
" and XDH public keys.\n"
"\n"
" Returns an error if the key is not an XDH key.\n"
).
-spec xdh_public_key(key(any())) -> {ok, kryptos@xdh:public_key()} |
{error, gose:gose_error()}.
xdh_public_key(Key) ->
_pipe = material_xdh(erlang:element(2, Key)),
gleam@result:map(_pipe, fun(Xdh) -> case Xdh of
{xdh_private, _, Public, _} ->
Public;
{xdh_public, K, _} ->
K
end end).
-file("src/gose/key.gleam", 887).
-spec map_public_key_op(key_op()) -> {ok, key_op()} | {error, nil}.
map_public_key_op(Op) ->
case Op of
sign ->
{ok, verify};
decrypt ->
{error, nil};
unwrap_key ->
{error, nil};
verify ->
{ok, Op};
encrypt ->
{ok, Op};
wrap_key ->
{ok, Op};
derive_key ->
{ok, Op};
derive_bits ->
{ok, Op}
end.
-file("src/gose/key.gleam", 880).
-spec filter_public_key_ops(list(key_op())) -> {ok, list(key_op())} |
{error, nil}.
filter_public_key_ops(Ops) ->
case gleam@list:unique(gleam@list:filter_map(Ops, fun map_public_key_op/1)) of
[] ->
{error, nil};
Filtered ->
{ok, Filtered}
end.
-file("src/gose/key.gleam", 838).
?DOC(
" Extract the public key from an asymmetric key.\n"
"\n"
" For private keys, extracts the corresponding public key.\n"
" For public keys, returns the key unchanged.\n"
" Returns an error for symmetric octet keys.\n"
"\n"
" When extracting a public key, `key_ops` are filtered to public-safe operations:\n"
" - `Sign` is mapped to `Verify`\n"
" - `Decrypt` and `UnwrapKey` are removed (private-only)\n"
" - Other operations are preserved\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let private_key = key.generate_ec(ec.P256)\n"
" let assert Ok(pub_key) = key.public_key(private_key)\n"
" ```\n"
).
-spec public_key(key(LAH)) -> {ok, key(LAH)} | {error, gose:gose_error()}.
public_key(Key) ->
Filtered_ops = begin
_pipe = erlang:element(5, Key),
_pipe@1 = gleam@option:map(_pipe, fun filter_public_key_ops/1),
gleam@option:then(_pipe@1, fun gleam@option:from_result/1)
end,
case erlang:element(2, Key) of
{rsa, {rsa_private, _, Public}} ->
{ok,
{key,
{rsa, {rsa_public, Public}},
erlang:element(3, Key),
erlang:element(4, Key),
Filtered_ops,
erlang:element(6, Key)}};
{rsa, {rsa_public, _}} ->
{ok,
{key,
erlang:element(2, Key),
erlang:element(3, Key),
erlang:element(4, Key),
Filtered_ops,
erlang:element(6, Key)}};
{ec, {ec_private, _, Public@1, Curve}} ->
{ok,
{key,
{ec, {ec_public, Public@1, Curve}},
erlang:element(3, Key),
erlang:element(4, Key),
Filtered_ops,
erlang:element(6, Key)}};
{ec, {ec_public, _, _}} ->
{ok,
{key,
erlang:element(2, Key),
erlang:element(3, Key),
erlang:element(4, Key),
Filtered_ops,
erlang:element(6, Key)}};
{eddsa, {eddsa_private, _, Public@2, Curve@1}} ->
{ok,
{key,
{eddsa, {eddsa_public, Public@2, Curve@1}},
erlang:element(3, Key),
erlang:element(4, Key),
Filtered_ops,
erlang:element(6, Key)}};
{eddsa, {eddsa_public, _, _}} ->
{ok,
{key,
erlang:element(2, Key),
erlang:element(3, Key),
erlang:element(4, Key),
Filtered_ops,
erlang:element(6, Key)}};
{xdh, {xdh_private, _, Public@3, Curve@2}} ->
{ok,
{key,
{xdh, {xdh_public, Public@3, Curve@2}},
erlang:element(3, Key),
erlang:element(4, Key),
Filtered_ops,
erlang:element(6, Key)}};
{xdh, {xdh_public, _, _}} ->
{ok,
{key,
erlang:element(2, Key),
erlang:element(3, Key),
erlang:element(4, Key),
Filtered_ops,
erlang:element(6, Key)}};
{octet_key, _} ->
{error, {invalid_state, <<"octet keys are not asymmetric"/utf8>>}}
end.
-file("src/gose/key.gleam", 899).
?DOC(
" Serialize a key to DER format.\n"
"\n"
" Supports RSA, EC, EdDSA, and XDH keys (both private and public).\n"
" Uses PKCS#8 for private keys and SPKI for public keys.\n"
).
-spec to_der(key(any())) -> {ok, bitstring()} | {error, gose:gose_error()}.
to_der(Key) ->
case erlang:element(2, Key) of
{rsa, {rsa_private, Private, _}} ->
_pipe = kryptos_ffi:rsa_export_private_key_der(Private, pkcs8),
gleam@result:replace_error(
_pipe,
{invalid_state, <<"failed to serialize RSA private key"/utf8>>}
);
{rsa, {rsa_public, Public}} ->
_pipe@1 = kryptos_ffi:rsa_export_public_key_der(Public, spki),
gleam@result:replace_error(
_pipe@1,
{invalid_state, <<"failed to serialize RSA public key"/utf8>>}
);
{ec, {ec_private, Private@1, _, _}} ->
_pipe@2 = kryptos_ffi:ec_export_private_key_der(Private@1),
gleam@result:replace_error(
_pipe@2,
{invalid_state, <<"failed to serialize EC private key"/utf8>>}
);
{ec, {ec_public, Public@1, _}} ->
_pipe@3 = kryptos_ffi:ec_export_public_key_der(Public@1),
gleam@result:replace_error(
_pipe@3,
{invalid_state, <<"failed to serialize EC public key"/utf8>>}
);
{eddsa, {eddsa_private, Private@2, _, _}} ->
_pipe@4 = kryptos_ffi:eddsa_export_private_key_der(Private@2),
gleam@result:replace_error(
_pipe@4,
{invalid_state,
<<"failed to serialize EdDSA private key"/utf8>>}
);
{eddsa, {eddsa_public, Public@2, _}} ->
_pipe@5 = kryptos_ffi:eddsa_export_public_key_der(Public@2),
gleam@result:replace_error(
_pipe@5,
{invalid_state, <<"failed to serialize EdDSA public key"/utf8>>}
);
{xdh, {xdh_private, Private@3, _, _}} ->
_pipe@6 = kryptos_ffi:xdh_export_private_key_der(Private@3),
gleam@result:replace_error(
_pipe@6,
{invalid_state, <<"failed to serialize XDH private key"/utf8>>}
);
{xdh, {xdh_public, Public@3, _}} ->
_pipe@7 = kryptos_ffi:xdh_export_public_key_der(Public@3),
gleam@result:replace_error(
_pipe@7,
{invalid_state, <<"failed to serialize XDH public key"/utf8>>}
);
{octet_key, _} ->
{error,
{invalid_state,
<<"octet keys cannot be serialized to DER"/utf8>>}}
end.
-file("src/gose/key.gleam", 952).
?DOC(
" Export the raw bytes of a key.\n"
"\n"
" Supported key types:\n"
" - Octet keys: returns the secret bytes\n"
" - EdDSA/XDH private keys: returns the private key bytes (d)\n"
" - EdDSA/XDH public keys: returns the public key bytes (x)\n"
).
-spec to_octet_bits(key(any())) -> {ok, bitstring()} |
{error, gose:gose_error()}.
to_octet_bits(Key) ->
case erlang:element(2, Key) of
{octet_key, Secret} ->
{ok, Secret};
{eddsa, {eddsa_private, Private, _, _}} ->
{ok, kryptos_ffi:eddsa_private_key_to_bytes(Private)};
{eddsa, {eddsa_public, Public, _}} ->
{ok, kryptos_ffi:eddsa_public_key_to_bytes(Public)};
{xdh, {xdh_private, Private@1, _, _}} ->
{ok, kryptos_ffi:xdh_private_key_to_bytes(Private@1)};
{xdh, {xdh_public, Public@1, _}} ->
{ok, kryptos_ffi:xdh_public_key_to_bytes(Public@1)};
{rsa, _} ->
{error,
{invalid_state,
<<"key has no single-value byte representation"/utf8>>}};
{ec, _} ->
{error,
{invalid_state,
<<"key has no single-value byte representation"/utf8>>}}
end.
-file("src/gose/key.gleam", 968).
?DOC(
" Serialize a key to PEM format.\n"
"\n"
" Supports RSA, EC, EdDSA, and XDH keys (both private and public).\n"
" Uses PKCS#8 for private keys and SPKI for public keys.\n"
).
-spec to_pem(key(any())) -> {ok, binary()} | {error, gose:gose_error()}.
to_pem(Key) ->
case erlang:element(2, Key) of
{rsa, {rsa_private, Private, _}} ->
_pipe = kryptos@rsa:to_pem(Private, pkcs8),
gleam@result:replace_error(
_pipe,
{invalid_state, <<"failed to serialize RSA private key"/utf8>>}
);
{rsa, {rsa_public, Public}} ->
_pipe@1 = kryptos@rsa:public_key_to_pem(Public, spki),
gleam@result:replace_error(
_pipe@1,
{invalid_state, <<"failed to serialize RSA public key"/utf8>>}
);
{ec, {ec_private, Private@1, _, _}} ->
_pipe@2 = kryptos@ec:to_pem(Private@1),
gleam@result:replace_error(
_pipe@2,
{invalid_state, <<"failed to serialize EC private key"/utf8>>}
);
{ec, {ec_public, Public@1, _}} ->
_pipe@3 = kryptos@ec:public_key_to_pem(Public@1),
gleam@result:replace_error(
_pipe@3,
{invalid_state, <<"failed to serialize EC public key"/utf8>>}
);
{eddsa, {eddsa_private, Private@2, _, _}} ->
_pipe@4 = kryptos@eddsa:to_pem(Private@2),
gleam@result:replace_error(
_pipe@4,
{invalid_state,
<<"failed to serialize EdDSA private key"/utf8>>}
);
{eddsa, {eddsa_public, Public@2, _}} ->
_pipe@5 = kryptos@eddsa:public_key_to_pem(Public@2),
gleam@result:replace_error(
_pipe@5,
{invalid_state, <<"failed to serialize EdDSA public key"/utf8>>}
);
{xdh, {xdh_private, Private@3, _, _}} ->
_pipe@6 = kryptos@xdh:to_pem(Private@3),
gleam@result:replace_error(
_pipe@6,
{invalid_state, <<"failed to serialize XDH private key"/utf8>>}
);
{xdh, {xdh_public, Public@3, _}} ->
_pipe@7 = kryptos@xdh:public_key_to_pem(Public@3),
gleam@result:replace_error(
_pipe@7,
{invalid_state, <<"failed to serialize XDH public key"/utf8>>}
);
{octet_key, _} ->
{error,
{invalid_state,
<<"octet keys cannot be serialized to PEM"/utf8>>}}
end.
-file("src/gose/key.gleam", 1018).
?DOC(false).
-spec build(
key_material(),
gleam@option:option(LBE),
gleam@option:option(key_use()),
gleam@option:option(list(key_op())),
gleam@option:option(alg())
) -> key(LBE).
build(Material, Kid, Key_use, Key_ops, Alg) ->
{key, Material, Kid, Key_use, Key_ops, Alg}.
-file("src/gose/key.gleam", 1031).
?DOC(false).
-spec validate_rfc8037_key_use_public(
key_material(),
gleam@option:option(key_use())
) -> {ok, nil} | {error, gose:gose_error()}.
validate_rfc8037_key_use_public(Material, Use_) ->
validate_rfc8037_key_use(Material, Use_).