Packages

Cryptography library for Gleam targeting Erlang and JavaScript

Current section

Files

Jump to
kryptos src kryptos@rsa.erl
Raw

src/kryptos@rsa.erl

-module(kryptos@rsa).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/kryptos/rsa.gleam").
-export([sign/4, verify/5, encrypt/3, decrypt/3, from_pem/2, from_der/2, to_pem/2, to_der/2, public_key_from_pem/2, public_key_from_der/2, public_key_to_pem/2, public_key_to_der/2, public_key_from_private_key/1, generate_key_pair/1]).
-export_type([private_key/0, public_key/0, private_key_format/0, public_key_format/0, pss_salt_length/0, sign_padding/0, encrypt_padding/0]).
-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(
" RSA (Rivest-Shamir-Adleman) cryptography.\n"
"\n"
" This module provides RSA key generation, signing, and encryption operations.\n"
" RSA keys can be used for both digital signatures and encryption.\n"
"\n"
" ## Key Generation\n"
"\n"
" ```gleam\n"
" import kryptos/rsa\n"
"\n"
" let assert Ok(#(private_key, public_key)) = rsa.generate_key_pair(2048)\n"
" ```\n"
"\n"
" ## Signing (RSA-PSS)\n"
"\n"
" ```gleam\n"
" import kryptos/rsa\n"
" import kryptos/hash\n"
"\n"
" let assert Ok(#(private_key, public_key)) = rsa.generate_key_pair(2048)\n"
" let message = <<\"hello world\":utf8>>\n"
" let padding = rsa.Pss(rsa.SaltLengthHashLen)\n"
" let signature = rsa.sign(private_key, message, hash.Sha256, padding)\n"
" let valid = rsa.verify(public_key, message, signature, hash.Sha256, padding)\n"
" ```\n"
"\n"
" ## Encryption (RSA-OAEP)\n"
"\n"
" ```gleam\n"
" import kryptos/rsa\n"
" import kryptos/hash\n"
"\n"
" let assert Ok(#(private_key, public_key)) = rsa.generate_key_pair(2048)\n"
" let plaintext = <<\"secret\":utf8>>\n"
" let padding = rsa.Oaep(hash: hash.Sha256, label: <<>>)\n"
" let assert Ok(ciphertext) = rsa.encrypt(public_key, plaintext, padding)\n"
" let assert Ok(decrypted) = rsa.decrypt(private_key, ciphertext, padding)\n"
" ```\n"
).
-type private_key() :: any().
-type public_key() :: any().
-type private_key_format() :: pkcs8 | pkcs1.
-type public_key_format() :: spki | rsa_public_key.
-type pss_salt_length() :: salt_length_hash_len |
salt_length_max |
{salt_length_explicit, integer()}.
-type sign_padding() :: pkcs1v15 | {pss, pss_salt_length()}.
-type encrypt_padding() :: encrypt_pkcs1v15 |
{oaep, kryptos@hash:hash_algorithm(), bitstring()}.
-file("src/kryptos/rsa.gleam", 145).
?DOC(
" Signs a message using RSA with the specified hash algorithm and padding.\n"
"\n"
" The message is hashed internally using the provided algorithm before signing.\n"
"\n"
" ## Parameters\n"
" - `private_key`: An RSA private key\n"
" - `message`: The message to sign (any length)\n"
" - `hash`: The hash algorithm to use\n"
" - `padding`: The signature padding scheme (Pkcs1v15 or Pss)\n"
"\n"
" ## Returns\n"
" The RSA signature.\n"
).
-spec sign(
private_key(),
bitstring(),
kryptos@hash:hash_algorithm(),
sign_padding()
) -> bitstring().
sign(Private_key, Message, Hash, Padding) ->
kryptos_ffi:rsa_sign(Private_key, Message, Hash, Padding).
-file("src/kryptos/rsa.gleam", 169).
?DOC(
" Verifies an RSA signature against a message.\n"
"\n"
" The message is hashed internally using the provided algorithm before\n"
" verification. The same hash algorithm and padding used during signing\n"
" must be used for verification.\n"
"\n"
" ## Parameters\n"
" - `public_key`: The RSA public key corresponding to the signing key\n"
" - `message`: The original message that was signed\n"
" - `signature`: The signature to verify\n"
" - `hash`: The hash algorithm used during signing\n"
" - `padding`: The signature padding scheme used during signing\n"
"\n"
" ## Returns\n"
" `True` if the signature is valid, `False` otherwise.\n"
).
-spec verify(
public_key(),
bitstring(),
bitstring(),
kryptos@hash:hash_algorithm(),
sign_padding()
) -> boolean().
verify(Public_key, Message, Signature, Hash, Padding) ->
kryptos_ffi:rsa_verify(Public_key, Message, Signature, Hash, Padding).
-file("src/kryptos/rsa.gleam", 192).
?DOC(
" Encrypts data using RSA with the specified padding scheme.\n"
"\n"
" **Note**: RSA encryption should only be used for small amounts of data\n"
" (typically symmetric keys). For bulk encryption, use a symmetric cipher\n"
" with a randomly generated key, then encrypt that key with RSA.\n"
"\n"
" ## Parameters\n"
" - `public_key`: The RSA public key\n"
" - `plaintext`: The data to encrypt\n"
" - `padding`: The encryption padding scheme (EncryptPkcs1v15 or Oaep)\n"
"\n"
" ## Returns\n"
" `Ok(ciphertext)` on success, `Error(Nil)` if plaintext is too long.\n"
).
-spec encrypt(public_key(), bitstring(), encrypt_padding()) -> {ok, bitstring()} |
{error, nil}.
encrypt(Public_key, Plaintext, Padding) ->
kryptos_ffi:rsa_encrypt(Public_key, Plaintext, Padding).
-file("src/kryptos/rsa.gleam", 209).
?DOC(
" Decrypts data using RSA with the specified padding scheme.\n"
"\n"
" ## Parameters\n"
" - `private_key`: The RSA private key\n"
" - `ciphertext`: The encrypted data\n"
" - `padding`: The encryption padding scheme (must match encryption)\n"
"\n"
" ## Returns\n"
" `Ok(plaintext)` on success, `Error(Nil)` on decryption failure.\n"
).
-spec decrypt(private_key(), bitstring(), encrypt_padding()) -> {ok,
bitstring()} |
{error, nil}.
decrypt(Private_key, Ciphertext, Padding) ->
kryptos_ffi:rsa_decrypt(Private_key, Ciphertext, Padding).
-file("src/kryptos/rsa.gleam", 225).
?DOC(
" Imports an RSA private key from PEM-encoded data.\n"
"\n"
" ## Parameters\n"
" - `pem`: PEM-encoded key string\n"
" - `format`: The key format (Pkcs8 or Pkcs1)\n"
"\n"
" ## Returns\n"
" `Ok(#(private_key, public_key))` on success, `Error(Nil)` on failure.\n"
).
-spec from_pem(binary(), private_key_format()) -> {ok,
{private_key(), public_key()}} |
{error, nil}.
from_pem(Pem, Format) ->
kryptos_ffi:rsa_import_private_key_pem(Pem, Format).
-file("src/kryptos/rsa.gleam", 240).
?DOC(
" Imports an RSA private key from DER-encoded data.\n"
"\n"
" ## Parameters\n"
" - `der`: DER-encoded key data\n"
" - `format`: The key format (Pkcs8 or Pkcs1)\n"
"\n"
" ## Returns\n"
" `Ok(#(private_key, public_key))` on success, `Error(Nil)` on failure.\n"
).
-spec from_der(bitstring(), private_key_format()) -> {ok,
{private_key(), public_key()}} |
{error, nil}.
from_der(Der, Format) ->
kryptos_ffi:rsa_import_private_key_der(Der, Format).
-file("src/kryptos/rsa.gleam", 253).
?DOC(
" Exports an RSA private key to PEM format.\n"
"\n"
" ## Parameters\n"
" - `key`: The private key to export\n"
" - `format`: The output format (Pkcs8 or Pkcs1)\n"
"\n"
" ## Returns\n"
" `Ok(pem_string)` on success, `Error(Nil)` on failure.\n"
).
-spec to_pem(private_key(), private_key_format()) -> {ok, binary()} |
{error, nil}.
to_pem(Key, Format) ->
_pipe = kryptos_ffi:rsa_export_private_key_pem(Key, Format),
gleam@result:map(
_pipe,
fun(Pem) -> <<(gleam@string:trim_end(Pem))/binary, "\n"/utf8>> end
).
-file("src/kryptos/rsa.gleam", 271).
?DOC(
" Exports an RSA private key to DER format.\n"
"\n"
" ## Parameters\n"
" - `key`: The private key to export\n"
" - `format`: The output format (Pkcs8 or Pkcs1)\n"
"\n"
" ## Returns\n"
" `Ok(der_data)` on success, `Error(Nil)` on failure.\n"
).
-spec to_der(private_key(), private_key_format()) -> {ok, bitstring()} |
{error, nil}.
to_der(Key, Format) ->
kryptos_ffi:rsa_export_private_key_der(Key, Format).
-file("src/kryptos/rsa.gleam", 286).
?DOC(
" Imports an RSA public key from PEM-encoded data.\n"
"\n"
" ## Parameters\n"
" - `pem`: PEM-encoded key string\n"
" - `format`: The key format (Spki or RsaPublicKey)\n"
"\n"
" ## Returns\n"
" `Ok(public_key)` on success, `Error(Nil)` on failure.\n"
).
-spec public_key_from_pem(binary(), public_key_format()) -> {ok, public_key()} |
{error, nil}.
public_key_from_pem(Pem, Format) ->
kryptos_ffi:rsa_import_public_key_pem(Pem, Format).
-file("src/kryptos/rsa.gleam", 301).
?DOC(
" Imports an RSA public key from DER-encoded data.\n"
"\n"
" ## Parameters\n"
" - `der`: DER-encoded key data\n"
" - `format`: The key format (Spki or RsaPublicKey)\n"
"\n"
" ## Returns\n"
" `Ok(public_key)` on success, `Error(Nil)` on failure.\n"
).
-spec public_key_from_der(bitstring(), public_key_format()) -> {ok,
public_key()} |
{error, nil}.
public_key_from_der(Der, Format) ->
kryptos_ffi:rsa_import_public_key_der(Der, Format).
-file("src/kryptos/rsa.gleam", 314).
?DOC(
" Exports an RSA public key to PEM format.\n"
"\n"
" ## Parameters\n"
" - `key`: The public key to export\n"
" - `format`: The output format (Spki or RsaPublicKey)\n"
"\n"
" ## Returns\n"
" `Ok(pem_string)` on success, `Error(Nil)` on failure.\n"
).
-spec public_key_to_pem(public_key(), public_key_format()) -> {ok, binary()} |
{error, nil}.
public_key_to_pem(Key, Format) ->
_pipe = kryptos_ffi:rsa_export_public_key_pem(Key, Format),
gleam@result:map(
_pipe,
fun(Pem) -> <<(gleam@string:trim_end(Pem))/binary, "\n"/utf8>> end
).
-file("src/kryptos/rsa.gleam", 339).
?DOC(
" Exports an RSA public key to DER format.\n"
"\n"
" ## Parameters\n"
" - `key`: The public key to export\n"
" - `format`: The output format (Spki or RsaPublicKey)\n"
"\n"
" ## Returns\n"
" `Ok(der_data)` on success, `Error(Nil)` on failure.\n"
).
-spec public_key_to_der(public_key(), public_key_format()) -> {ok, bitstring()} |
{error, nil}.
public_key_to_der(Key, Format) ->
kryptos_ffi:rsa_export_public_key_der(Key, Format).
-file("src/kryptos/rsa.gleam", 353).
?DOC(
" Derives the public key from an RSA private key.\n"
"\n"
" ## Parameters\n"
" - `key`: The private key\n"
"\n"
" ## Returns\n"
" The corresponding public key.\n"
).
-spec public_key_from_private_key(private_key()) -> public_key().
public_key_from_private_key(Key) ->
kryptos_ffi:rsa_public_key_from_private(Key).
-file("src/kryptos/rsa.gleam", 120).
?DOC(
" Generates an RSA key pair with the specified key size.\n"
"\n"
" The key can be used for both signing and encryption operations.\n"
"\n"
" ## Parameters\n"
" - `bits`: The key size in bits (must be >= 1024)\n"
"\n"
" ## Returns\n"
" `Ok(#(private_key, public_key))` on success, `Error(Nil)` if bits < 1024.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let assert Ok(#(private_key, public_key)) = rsa.generate_key_pair(2048)\n"
" ```\n"
).
-spec generate_key_pair(integer()) -> {ok, {private_key(), public_key()}} |
{error, nil}.
generate_key_pair(Bits) ->
case Bits >= 1024 of
true ->
{ok, kryptos_ffi:rsa_generate_key_pair(Bits)};
false ->
{error, nil}
end.