Packages

Cryptography library for Gleam targeting Erlang and JavaScript

Current section

Files

Jump to
kryptos src kryptos@block.erl
Raw

src/kryptos@block.erl

-module(kryptos@block).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/kryptos/block.gleam").
-export([key_size/1, block_size/1, aes_128/1, aes_192/1, aes_256/1, ecb/1, cbc/2, ctr/2, encrypt/2, decrypt/2, cipher_name/1, cipher_key/1, cipher_iv/1]).
-export_type([block_cipher/0, cipher_context/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(
" Block cipher implementations and modes of operation.\n"
"\n"
" This module provides AES block ciphers and modes of operation (ECB, CBC, CTR).\n"
"\n"
" **IMPORTANT SECURITY WARNING:**\n"
" ECB, CBC, and CTR modes do NOT provide authentication. An attacker can modify\n"
" ciphertext without detection. For most applications, you should use\n"
" authenticated encryption modes like AES-GCM or ChaCha20-Poly1305\n"
" from the `kryptos/aead` module instead.\n"
"\n"
" Use these modes only when:\n"
" - Interoperating with legacy systems that require them\n"
" - Implementing higher-level protocols that provide their own authentication\n"
" - You fully understand the security implications\n"
"\n"
" ## Modes Overview\n"
"\n"
" - **ECB (Electronic Codebook):** Encrypts each block independently.\n"
" INSECURE for most uses - reveals patterns in data. Only use for\n"
" single-block encryption or specific legacy requirements.\n"
" - **CBC (Cipher Block Chaining):** Each block XORed with previous ciphertext.\n"
" Requires random IV per encryption. Uses PKCS7 padding automatically.\n"
" - **CTR (Counter):** Converts block cipher to stream cipher.\n"
" Nonce reuse is catastrophic - NEVER reuse a nonce with the same key.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import kryptos/block\n"
" import kryptos/crypto\n"
"\n"
" // CBC encryption with random IV\n"
" let assert Ok(cipher) = block.aes_256(crypto.random_bytes(32))\n"
" let assert Ok(ctx) = block.cbc(cipher, iv: crypto.random_bytes(16))\n"
" let assert Ok(ciphertext) = block.encrypt(ctx, <<\"secret\":utf8>>)\n"
" let assert Ok(decrypted) = block.decrypt(ctx, ciphertext)\n"
" // decrypted == <<\"secret\":utf8>>\n"
" ```\n"
).
-type block_cipher() :: {aes, integer(), bitstring()}.
-type cipher_context() :: {ecb, block_cipher()} |
{cbc, block_cipher(), bitstring()} |
{ctr, block_cipher(), bitstring()}.
-file("src/kryptos/block.gleam", 76).
?DOC(
" Returns the key size in bytes for a block cipher.\n"
"\n"
" ## Parameters\n"
" - `cipher`: The block cipher to get the key size for\n"
"\n"
" ## Returns\n"
" The key size in bytes (16, 24, or 32 for AES).\n"
).
-spec key_size(block_cipher()) -> integer().
key_size(Cipher) ->
case Cipher of
{aes, Key_size, _} ->
Key_size
end.
-file("src/kryptos/block.gleam", 89).
?DOC(
" Returns the block size in bytes for a block cipher.\n"
"\n"
" ## Parameters\n"
" - `cipher`: The block cipher to get the block size for\n"
"\n"
" ## Returns\n"
" The block size in bytes (16 for AES).\n"
).
-spec block_size(block_cipher()) -> integer().
block_size(Cipher) ->
case Cipher of
{aes, _, _} ->
16
end.
-file("src/kryptos/block.gleam", 103).
?DOC(
" Creates a new AES-128 block cipher with the given key.\n"
"\n"
" ## Parameters\n"
" - `key`: A 16-byte key for AES-128\n"
"\n"
" ## Returns\n"
" - `Ok(BlockCipher)` if the key is exactly 16 bytes\n"
" - `Error(Nil)` if the key size is incorrect\n"
).
-spec aes_128(bitstring()) -> {ok, block_cipher()} | {error, nil}.
aes_128(Key) ->
case erlang:byte_size(Key) =:= 16 of
true ->
{ok, {aes, 128, Key}};
false ->
{error, nil}
end.
-file("src/kryptos/block.gleam", 118).
?DOC(
" Creates a new AES-192 block cipher with the given key.\n"
"\n"
" ## Parameters\n"
" - `key`: A 24-byte key for AES-192\n"
"\n"
" ## Returns\n"
" - `Ok(BlockCipher)` if the key is exactly 24 bytes\n"
" - `Error(Nil)` if the key size is incorrect\n"
).
-spec aes_192(bitstring()) -> {ok, block_cipher()} | {error, nil}.
aes_192(Key) ->
case erlang:byte_size(Key) =:= 24 of
true ->
{ok, {aes, 192, Key}};
false ->
{error, nil}
end.
-file("src/kryptos/block.gleam", 133).
?DOC(
" Creates a new AES-256 block cipher with the given key.\n"
"\n"
" ## Parameters\n"
" - `key`: A 32-byte key for AES-256\n"
"\n"
" ## Returns\n"
" - `Ok(BlockCipher)` if the key is exactly 32 bytes\n"
" - `Error(Nil)` if the key size is incorrect\n"
).
-spec aes_256(bitstring()) -> {ok, block_cipher()} | {error, nil}.
aes_256(Key) ->
case erlang:byte_size(Key) =:= 32 of
true ->
{ok, {aes, 256, Key}};
false ->
{error, nil}
end.
-file("src/kryptos/block.gleam", 151).
?DOC(
" Creates an ECB mode context for the given cipher.\n"
"\n"
" **SECURITY WARNING:** ECB mode is insecure for most use cases.\n"
" Identical plaintext blocks produce identical ciphertext blocks,\n"
" revealing patterns in the data.\n"
"\n"
" ## Parameters\n"
" - `cipher`: The block cipher to use\n"
"\n"
" ## Returns\n"
" An ECB cipher context.\n"
).
-spec ecb(block_cipher()) -> cipher_context().
ecb(Cipher) ->
{ecb, Cipher}.
-file("src/kryptos/block.gleam", 164).
?DOC(
" Creates a CBC mode context with the given cipher and IV.\n"
"\n"
" ## Parameters\n"
" - `cipher`: The block cipher to use\n"
" - `iv`: A 16-byte initialization vector (must be random and unique per encryption)\n"
"\n"
" ## Returns\n"
" - `Ok(CipherContext)` if the IV is exactly 16 bytes\n"
" - `Error(Nil)` if the IV size is incorrect\n"
).
-spec cbc(block_cipher(), bitstring()) -> {ok, cipher_context()} | {error, nil}.
cbc(Cipher, Iv) ->
case erlang:byte_size(Iv) =:= 16 of
true ->
{ok, {cbc, Cipher, Iv}};
false ->
{error, nil}
end.
-file("src/kryptos/block.gleam", 183).
?DOC(
" Creates a CTR mode context with the given cipher and nonce.\n"
"\n"
" **SECURITY WARNING:** Nonce reuse is catastrophic in CTR mode.\n"
" NEVER reuse a nonce with the same key.\n"
"\n"
" ## Parameters\n"
" - `cipher`: The block cipher to use\n"
" - `nonce`: A 16-byte nonce (must be unique per encryption with the same key)\n"
"\n"
" ## Returns\n"
" - `Ok(CipherContext)` if the nonce is exactly 16 bytes\n"
" - `Error(Nil)` if the nonce size is incorrect\n"
).
-spec ctr(block_cipher(), bitstring()) -> {ok, cipher_context()} | {error, nil}.
ctr(Cipher, Nonce) ->
case erlang:byte_size(Nonce) =:= 16 of
true ->
{ok, {ctr, Cipher, Nonce}};
false ->
{error, nil}
end.
-file("src/kryptos/block.gleam", 214).
-spec validate_iv(cipher_context()) -> boolean().
validate_iv(Ctx) ->
case Ctx of
{ecb, _} ->
true;
{cbc, _, Iv} ->
erlang:byte_size(Iv) =:= 16;
{ctr, _, Nonce} ->
erlang:byte_size(Nonce) =:= 16
end.
-file("src/kryptos/block.gleam", 207).
?DOC(
" Encrypts plaintext using the cipher mode.\n"
"\n"
" ## Parameters\n"
" - `ctx`: The cipher context (includes IV/nonce for CBC/CTR)\n"
" - `plaintext`: The data to encrypt\n"
"\n"
" ## Returns\n"
" - `Ok(ciphertext)` on success\n"
" - `Error(Nil)` if IV/nonce size is incorrect\n"
"\n"
" ## Notes\n"
" - ECB: No IV required\n"
" - CBC: Automatically applies PKCS7 padding; ciphertext may be larger than plaintext\n"
" - CTR: No padding needed; ciphertext is same size as plaintext\n"
).
-spec encrypt(cipher_context(), bitstring()) -> {ok, bitstring()} | {error, nil}.
encrypt(Ctx, Plaintext) ->
case validate_iv(Ctx) of
true ->
kryptos_ffi:block_cipher_encrypt(Ctx, Plaintext);
false ->
{error, nil}
end.
-file("src/kryptos/block.gleam", 240).
?DOC(
" Decrypts ciphertext using the cipher mode.\n"
"\n"
" ## Parameters\n"
" - `ctx`: The cipher context (includes IV/nonce for CBC/CTR)\n"
" - `ciphertext`: The encrypted data\n"
"\n"
" ## Returns\n"
" - `Ok(plaintext)` on success\n"
" - `Error(Nil)` if IV/nonce size is incorrect, ciphertext size is invalid, or padding is invalid\n"
"\n"
" ## Notes\n"
" - ECB: No IV required\n"
" - CBC: Automatically removes PKCS7 padding; returns error if padding is invalid\n"
" - CTR: No padding; ciphertext size equals plaintext size\n"
).
-spec decrypt(cipher_context(), bitstring()) -> {ok, bitstring()} | {error, nil}.
decrypt(Ctx, Ciphertext) ->
case validate_iv(Ctx) of
true ->
kryptos_ffi:block_cipher_decrypt(Ctx, Ciphertext);
false ->
{error, nil}
end.
-file("src/kryptos/block.gleam", 255).
?DOC(false).
-spec cipher_name(cipher_context()) -> binary().
cipher_name(Ctx) ->
case Ctx of
{ecb, Cipher} ->
case Cipher of
{aes, Key_size, _} ->
<<<<"aes-"/utf8,
(erlang:integer_to_binary(Key_size))/binary>>/binary,
"-ecb"/utf8>>
end;
{cbc, Cipher@1, _} ->
case Cipher@1 of
{aes, Key_size@1, _} ->
<<<<"aes-"/utf8,
(erlang:integer_to_binary(Key_size@1))/binary>>/binary,
"-cbc"/utf8>>
end;
{ctr, Cipher@2, _} ->
case Cipher@2 of
{aes, Key_size@2, _} ->
<<<<"aes-"/utf8,
(erlang:integer_to_binary(Key_size@2))/binary>>/binary,
"-ctr"/utf8>>
end
end.
-file("src/kryptos/block.gleam", 273).
?DOC(false).
-spec cipher_key(cipher_context()) -> bitstring().
cipher_key(Ctx) ->
case Ctx of
{ecb, Cipher} ->
case Cipher of
{aes, _, Key} ->
Key
end;
{cbc, Cipher, _} ->
case Cipher of
{aes, _, Key} ->
Key
end;
{ctr, Cipher, _} ->
case Cipher of
{aes, _, Key} ->
Key
end
end.
-file("src/kryptos/block.gleam", 283).
?DOC(false).
-spec cipher_iv(cipher_context()) -> bitstring().
cipher_iv(Ctx) ->
case Ctx of
{ecb, _} ->
<<>>;
{cbc, _, Iv} ->
Iv;
{ctr, _, Nonce} ->
Nonce
end.