Cryptography
Cryptography based on libcrypto.
usage
(import :std/crypto)
Digests
Examples:
(import :std/crypto
(only-in :std/text/hex hex-encode))
(let ((d (make-digest digest::sha256)))
(digest-update! d (@bytes "Hello Gerbil"))
(hex-encode (digest-final! d)))
;; => "b202f46d2ef4fc97f3628d6619b50911bc09c29550102b2c0d3976b8ad33f204"
(hex-encode (sha256 (@bytes "Hello Gerbil")))
;; => "b202f46d2ef4fc97f3628d6619b50911bc09c29550102b2c0d3976b8ad33f204"
make-digest
(make-digest type) => digest
Create a new digest using the given type of cryptographic hash function.
Available cryptographic hash functions
digest::blake2b512
digest::blake2s256
digest::keccak256
digest::md5
digest::ripemd160
digest::sha1
digest::sha224
digest::sha256
digest::sha3_224
digest::sha3_256
digest::sha3_384
digest::sha3_512
digest::sha384
digest::sha512
digest::shake128
digest::shake256
digest::whirlpool
digest?
(digest? var) => :boolean
Test if variable is a digest.
digest-update!
(digest-update! digest bytes (start #f) (end #f)) => :fixnum
Update a digest object. Returns 1 for success and 0 for failure.
digest-update*
(digest-update* digest input (start #f) (end #f)) => :fixnum
Like digest-update!
, but uses call-with-binary-input
to accept either a u8vector
, string
or input-port
.
digest-final!
(digest-final! digest (bytes #f)) => :u8vector
Finalize the digest and extract the hash from the digest.
The digest will not longer be usable after finalization.
Use :std/text/hex#hex-encode
to convert to a hex string.
digest-size
(digest-size digest) => :fixnum
Returns the digest or block size in bytes or -1 for failure.
digest-name
(digest-name digest) => :string
Get the name of the cryptographic hash function by a digest or digest type.
(digest-name digest::sha256)
;; => "SHA256"
(digest-name (make-digest digest::sha256))
;; => "SHA256"
digest-copy
(digest-copy digest) => digest
Create a new digest that is a copy of an existing. This is useful if large amounts of data are to be hashed which only differ in the last few bytes.
md5
(md5 in) => :u8vector
Convenience function to hash a u8vector
, string
or input-port
and return the finalized bytes.
sha1
(sha1 in) => :u8vector
Convenience function to hash a u8vector
, string
or input-port
and return the finalized bytes.
sha224
(sha224 in) => :u8vector
Convenience function to hash a u8vector
, string
or input-port
and return the finalized bytes.
sha256
(sha256 in) => :u8vector
Convenience function to hash a u8vector
, string
or input-port
and return the finalized bytes.
sha384
(sha384 in) => :u8vector
Convenience function to hash a u8vector
, string
or input-port
and return the finalized bytes.
whirlpool
(whirlpool in) => :u8vector
Convenience function to hash a u8vector
, string
or input-port
and return the finalized bytes.
ripemd160
(ripemd160 in) => :u8vector
Convenience function to hash a u8vector
, string
or input-port
and return the finalized bytes.
Digest Objects
Various symbols are created for each cryptographic hash function. For instance, for "sha512" the following are created:
- Type for digest constructor ::
digest::sha512
- Typed digest constructor ::
make-sha512-digest
- Digest type predicate ::
sha512-digest?
- Input to byte vector convenience function ::
sha512
The list of cryptographic hash functions that follow this patterns are:
blake2s256
keccak256
md5
ripemd160
sha1
sha224
sha256
sha3_224
sha3_256
sha3_384
sha3_512
sha384
sha512
shake128
shake256
whirlpool
Example
digest::whirlpool
make-whirlpool-digest
whirlpool-digest?
whirlpool
digest::sha3_256
make-sha3_256-digest
sha3_256-digest?
sha3_256
digest::md5
make-md5-digest
md5-digest?
md5
Ciphers
cipher
These are used to create ciphers, which are used for encryption.
make-cipher
(make-cipher type) => cipher
Create a cipher
with the specified cipher type.
Cipher Types
These follow the pattern "cipher::TYPE". A convenience function also exists for each type to create the cipher as well as a type checker.
Examples:
cipher::aes-256-cfb
make-aes-256-cfb-cipher
aes-256-cfb-cipher?
Recommended for Modern Security Standards
These ciphers are considered secure and are recommended for modern security standards:
AES (Advanced Encryption Standard)
cipher::aes-128-ccm
cipher::aes-128-ctr
cipher::aes-128-gcm
cipher::aes-192-ccm
cipher::aes-192-ctr
cipher::aes-192-gcm
cipher::aes-256-ccm
cipher::aes-256-ctr
cipher::aes-256-gcm
Camellia
cipher::camellia-128-cbc
cipher::camellia-128-cfb
cipher::camellia-128-ecb
cipher::camellia-128-ofb
cipher::camellia-192-cbc
cipher::camellia-192-cfb
cipher::camellia-192-ecb
cipher::camellia-192-ofb
cipher::camellia-256-cbc
cipher::camellia-256-cfb
cipher::camellia-256-ecb
cipher::camellia-256-ofb
Not Recommended for Modern Security Standards
These ciphers are not recommended due to known vulnerabilities or weaker security:
AES (using ECB mode)
cipher::aes-128-ecb
cipher::aes-192-ecb
cipher::aes-256-ecb
Blowfish
cipher::bf-cbc
cipher::bf-cfb
cipher::bf-ecb
cipher::bf-ofb
CAST5
cipher::cast5-cbc
cipher::cast5-cfb
cipher::cast5-ecb
cipher::cast5-ofb
RC4
cipher::rc4
Neutral or Situational Use
These ciphers can be secure in certain contexts but might have specific use cases or be less commonly recommended:
- AES (other modes)
cipher::aes-128-cbc
cipher::aes-128-cfb
cipher::aes-128-ofb
cipher::aes-128-xts
cipher::aes-192-cbc
cipher::aes-192-cfb
cipher::aes-192-ofb
cipher::aes-256-cbc
cipher::aes-256-cfb
cipher::aes-256-ofb
cipher::aes-256-xts
cipher?
(cipher? var) => :boolean
Test if variable is a cipher.
cipher-type
(cipher-type cipher) => EVP_CIPHER*
Returns the cipher type, like cipher::aes-256-cfb
.
cipher-ctx
(cipher-ctx cipher) => EVP_CIPHER_CTX*
Get the context from the cipher. Returns #f if cipher already finalized.
cipher-context
(cipher-context cipher) => EVP_CIPHER_CTX*
Get the context from the cipher. Errors if cipher already finalized.
cipher-name
(cipher-name cipher) => :string
Gets the string name of the cipher, like "AES-256-ECB".
cipher-block-size
(cipher-block-size cipher) => :fixnum
Get the number of bytes used per block.
cipher-key-length
(cipher-key-length cipher) => :fixnum
Get the number of bytes used for keys for this cipher.
cipher-iv-length
(cipher-iv-length cipher) => :fixnum
Get the number of bytes used for the IV for this cipher.
cipher-copy
(cipher-copy cipher) => cipher
Create a copy of a cipher.
Cipher Objects
cipher::rc4
make-rc4-cipher
rc4-cipher?
cipher::bf-ofb
make-bf-ofb-cipher
bf-ofb-cipher?
cipher::bf-cfb
make-bf-cfb-cipher
bf-cfb-cipher?
cipher::bf-cbc
make-bf-cbc-cipher
bf-cbc-cipher?
cipher::bf-ecb
make-bf-ecb-cipher
bf-ecb-cipher?
cipher::cast5-ofb
make-cast5-ofb-cipher
cast5-ofb-cipher?
cipher::cast5-cfb
make-cast5-cfb-cipher
cast5-cfb-cipher?
cipher::cast5-cbc
make-cast5-cbc-cipher
cast5-cbc-cipher?
cipher::cast5-ecb
make-cast5-ecb-cipher
cast5-ecb-cipher?
cipher::camellia-256-ofb
make-camellia-256-ofb-cipher
camellia-256-ofb-cipher?
cipher::camellia-256-cfb
make-camellia-256-cfb-cipher
camellia-256-cfb-cipher?
cipher::camellia-256-cbc
make-camellia-256-cbc-cipher
camellia-256-cbc-cipher?
cipher::camellia-256-ecb
make-camellia-256-ecb-cipher
camellia-256-ecb-cipher?
cipher::camellia-192-ofb
make-camellia-192-ofb-cipher
camellia-192-ofb-cipher?
cipher::camellia-192-cfb
make-camellia-192-cfb-cipher
camellia-192-cfb-cipher?
cipher::camellia-192-cbc
make-camellia-192-cbc-cipher
camellia-192-cbc-cipher?
cipher::camellia-192-ecb
make-camellia-192-ecb-cipher
camellia-192-ecb-cipher?
cipher::camellia-128-ofb
make-camellia-128-ofb-cipher
camellia-128-ofb-cipher?
cipher::camellia-128-cfb
make-camellia-128-cfb-cipher
camellia-128-cfb-cipher?
cipher::camellia-128-cbc
make-camellia-128-cbc-cipher
camellia-128-cbc-cipher?
cipher::camellia-128-ecb
make-camellia-128-ecb-cipher
camellia-128-ecb-cipher?
cipher::aes-256-xts
make-aes-256-xts-cipher
aes-256-xts-cipher?
cipher::aes-256-gcm
make-aes-256-gcm-cipher
aes-256-gcm-cipher?
cipher::aes-256-ccm
make-aes-256-ccm-cipher
aes-256-ccm-cipher?
cipher::aes-256-ctr
make-aes-256-ctr-cipher
aes-256-ctr-cipher?
cipher::aes-256-ofb
make-aes-256-ofb-cipher
aes-256-ofb-cipher?
cipher::aes-256-cfb
make-aes-256-cfb-cipher
aes-256-cfb-cipher?
cipher::aes-256-cbc
make-aes-256-cbc-cipher
aes-256-cbc-cipher?
cipher::aes-256-ecb
make-aes-256-ecb-cipher
aes-256-ecb-cipher?
cipher::aes-192-gcm
make-aes-192-gcm-cipher
aes-192-gcm-cipher?
cipher::aes-192-ccm
make-aes-192-ccm-cipher
aes-192-ccm-cipher?
cipher::aes-192-ctr
make-aes-192-ctr-cipher
aes-192-ctr-cipher?
cipher::aes-192-ofb
make-aes-192-ofb-cipher
aes-192-ofb-cipher?
cipher::aes-192-cfb
make-aes-192-cfb-cipher
aes-192-cfb-cipher?
cipher::aes-192-cbc
make-aes-192-cbc-cipher
aes-192-cbc-cipher?
cipher::aes-192-ecb
make-aes-192-ecb-cipher
aes-192-ecb-cipher?
cipher::aes-128-xts
make-aes-128-xts-cipher
aes-128-xts-cipher?
cipher::aes-128-gcm
make-aes-128-gcm-cipher
aes-128-gcm-cipher?
cipher::aes-128-ccm
make-aes-128-ccm-cipher
aes-128-ccm-cipher?
cipher::aes-128-ctr
make-aes-128-ctr-cipher
aes-128-ctr-cipher?
cipher::aes-128-ofb
make-aes-128-ofb-cipher
aes-128-ofb-cipher?
cipher::aes-128-cfb
make-aes-128-cfb-cipher
aes-128-cfb-cipher?
cipher::aes-128-cbc
make-aes-128-cbc-cipher
aes-128-cbc-cipher?
cipher::aes-128-ecb
make-aes-128-ecb-cipher
aes-128-ecb-cipher?
Encryption and Decryption
Example:
(let* ((plaintext "Hello Gerbil!")
(cipher (make-aes-256-cfb-cipher))
(key-length (cipher-key-length cipher))
(key (random-bytes key-length))
(iv-length (cipher-iv-length cipher))
(iv (random-bytes iv-length))
(encrypted-data (encrypt cipher key iv plaintext)))
(utf8->string (decrypt (make-aes-256-cfb-cipher) key iv encrypted-data)))
;; => "Hello Gerbil!"
encrypt
(encrypt cipher key iv in) => :u8vector
Encrypt a u8vector
, string
or input-port
and return the encrypted bytes.
encrypt-u8vector
(encrypt-u8vector cipher key iv in (start 0) (end (u8vector-length in))) => :u8vector
Encrypt a u8vector, with optional parameters to specify the start and end indices for the portion of the vector to be encrypted. Returns the encrypted bytes.
encrypt-u8vector!
(encrypt-u8vector! cipher key iv bytes start end buf) => :fixnum
Encrypt and finalize buffer buf
using input from bytes
.
Returns the number of bytes written.
encrypt-init!
(encrypt-init! cipher key iv)
Initializes the cipher with the key and IV.
encrypt-update!
(encrypt-update! cipher out out-start in start end) => :fixnum
Encrypts data from in
buffer writes it to out
then returns the number of bytes written.
This function can be called multiple times to encrypt successive blocks of data.
The amount of data written depends on the block alignment of the encrypted data.
For most ciphers and modes, the amount of data written can be anything from zero bytes to in-length + cipher-block-size - 1
bytes.
For wrap cipher modes, the amount of data written can be anything from zero bytes to in-length + cipher-block-size
bytes.
For stream ciphers, the amount of data written can be anything from zero bytes to in-length
bytes.
Thus, out should contain sufficient room for the operation being performed.
It also checks if in and out are partially overlapping, and if they are an error is thrown.
encrypt-final!
(encrypt-final! cipher out (out-start 0)) => :fixnum
Encrypts the "final" data, that is any data that remains in a partial block. It uses standard block padding (aka PKCS padding). The encrypted final data is written to out which should have sufficient space for one cipher block. The number of bytes written is returned. After this function is called the encryption operation is finished and the cipher may no longer be used.
decrypt
(decrypt cipher key iv in) => :u8vector
Decrypt a u8vector
or input-port
and return the decrypted bytes.
decrypt-u8vector
(decrypt-u8vector cipher key iv in (start 0) (end (u8vector-length in))) => :u8vector
Decrypt a u8vector, with optional parameters to specify the start and end indices for the portion of the vector to be decrypted. Returns the decrypted bytes.
decrypt-u8vector!
(decrypt-u8vector! cipher key iv bytes start end buf) => :fixnum
Decrypt and finalize buffer buf
using input from bytes
.
Returns the number of bytes written.
decrypt-init!
(decrypt-init! cipher key iv)
Initializes the cipher with the key and IV.
decrypt-update!
(decrypt-update! cipher out out-start in start end) => :fixnum
Decrypts data from in
buffer writes it to out
then returns the number of bytes written.
Mirrors encrypt-update!.
The parameters and restrictions are identical except that the decrypted data buffer out passed to decrypt-update!
should have sufficient room for in-length + cipher-block-size
bytes unless the cipher block size is 1 in which case in-length
bytes is sufficient.
decrypt-final!
(decrypt-final! cipher out (out-start 0)) => :fixnum
Mirror of encrypt-final!.
HMAC
Hash-based message authentication code. It may be used to simultaneously verify both the data integrity and authenticity of a message.
hmac?
(hmac? var) => :boolean
Test if variable is an hmac object.
make-hmac
(make-hmac md) => hmac
Create a hmac using a [digest type][#digest_objects], such as digest::sha256
.
hmac-init!
(hmac-init! hmac key)
Initialize the hmac
to use the given key
.
hmac-update!
(hmac-update! hmac bytes (start #f) (end #f))
Update hmac with chunk of message to be authenticated. Can be called repeatedly with chunks of the message to be authenticated.
hmac-final!
(hmac-final! hmac (bytes #f)) => :u8vector
Returns the message authentication code.
Output buffer may be passed in as bytes
, which must have space for the hash function output.
hmac-digest
(hmac-digest md key bytes (start #f) (end #f)) => :u8vector
Create an authentication code using a [digest type][#digest_objects], such as digest::sha256
.
hmac-md5
(hmac-md5 key bytes (start #f) (end #f)) => :u8vector
Create an authentication code using MD5.
hmac-sha1
(hmac-sha1 key bytes (start #f) (end #f)) => :u8vector
Create an authentication code using SHA1.
hmac-sha256
(hmac-sha256 key bytes (start #f) (end #f)) => :u8vector
Create an authentication code using SHA256.
hmac-sha384
(hmac-sha384 key bytes (start #f) (end #f)) => :u8vector
Create an authentication code using SHA384.
hmac-sha512
(hmac-sha512 key bytes (start #f) (end #f)) => :u8vector
Create an authentication code using SHA512.
DH Key Exchange
DH-generate-key
(DH-generate-key dh)
Setup the dh, which is provided by the DH-get-
functions.
DH-generate-key
performs the first step of a Diffie-Hellman key exchange by generating private and public DH values.
By calling DH-compute-key
, these are combined with the other party's public value to compute the shared key.
DH-get-2048-256
(DH-get-2048-256) => DH
Deprecated in OpenSSL. Create a DH object.
DH-get-2048-224
(DH-get-2048-224) => DH
Deprecated in OpenSSL. Create a DH object.
DH-get-1024-160
(DH-get-1024-160) => DH
Deprecated in OpenSSL. Create a DH object.
DH-compute-key
(DH-compute-key dh bn) => :u8vector
dh
is the DH
returned from functions like DH-get-1024-160
.
bn
is the pubkey created by DH-pub-key
.
The computed shared secret is returned.
DH-pub-key
(DH-pub-key dh) => BN
Returns public key from dh.
EVP Key and Parameter Generation
keygen/ed25519
(keygen/ed25519) => pkey
Performs a key generation operation using the ED25519 keytype.
bytes->private-key
(bytes->private-key type bytes engine: (engine #f)) => pkey
Convert bytes
to a private key pkey
.
bytes->public-key
(bytes->public-key type bytes engine: (engine #f)) => pkey
Convert bytes
to a public key pkey
.
private-key->bytes
(private-key->bytes pkey (bytes #f)) => :u8vector
Get the private key from a pkey
.
Optional buffer bytes
can be passed in to be used and returned.
Returns #f
if invalid pkey passed in.
public-key->bytes
(public-key->bytes pkey (bytes #f))
Get the public key from a pkey
.
Optional buffer bytes
can be passed in to be used and returned.
Returns #f
if invalid pkey passed in.
digest-sign
(digest-sign pkey bytes sig: (sig #f)) => :u8vector
Sign bytes using pkey.
Optional buffer siq
can be passed in to be used and returned.
digest-verify
(digest-verify pkey sig bytes) => :boolean
Verify bytes
matches sig
using pkey
.
scrypt
(scrypt pass salt size (N 1024) (r 8) (p 16)) => :u8vector
The scrypt algorithm implements the scrypt password based key derivation function, as described in RFC 7914. It is memory-hard in the sense that it deliberately requires a significant amount of RAM for efficient computation. The intention of this is to render brute forcing of passwords on systems that lack large amounts of main memory (such as GPUs or ASICs) computationally infeasible.
scrypt
provides three work factors that can be customized: N
, r
and p
.
N
, which has to be a positive power of two, is the general work factor and scales CPU time in an approximately linear fashion.
r
is the block size of the internally used hash function and p
is the parallelization factor.
Both r
and p
need to be greater than zero.
The amount of RAM that scrypt
requires for its computation is roughly 128 * N * r * p
bytes.
EVP Key types
EVP_PKEY_ED25519
etc
libcrypto-error?
(libcrypto-error? e) => :boolean
Test if error is a libcrypto-error.
random-bytes
(random-bytes len) => :u8vector
Generate random bytes.
random-bytes!
(random-bytes! bytes (start 0) (end (u8vector-length bytes)))
Generate random bytes into an existing buffer.
bytes->BN
(BN->bytes bn) => :u8vector
Converts the absolute value of bn into big-endian form and returns it as a vector.
BN->bytes
(bytes->BN bytes (start 0) (end #f)) => BN
Convert bytes into BN.