Sodium::FFI - Sodium is a modern, easy-to-use software library for encryption, decryption, signatures, password hashing, and more.
use strict;
use warnings;
use v5.34;
use Sodium::FFI ();
my $text = "1234";
my $padded = Sodium::FFI::pad($text, 16);
say Sodium::FFI::unpad($padded);
Sodium::FFI is a set of Perl bindings for the LibSodium C library. Sodium is a modern, easy-to-use software library for encryption, decryption, signatures, password hashing, and more. These bindings have been created using FFI via FFI::Platypus.
We also intend to eventually fix Crypt::NaCl::Sodium so that it can use newer versions of LibSodium.
LibSodium provides a few Crypto Auth Functions to encrypt and verify messages with a key.
use Sodium::FFI qw(randombytes_buf crypto_auth crypto_auth_keygen);
# First, let's create a key
my $key = crypto_auth_keygen();
# let's encrypt 12 bytes of random data... for fun
my $message = randombytes_buf(12);
my $encrypted_bytes = crypto_auth($message, $key);
say $encrypted_bytes;
The crypto_auth function encrypts a message using a secret key and returns that message as a string of bytes.
use Sodium::FFI qw(randombytes_buf crypto_auth_verify crypto_auth_keygen);
my $message = randombytes_buf(12);
# you'd really need to already have the key, but here
my $key = crypto_auth_keygen();
# your encrypted data would come from a call to crypto_auth
my $encrypted; # assume this is full of bytes
# let's verify
my $boolean = crypto_auth_verify($encrypted, $message, $key);
say $boolean;
The crypto_auth_verify function returns a boolean letting us know if the encrypted message and the original message are verified with the secret key.
use Sodium::FFI qw(crypto_auth_keygen);
my $key = crypto_auth_keygen();
# this could also be written:
use Sodium::FFI qw(randombytes_buf crypto_auth_KEYBYTES);
my $key = randombytes_buf(crypto_auth_KEYBYTES);
The crypto_auth_keygen
function returns a byte string of crypto_auth_KEYBYTES
bytes.
LibSodium provides a few
AES256-GCM functions
to encrypt or decrypt a message with a nonce and key. Note that these functions may not be
available on your hardware and will croak
in such a case.
use Sodium::FFI qw(
randombytes_buf crypto_aead_aes256gcm_decrypt
crypto_aead_aes256gcm_is_available
crypto_aead_aes256gcm_keygen crypto_aead_aes256gcm_NPUBBYTES
);
if (crypto_aead_aes256gcm_is_available()) {
# you'd really need to already have the nonce and key, but here
my $key = crypto_aead_aes256gcm_keygen();
my $nonce = randombytes_buf(crypto_aead_aes256gcm_NPUBBYTES);
# your encrypted data would come from a call to crypto_aead_aes256gcm_encrypt
my $encrypted; # assume this is full of bytes
# any additional data bytes that were encrypted should also be included
# they can be undef
my $additional_data = undef; # we don't care to add anything extra
# let's decrypt!
my $decrypted_bytes = crypto_aead_aes256gcm_decrypt(
$encrypted, $additional_data, $nonce, $key
);
say $decrypted_bytes;
}
The crypto_aead_aes256gcm_decrypt function returns a string of bytes after verifying that the ciphertext includes a valid tag using a secret key, a public nonce, and additional data.
use Sodium::FFI qw(
randombytes_buf crypto_aead_aes256gcm_encrypt
crypto_aead_aes256gcm_is_available
crypto_aead_aes256gcm_keygen crypto_aead_aes256gcm_NPUBBYTES
);
if (crypto_aead_aes256gcm_is_available()) {
# First, let's create a key and nonce
my $key = crypto_aead_aes256gcm_keygen();
my $nonce = randombytes_buf(crypto_aead_aes256gcm_NPUBBYTES);
# let's encrypt 12 bytes of random data... for fun
my $message = randombytes_buf(12);
# any additional data bytes that were encrypted should also be included
# they can be undef
my $additional_data = undef; # we don't care to add anything extra
$additional_data = randombytes_buf(12); # or some random byte string
my $encrypted_bytes = crypto_aead_aes256gcm_encrypt(
$message, $additional_data, $nonce, $key
);
say $encrypted_bytes;
}
The crypto_aead_aes256gcm_encrypt function encrypts a message using a secret key and a public nonce and returns that message as a string of bytes.
use Sodium::FFI qw(crypto_aead_aes256gcm_is_available);
if (crypto_aead_aes256gcm_is_available()) {
# ... encrypt and decrypt some data here
}
The crypto_aead_aes256gcm_is_available
function returns 1
if the current CPU supports the AES256-GCM implementation, 0
otherwise.
use Sodium::FFI qw(
crypto_aead_aes256gcm_keygen crypto_aead_aes256gcm_is_available
);
if (crypto_aead_aes256gcm_is_available()) {
my $key = crypto_aead_aes256gcm_keygen();
# this could also be written:
use Sodium::FFI qw(randombytes_buf crypto_aead_aes256gcm_KEYBYTES);
my $key = randombytes_buf(crypto_aead_aes256gcm_KEYBYTES);
}
The crypto_aead_aes256gcm_keygen
function returns a byte string of crypto_aead_aes256gcm_KEYBYTES
bytes.
LibSodium provides a few chacha20poly1305 functions to encrypt or decrypt a message with a nonce and key.
use Sodium::FFI qw(
randombytes_buf crypto_aead_chacha20poly1305_decrypt
crypto_aead_chacha20poly1305_keygen crypto_aead_chacha20poly1305_NPUBBYTES
);
# you'd really need to already have the nonce and key, but here
my $key = crypto_aead_chacha20poly1305_keygen();
my $nonce = randombytes_buf(crypto_aead_chacha20poly1305_NPUBBYTES);
# your encrypted data would come from a call to crypto_aead_chacha20poly1305_encrypt
my $encrypted; # assume this is full of bytes
# any additional data bytes that were encrypted should also be included
# they can be undef
my $additional_data = undef; # we don't care to add anything extra
# let's decrypt!
my $decrypted_bytes = crypto_aead_chacha20poly1305_decrypt(
$encrypted, $additional_data, $nonce, $key
);
say $decrypted_bytes;
The crypto_aead_chacha20poly1305_decrypt function returns a string of bytes after verifying that the ciphertext includes a valid tag using a secret key, a public nonce, and additional data.
use Sodium::FFI qw(
randombytes_buf crypto_aead_chacha20poly1305_encrypt
crypto_aead_chacha20poly1305_keygen crypto_aead_chacha20poly1305_NPUBBYTES
);
# First, let's create a key and nonce
my $key = crypto_aead_chacha20poly1305_keygen();
my $nonce = randombytes_buf(crypto_aead_chacha20poly1305_NPUBBYTES);
# let's encrypt 12 bytes of random data... for fun
my $message = randombytes_buf(12);
# any additional data bytes that were encrypted should also be included
# they can be undef
my $additional_data = undef; # we don't care to add anything extra
$additional_data = randombytes_buf(12); # or some random byte string
my $encrypted_bytes = crypto_aead_chacha20poly1305_encrypt(
$message, $additional_data, $nonce, $key
);
say $encrypted_bytes;
The crypto_aead_chacha20poly1305_encrypt function encrypts a message using a secret key and a public nonce and returns that message as a string of bytes.
use Sodium::FFI qw(
crypto_aead_chacha20poly1305_keygen
);
my $key = crypto_aead_chacha20poly1305_keygen();
# this could also be written:
use Sodium::FFI qw(randombytes_buf crypto_aead_chacha20poly1305_KEYBYTES);
my $key = randombytes_buf(crypto_aead_chacha20poly1305_KEYBYTES);
The crypto_aead_chacha20poly1305_keygen
function returns a byte string of crypto_aead_chacha20poly1305_KEYBYTES
bytes.
LibSodium provides a few chacha20poly1305 IETF functions to encrypt or decrypt a message with a nonce and key.
The IETF
variant of the ChaCha20-Poly1305
construction can safely encrypt a practically unlimited number of messages,
but individual messages cannot exceed approximately 256 GiB
.
use Sodium::FFI qw(
randombytes_buf crypto_aead_chacha20poly1305_ietf_decrypt
crypto_aead_chacha20poly1305_ietf_keygen crypto_aead_chacha20poly1305_IETF_NPUBBYTES
);
# you'd really need to already have the nonce and key, but here
my $key = crypto_aead_chacha20poly1305_ietf_keygen();
my $nonce = randombytes_buf(crypto_aead_chacha20poly1305_IETF_NPUBBYTES);
# your encrypted data would come from a call to crypto_aead_chacha20poly1305_ietf_encrypt
my $encrypted; # assume this is full of bytes
# any additional data bytes that were encrypted should also be included
# they can be undef
my $additional_data = undef; # we don't care to add anything extra
# let's decrypt!
my $decrypted_bytes = crypto_aead_chacha20poly1305_ietf_decrypt(
$encrypted, $additional_data, $nonce, $key
);
say $decrypted_bytes;
The crypto_aead_chacha20poly1305_ietf_decrypt function returns a string of bytes after verifying that the ciphertext includes a valid tag using a secret key, a public nonce, and additional data.
use Sodium::FFI qw(
randombytes_buf crypto_aead_chacha20poly1305_ietf_encrypt
crypto_aead_chacha20poly1305_ietf_keygen crypto_aead_chacha20poly1305_IETF_NPUBBYTES
);
# First, let's create a key and nonce
my $key = crypto_aead_chacha20poly1305_ietf_keygen();
my $nonce = randombytes_buf(crypto_aead_chacha20poly1305_IETF_NPUBBYTES);
# let's encrypt 12 bytes of random data... for fun
my $message = randombytes_buf(12);
# any additional data bytes that were encrypted should also be included
# they can be undef
my $additional_data = undef; # we don't care to add anything extra
$additional_data = randombytes_buf(12); # or some random byte string
my $encrypted_bytes = crypto_aead_chacha20poly1305_ietf_encrypt(
$message, $additional_data, $nonce, $key
);
say $encrypted_bytes;
The crypto_aead_chacha20poly1305_ietf_encrypt function encrypts a message using a secret key and a public nonce and returns that message as a string of bytes.
use Sodium::FFI qw(
crypto_aead_chacha20poly1305_ietf_keygen
);
my $key = crypto_aead_chacha20poly1305_ietf_keygen();
# this could also be written:
use Sodium::FFI qw(randombytes_buf crypto_aead_chacha20poly1305_IETF_KEYBYTES);
my $key = randombytes_buf(crypto_aead_chacha20poly1305_IETF_KEYBYTES);
The crypto_aead_chacha20poly1305_ietf_keygen
function returns a byte string of crypto_aead_chacha20poly1305_IETF_KEYBYTES
bytes.
LibSodium provides a few Public Key Authenticated Encryption and Sealed Box Encryption functions to allow sending messages using authenticated encryption.
use Sodium::FFI qw(crypto_box_keypair crypto_box_easy randombytes_buf crypto_box_NONCEBYTES);
my $nonce = randombytes_buf(crypto_box_NONCEBYTES);
my ($public_key, $secret_key) = crypto_box_keypair();
my $msg = "test";
my $cipher_text = crypto_box_easy($msg, $nonce, $public_key, $secret_key);
The crypto_box_easy function encrypts a message using the recipient's public key, the sender's secret key, and a nonce.
use Sodium::FFI qw(crypto_box_keypair);
my ($public_key, $secret_key) = crypto_box_keypair();
The crypto_box_keypair function randomly generates a secret key and a corresponding public key.
use Sodium::FFI qw(crypto_box_keypair crypto_box_easy crypto_box_open_easy randombytes_buf crypto_box_NONCEBYTES);
my $nonce = randombytes_buf(crypto_box_NONCEBYTES);
my ($public_key, $secret_key) = crypto_box_keypair();
my $msg = "test";
my $cipher_text = crypto_box_easy($msg, $nonce, $public_key, $secret_key);
my $decrypted = crypto_box_open_easy($cipher_text, $nonce, $public_key, $secret_key);
if ($decrypted eq $msg) {
say "Yay!";
}
The crypto_box_open_easy function decrypts a cipher text produced by crypto_box_easy.
use Sodium::FFI qw(crypto_box_keypair crypto_box_seal);
my ($public_key, $secret_key) = crypto_box_keypair();
my $msg = "test";
my $cipher_text = crypto_box_seal($msg, $public_key);
The crypto_box_seal function encrypts a message for a recipient whose public key is provided. The function creates a new key pair for each message and attaches the public key to the ciphertext. The secret key is overwritten and is not accessible after this function returns.
use Sodium::FFI qw(crypto_box_keypair crypto_box_seal crypto_box_seal_open);
my ($public_key, $secret_key) = crypto_box_keypair();
my $msg = "test";
my $cipher_text = crypto_box_seal($msg, $public_key);
my $decrypted = crypto_box_seal_open($cipher_text, $public_key, $secret_key);
if ($decrypted eq $msg) {
say "Yay!";
}
The crypto_box_seal_open function decrypts a cipher text produced by crypto_box_seal.
use Sodium::FFI qw(crypto_box_seed_keypair crypto_sign_SEEDBYTES randombytes_buf);
my $seed = randombytes_buf(crypto_sign_SEEDBYTES);
my ($public_key, $secret_key) = crypto_box_seed_keypair($seed);
The crypto_box_seed_keypair function randomly generates a secret key deterministically derived from a single key seed.
use Sodium::FFI qw(crypto_box_keypair crypto_scalarmult_base);
my ($public_key, $secret_key) = crypto_box_keypair();
my $computed_public = crypto_scalarmult_base($secret_key);
if ($public_key eq $computed_public) {
say "Yay!";
}
The crypto_scalarmult_base function can be used to compute the public key given a secret key previously generated with crypto_box_keypair.
LibSodium provides a few Public Key Signature Functions where a signer generates a key pair (public key and secret key) and appends the secret key to any number of messages. The one doing the verification will need to know and trust the public key before messages signed using it can be verified. This is not authenticated encryption.
use Sodium::FFI qw(crypto_sign_keypair crypto_sign);
my $msg = "Let's sign this and stuff!";
my ($public_key, $secret_key) = crypto_sign_keypair();
my $signed_msg = crypto_sign($msg, $secret_key);
The crypto_sign function prepends a signature to an unaltered message.
use Sodium::FFI qw(crypto_sign_keypair crypto_sign_detached);
my $msg = "Let's sign this and stuff!";
my ($public_key, $secret_key) = crypto_sign_keypair();
my $signature = crypto_sign_detached($msg, $secret_key);
The crypto_sign_detached function signs the message with the secret key and returns the signature.
use Sodium::FFI qw(crypto_sign_keypair);
my ($public_key, $secret_key) = crypto_sign_keypair();
The crypto_sign_keypair function randomly generates a secret key and a corresponding public key.
use Sodium::FFI qw(crypto_sign_open);
# we should have the public key and signed message to open
my $signed_msg = ...;
my $public_key = ...;
my $msg = crypto_sign_open($signed_msg, $public_key);
The crypto_sign_open function checks that a signed message has a valid signature for the public key. If so, it returns that message and if not, it will throw.
use Sodium::FFI qw(crypto_sign_seed_keypair crypto_sign_SEEDBYTES randombytes_buf);
my $seed = randombytes_buf(crypto_sign_SEEDBYTES);
my ($public_key, $secret_key) = crypto_sign_seed_keypair($seed);
The crypto_sign_seed_keypair function randomly generates a secret key deterministically derived from a single key seed and a corresponding public key.
use Sodium::FFI qw(crypto_sign_verify_detached);
my $signature = ...;
my $message = ...;
my $public_key = ...;
my $boolean = crypto_sign_verify_detached($signature, $message, $public_key);
The crypto_sign_verify_detached
function verifies that a signature is valid for the supplied message with public key. It returns
a boolean value, 1
for true, 0
for false.
LibSodium provides a few Random Number Generator Functions to assist you in getting your data ready for encryption, decryption, or hashing.
use Sodium::FFI qw(randombytes_buf);
my $bytes = randombytes_buf(2);
say $bytes; # contains two bytes of random data
The randombytes_buf function returns string of random bytes limited by a provided length.
use Sodium::FFI qw(randombytes_buf_deterministic);
# create some seed string of length Sodium::FFI::randombytes_SEEDBYTES
my $seed = 'x' x Sodium::FFI::randombytes_SEEDBYTES;
# use that seed to create a random string
my $length = 2;
my $bytes = randombytes_buf_deterministic($length, $seed);
say $bytes; # contains two bytes of random data
The randombytes_buf_deterministic function returns string of random bytes limited by a provided length.
It returns a byte string indistinguishable from random bytes without knowing the $seed
.
For a given seed, this function will always output the same sequence.
The seed string you create should be randombytes_SEEDBYTES
bytes long.
Up to 256 GB can be produced with a single seed.
use Sodium::FFI qw(randombytes_random);
my $random = randombytes_random();
say $random;
The randombytes_random
function returns an unpredictable value between 0
and 0xffffffff
(included).
use Sodium::FFI qw(randombytes_uniform);
my $upper_limit = 0xffffffff;
my $random = randombytes_uniform($upper_limit);
say $random;
The randombytes_uniform
function returns an unpredictable value between 0
and $upper_bound
(excluded).
Unlike randombytes_random() % $upper_bound
, it guarantees a uniform
distribution of the possible output values even when $upper_bound
is not a
power of 2
. Note that an $upper_bound
less than 2
leaves only a single element
to be chosen, namely 0
.
LibSodium provides a few Utility/Helper Functions to assist you in getting your data ready for encryption, decryption, or hashing.
use Sodium::FFI qw(sodium_add);
my $left = "111";
$left = sodium_add($left, 111);
say $left; # bbb
The sodium_add function adds 2 large numbers.
use Sodium::FFI qw(sodium_base642bin);
say sodium_base642bin('/wA='); # \377\000
my $variant = Sodium::FFI::sodium_base64_VARIANT_ORIGINAL;
say sodium_base642bin('/wA=', $variant); # \377\000
$variant = Sodium::FFI::sodium_base64_VARIANT_ORIGINAL_NO_PADDING;
say sodium_base642bin('/wA', $variant); # \377\000
$variant = Sodium::FFI::sodium_base64_VARIANT_URLSAFE;
say sodium_base642bin('_wA=', $variant); # \377\000
$variant = Sodium::FFI::sodium_base64_VARIANT_URLSAFE_NO_PADDING;
say sodium_base642bin('_wA', $variant); # \377\000
The sodium_base642bin function takes a base64 encoded string and turns it back into a binary string.
use Sodium::FFI qw(sodium_bin2base64);
say sodium_bin2base64("\377\000"); # /wA=
my $variant = Sodium::FFI::sodium_base64_VARIANT_ORIGINAL;
say sodium_bin2base64("\377\000", $variant); # /wA=
$variant = Sodium::FFI::sodium_base64_VARIANT_ORIGINAL_NO_PADDING;
say sodium_bin2base64("\377\000", $variant); # /wA
$variant = Sodium::FFI::sodium_base64_VARIANT_URLSAFE;
say sodium_bin2base64("\377\000", $variant); # _wA=
$variant = Sodium::FFI::sodium_base64_VARIANT_URLSAFE_NO_PADDING;
say sodium_bin2base64("\377\000", $variant); # _wA
The sodium_bin2base64 function takes a binary string and turns it into a base64 encoded string.
use Sodium::FFI qw(sodium_bin2hex);
my $binary = "ABC";
my $hex = sodium_bin2hex($binary);
say $hex; # 414243
The sodium_bin2hex function takes a binary string and turns it into a hex string.
use Sodium::FFI qw(sodium_compare);
say sodium_compare("\x01", "\x02"); # -1
say sodium_compare("\x02", "\x01"); # 1
say sodium_compare("\x01", "\x01"); # 0
The sodium_compare
function compares two large numbers encoded in little endian format.
Results in -1
when $left < $right
Results in 0
when $left eq $right
Results in 1
when $left > $right
use Sodium::FFI qw(sodium_hex2bin);
my $hex = "414243";
my $bin = sodium_hex2bin($hex);
say $bin; # ABC
The sodium_hex2bin function takes a hex string and turns it into a binary string.
use Sodium::FFI qw(sodium_increment);
my $x = "\x01";
$x = sodium_increment($x); # "\x02";
The sodium_increment function takes an arbitrarily long unsigned number and increments it.
use Sodium::FFI qw(sodium_is_zero);
my $string = "\x00\x00\x01"; # zero zero 1
# entire string not zeros
say sodium_is_zero($string); # 0
# first byte of string is zero
say sodium_is_zero($string, 1); # 1
# first two bytes of string is zero
say sodium_is_zero($string, 2); # 1
The sodium_is_zero function tests a string for all zeros.
use Sodium::FFI qw(sodium_library_minimal);
say sodium_library_minimal; # 0 or 1
The sodium_library_minimal
function lets you know if this is a minimal version.
use Sodium::FFI qw(sodium_library_version_major);
say sodium_library_version_major; # 10
The sodium_library_version_major
function returns the major version of the library.
use Sodium::FFI qw(sodium_library_version_minor);
say sodium_library_version_minor; # 3
The sodium_library_version_minor
function returns the minor version of the library.
use Sodium::FFI qw(sodium_memcmp);
my $string1 = "abcdef";
my $string2 = "abc";
my $match_length = 3;
# string 1 and 2 are equal for the first 3
say sodium_memcmp($string1, $string2, $match_length); # 0
# they are not equal for 4 slots
say sodium_memcmp("abcdef", "abc", 4); # -1
The sodium_memcmp
function compares two strings in constant time.
Results in -1
when strings 1 and 2 aren't equal.
Results in 0
when strings 1 and 2 are equal.
use Sodium::FFI qw(sodium_pad);
my $bin_string = "\x01";
my $block_size = 4;
say sodium_pad($bin_string, $block_size); # 01800000
The sodium_pad function adds padding data to a buffer in order to extend its total length to a multiple of the block size.
use Sodium::FFI qw(sodium_sub);
my $x = "\x02";
my $y = "\x01";
my $z = sodium_sub($x, $y);
say $x; # \x01
The sodium_sub function subtracts 2 large, unsigned numbers encoded in little-endian format.
use Sodium::FFI qw(sodium_unpad);
my $bin_string = "\x01\x80\x00\x00\x0";
my $block_size = 4;
say sodium_unpad($bin_string, $block_size); # 01
The sodium_unpad function
computes the original, unpadded length of a message previously
padded using sodium_pad
.
use Sodium::FFI qw(sodium_version_string);
say sodium_version_string; # 1.0.18
The sodium_version_string
function returns the stringified version information
for the version of LibSodium that you have installed.
Copyright 2020 Chase Whitener. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.