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::blake2b512digest::blake2s256digest::keccak256digest::md5digest::ripemd160digest::sha1digest::sha224digest::sha256digest::sha3_224digest::sha3_256digest::sha3_384digest::sha3_512digest::sha384digest::sha512digest::shake128digest::shake256digest::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:
blake2s256keccak256md5ripemd160sha1sha224sha256sha3_224sha3_256sha3_384sha3_512sha384sha512shake128shake256whirlpool
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-cfbmake-aes-256-cfb-cipheraes-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-ccmcipher::aes-128-ctrcipher::aes-128-gcmcipher::aes-192-ccmcipher::aes-192-ctrcipher::aes-192-gcmcipher::aes-256-ccmcipher::aes-256-ctrcipher::aes-256-gcm
Camellia
cipher::camellia-128-cbccipher::camellia-128-cfbcipher::camellia-128-ecbcipher::camellia-128-ofbcipher::camellia-192-cbccipher::camellia-192-cfbcipher::camellia-192-ecbcipher::camellia-192-ofbcipher::camellia-256-cbccipher::camellia-256-cfbcipher::camellia-256-ecbcipher::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-ecbcipher::aes-192-ecbcipher::aes-256-ecb
Blowfish
cipher::bf-cbccipher::bf-cfbcipher::bf-ecbcipher::bf-ofb
CAST5
cipher::cast5-cbccipher::cast5-cfbcipher::cast5-ecbcipher::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-cbccipher::aes-128-cfbcipher::aes-128-ofbcipher::aes-128-xtscipher::aes-192-cbccipher::aes-192-cfbcipher::aes-192-ofbcipher::aes-256-cbccipher::aes-256-cfbcipher::aes-256-ofbcipher::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.