1Introduction to the Crypto Library
Cryptography is not security. It is a tool that may be used in somecases to achieve security goals.
This library is not a turn-key solution to security. It is a libraryof low-level cryptographic operations—
This manual assumes that you already know to use the cryptographicoperations properly. Every operation has conditions that must besatisfied for the operation’s security properties to hold; they arenot always well-advertised in documentation or literature, and theyare sometimes revised as new weaknesses or attacks arediscovered. Aside from the occasional off-hand comment, this manualdoes not discuss them at all. You are on your own.
1.1Cryptography Examples
In order to use a cryptographic operation, you need an implementationof it from a crypto provider. Implementations are managed throughcrypto factories. This introduction will use the factory for libcrypto(OpenSSL), since it is widely available and supports many usefulcryptographic operations. See Cryptography Factories for other cryptoproviders.
> (requirecrypto) > (requirecrypto/libcrypto)
You can configure this library with a “search path” of cryptofactories:
That allows you to perform an operation by providing a cryptoalgorithm specifier, which is automatically resolved to animplementation using the factories in (crypto-factories). Forexample, to compute a message digest, call the digestfunction with the name of the digest algorithm:
> (digest'sha1"Hello world!") #"\323Hj\351\23nxV\274B!#\205\352yp\224GX\2"
Or, if you prefer, you can obtain an algorithm implementationexplicitly:
> (definesha1-impl(get-digest'sha1libcrypto-factory)) > (digestsha1-impl"Hello world!") #"\323Hj\351\23nxV\274B!#\205\352yp\224GX\2"
To encrypt using a symmetric cipher, call the encryptfunction with a cipher specifier consisting of the name of the cipherand the cipher mode (see cipher-spec? for details).
> (defineskey#"VeryVerySecr3t!!") > (defineiv(make-bytes(cipher-iv-size'(aesctr))0)) > (encrypt'(aesctr)skeyiv"Hello world!") #"wu\345\215\e\16\256\355.\242\30x"
Of course, using an all-zero IV is usually a very bad idea. You cangenerate a random IV of the right size (if a random IV isappropriate), or you can get the IV size and construct one yourself:
> (defineiv(generate-cipher-iv'(aesctr))) > iv #"\351\256\17\\f\3505l\227\235\17\0007\376\vu"
> (cipher-iv-size'(aesctr)) 16
There are also functions to generate session keys, HMAC keys,etc. These functions use crypto-random-bytes, acryptographically strong source of randomness.
When an authenticated encryption (AEAD) cipher, such asAES-GCM, is used with encrypt or decrypt, theauthentication tag is automatically appended to (or taken from) theend of the cipher text, respectively. AEAD ciphers also supportadditionally authenticated data, passed with the #:aadkeyword.
> (definekey(generate-cipher-key'(aesgcm))) > (defineiv(generate-cipher-iv'(aesgcm))) > (definect(encrypt'(aesgcm)keyiv#"Nevermore!"#:aad#"quoth the raven")) > (decrypt'(aesgcm)keyivct#:aad#"quoth the raven") #"Nevermore!"
If authentication fails at the end of decryption, an exception israised:
> (decrypt'(aesgcm)keyivct#:aad#"said the bird") decrypt: authenticated decryption failed
In addition to “all-at-once” operations like digest andencrypt, this library also supports algorithm contexts forincremental computation.
> (definesha1-ctx(make-digest-ctx'sha1)) > (digest-updatesha1-ctx#"Hello ") > (digest-updatesha1-ctx#"world!") > (digest-finalsha1-ctx) #"\323Hj\351\23nxV\274B!#\205\352yp\224GX\2"
1.2Public-Key Cryptography Examples
Public-key (PK) cryptography uses keypairs consisting of public andprivate keys. A keypair can be generated by callinggenerate-private-key with the desired PK cryptosystem and anassociation list of key-generation options. The private key consistsof the whole keypair—
> (definersa-impl(get-pk'rsalibcrypto-factory)) > (defineprivkey(generate-private-keyrsa-impl'((nbits512)))) > (definepubkey(pk-key->public-only-keyprivkey))
RSA keys support both signing and encryption. Other PK cryptosystemsmay support different operations; for example, DSA supports signingbut not encryption, and DH only supports key agreement.
PK signature algorithms are limited in the amount of data they cansign directly, so the message is first processed with a digestfunction, then the digest is signed. The digest/sign anddigest/verify functions compute the digest automatically. Theprivate key signs, and the public key verifies.
> (definesig(digest/signprivkey'sha1"Hello world!")) > (digest/verifypubkey'sha1"Hello world!"sig) #t
> (digest/verifypubkey'sha1"Transfer $100"sig) #f
It is also possible to sign a precomputed digest. The digest algorithmis still required as an argument, because some signature schemes include adigest algorithm identifier.
> (definedgst(digest'sha1"Hello world!")) > (definesig(pk-sign-digestprivkey'sha1dgst)) > (pk-verify-digestpubkey'sha1(digest'sha1"Hello world!")sig) #t
> (pk-verify-digestpubkey'sha1(digest'sha1"Transfer $100")sig) #f
Encryption is similar, except that the public key encrypts, and theprivate key decrypts.
> (defineskey#"VeryVerySecr3t!!") > (definee-skey(pk-encryptpubkeyskey)) > (pk-decryptprivkeye-skey) #"VeryVerySecr3t!!"
The other PK operation is key agreement, or shared secretderivation. Two parties exchange public keys, and each party usestheir own private key together with their peer’s public key to derivea shared secret.
For additional examples, see the crypto/examples directory(online here).