Version: 4.1.3.3
mzcrypto
1 Overview
mzcrypto is a cryptographic library for mzscheme.
The library provides a high level interface for accessing primitives
from libcrypto.
To use this library you will need OpenSSL (0.9.8 or later) installed on
your system.
1.1 Installation
To use the library through PLaneT:
> (require (planet vyzo/crypto))
To locally install the library, extract the library archive to your
collects directory and run
setup-plt -l crypto
To use the local library:
> (require crypto)
To run basic tests on the library:
> (require (only crypto/test run-tests))
> (run-tests)
1.2 License
(C) Copyright 2007,2008 Dimitris Vyzovitis <vyzo at media.mit.edu>
mzcrypto is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
mzcrypto is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with mzcrypto. If not, see
<http://www.gnu.org/licenses/>.
2 API Organization
The API provided by mzcrypto is conceptually organized in 5 sections:
Each section documents the relevant scheme bindings, with
tutorial-style examples in Examples
3 Message Digests
3.1 Digest Algorithms
A <digest> is a first class object which captures algorithm details.
The set of digest algorithms depends on the local libcrypto configuration
and is determined at module load-time.
|
digest:ripemd160 : <digest> |
|
|
|
|
|
|
|
Digest algorithms. Bound to #f when an algorithm is unavailable.
List of available digest names.
True if o is a <digest>.
The block size of a digest algorithm
3.2 Computing Digests
Computes a digest for inp using t as the digest algorithm.
Shortcuts for (digest <digest> inp).
Computes an HMAC for inp using t as the digest algorithm
and key as the authentication key.
3.3 Low Level Digest Operations
Low level operations are performed on digest contexts for message
digest computations and hmac contexts for hmac computations.
(digest-new t) → digest? |
t : <digest> |
Create and initialize a new digest context
Incrementally update a digest context.
Finalize the digest context.
The first form returns the output; The second form
writes the output in outp which must have enough room for the
digest and return the digest size.
(digest-copy o) → digest? |
o : digest? |
Copies a digest context, which must not be finalized.
(digest->bytes o) → bytes? |
o : digest? |
Returns the current value of the digest.
True if o is a digest context.
(hmac-new t key) → hmac? |
t : <digest> |
key : bytes? |
Create and initialize a hmac context
Incrementally update an hmac context.
Finalize an hmac context.
True if o is an hmac context.
4 Symmetric Ciphers
4.1 Cipher Algorithms
A <cipher> is a first class object which captures cipher algorithm
details.
The set of cipher algorithms depends on the local libcrypto configuration
and is determined at module load-time.
|
cipher:des-ede : <cipher> |
|
cipher:des-ede3 : <cipher> |
|
|
|
|
cipher:aes-128 : <cipher> |
|
cipher:aes-192 : <cipher> |
|
cipher:aes-256 : <cipher> |
|
cipher:camellia-128 : <cipher> |
|
cipher:camellia-192 : <cipher> |
|
cipher:camellia-256 : <cipher> |
|
Cipher algorithms. Bound to #f when an algorithm is unavailable.
The default mode of operation is cbc. Different modes are bound to
<cipher>-mode, where mode is one of (ecb cbc cfb ofb).
List of available cipher names.
True if o is a <cipher>.
Return the block size, key length, and iv length of o
4.2 Encryption and Decryption
Encrypt with cipher c, using key as the secret key and
iv as the initialization vector.
The first form creates an encryption pipe.
The result is two values, an input-port where ciphertext can be
read from and an output-port where plaintext should be written to.
In the second form, when inp is a port a half-pipe is created that
reads plaintext from inp; the result is a ciphertext input-port.
When inp is a byte string, then it is synchronously encrypted
returning the ciphertext.
The third form synchronously encrypts plaintext from inp, writing
ciphertext to outp.
Decrypt with cipher c, using key as the secret key and
iv as the initialization vector.
Semantics of arguments and return values are symmetric to encrypt.
4.3 Low Level Cipher Operations
Low level operations are performed on cipher contexts.
The same set of operations is used both for encryption and decryption,
depending on the initialization of the context.
(cipher-encrypt t key iv [#:padding pad?]) → cipher? | t : <cipher> | key : bytes? | iv : bytes? | pad? : boolean? = #t |
|
(cipher-decrypt t key iv [#:padding pad?]) → cipher? | t : <cipher> | key : bytes? | iv : bytes? | pad? : boolean? = #t |
|
Create and initialize a cipher context for encryption or decryption
respectively.
Incrementally update a cipher context, with input ibs.
The first form returns the output of the update; the other two forms
write the output in obs, which must have room for at least
(cipher-block-length c) plus the input length, and return
the number of bytes written.
Finalize a cipher context.
The first form returns the final output block; the second form writes
the final output block in obs, which must have room for at least
(cipher-block-size c) bytes and return the number of bytes written.
True if o is a cipher context.
(cipher-encrypt? o) → boolean? |
o : cipher? |
True if o is a cipher-context used for encryption.
5 Public Key Cryptography
5.1 Algorithms and Keys
A <pkey> is a first class object which captures public key algorithm
details. Key-pairs can be generated using generate-key with a
<pkey>.
Builtin <pkey> algorithms.
True if o is a <pkey>.
True if o is a public or private key.
True if o is a private key.
(pkey->public-key o) → pkey? |
o : pkey? |
Extracts the public key component.
(public-key->bytes o) → bytes? | o : pkey? |
|
(private-key->bytes o) → bytes? | o : pkey? |
|
(bytes->public-key bs) → pkey? | bs : bytes? |
|
(bytes->private-key bs) → pkey? | bs : bytes? |
|
Conversions between keys and bytes.
The size of a key in bytes and bits respectively.
Key equality predicate.
5.2 Signatures
Computes a signature, using the private key pk and t
as the digest type.
Note: As of openssl-0.9.8 only certain types of digests can be used
with specific public key algorithms. Specifically, pkey:rsa keys
can only sign using sha* and ripemd160 as digests,
while pkey:dsa can only sign with dss1 digests.
This restriction has been removed in development versions of openssl (0.9.9).
Verifies a signature sig, using the public key pk and
t as the digest type.
Signature and verification using digest contexts directly.
5.3 Encryption
Encrypt and decrypt using a public/private key.
(encrypt/envelope pk c arg ...) | | → | | |
|
pk : pkey? |
c : <cipher> |
arg : _ |
Encrypt using c as the <cipher> with a random key
sealed using the public key pkey.
Returns the sealed key and iv for the cipher, prepended to the values
returned by the nested encrypt.
(decrypt/envelope pk c sk iv arg ...) | | → | | |
|
pk : pkey? |
c : <cipher> |
sk : bytes? |
iv : bytes? |
arg : _ |
Decrypt using c as the <cipher>, using the
sealed key sk decrypted with the private key pk.
6 Diffie-Hellman Key Exchange
Diffie-Hellman key parameters are encapsulated in instances of <dh>.
Keys can be generated from a parameter instance using generate-key.
Pre-computed Diffie-Hellman parameters from the OpenSSL project.
Computes a shared key using the private key priv and the peer
public key key.
True if o is a Diffie-Hellman key.
True if o is a <dh> parameter object.
The size in bites of the keys generated from o.
7 Utilities
7.1 Key Generation
Random key generation.
When t is a <cipher> instance the returned values are
a fresh key and iv for the algorithm.
When t is a <pkey> instance the bits argument
specifies the size of the requested key and the returned value is a fresh pkey.
For pkey:rsa the function optionally accepts an exponent argument
(defaults to 65537).
Finally, when t is a <dh> instance the returned values are
the private dh key and the public key part for the exchange.
7.2 Randomness
Generate cryptographically secure random data.
Generate pseudorandom data (not cryptographically secure).
|
|
|
|
(random-rnd-write f) → integer? | f : path |
|
(random-rnd-filename) → path? |
|
Query and manipulate the random entropy pool.
In general, you should not have to use these functions directly as libcrypto
automatically refreshes the entropy pool using OS-provided cryptographic
facilities.
7.3 Engine Support
(engine-load-builtin) → _ |
|
|
engine-load-builtin loads the builtin accelerated libcrypto engine
implementations.
The application must cleanup by explicitly calling engine-cleanup
as there is currently no reliable way to automatically cleanup using ffi.
7.4 Miscellaneous
This module provides some additional utilities that are not exported
by the main crypto library.
hex-encode and decode a byte-string
Compute the bitwise-xor of two byte-strings;
bytes-xor! computes the result in-place by mutating in.
key must be at least as long as in.
Returns (subbytes o len) when o is longer than len
and o otherwise.
8 Examples
In order to run the examples, you should first require the library and
the utilities module.
Using planet:
(require (planet vyzo/crypto) (planet vyzo/crypto/util))
Or if you have locally installed:
(require crypto crypto/util)
In the following we use this definition for msg
(define msg #"There is a cat in the box.")
8.1 Message Digests
Message digests are computed in two fundamental ways: one-shot or incrementally.
For one shot digest computations one can use the named digest functions or
the generic digest function:
(hex (sha1 msg)) |
=> #"2f888f0fa9a7cdd78fbbb15816f492d14b252e23" |
(hex (sha1 (open-input-bytes msg))) |
=> #"2f888f0fa9a7cdd78fbbb15816f492d14b252e23" |
(hex (digest digest:sha1 msg)) |
=> #"2f888f0fa9a7cdd78fbbb15816f492d14b252e23" |
For incremental computation we use digest-new, digest-update!,
and digest-final!.
(let ((dg (digest-new digest:sha1))) |
(digest-update! dg msg) |
(digest-final! dg)) |
=> #"2f888f0fa9a7cdd78fbbb15816f492d14b252e23" |
HMACs can be computed using hmac:
(let ((hkey (random-bytes (digest-size digest:sha1)))) |
(hex (hmac digest:sha1 hkey msg))) |
=> #"8ef155b9b05d11970241401eb23678df5db44686" |
8.2 Ciphers
In the following we encrypt msg using AES-128 (in the default cbc
mode).
First, we need to generate a key/iv pair:
(define-values (key iv) (generate-key cipher:aes-128))
To encrypt and decrypt directly:
(let ((ct (encrypt cipher:aes-128 key iv msg))) |
(decrypt cipher:aes-128 key iv ct)) |
=> #"There is a cat in the box." |
To encrypt and decrypt using ports:
(let* ((cin (encrypt cipher:aes-128 key iv (open-input-bytes msg))) |
(pin (decrypt cipher:aes-128 key iv cin))) |
(read-bytes 128 pin)) |
=> #"There is a cat in the box." |
Using pipes:
The pipe interface is quite flexible: encrypt can create a
ciphertext input-port and a plaintext output-port, while decrypt
can create a plaintext input-port and a ciphertext output-port.
The ports can be connected:
Finally, the most general interface is the low level interface, used internally
to implement the high level operations illustrated above.
cipher-encrypt and cipher-decrypt create cipher contexts;
the contexts can be updated incrementally with cipher-update!, while
cipher-final! completes the operation.
In this vain, we can implement custom encryption and decryption functions:
(define (my-encrypt key iv) |
(lambda (ptext) |
(let ((octx (cipher-encrypt cipher:aes-128 key iv))) |
(bytes-append (cipher-update! octx ptext) |
(cipher-final! octx))))) |
|
(define (my-decrypt key iv) |
(lambda (ctext) |
(let ((ictx (cipher-decrypt cipher:aes-128 key iv))) |
(bytes-append (cipher-update! ictx ctext) |
(cipher-final! ictx))))) |
|
((my-decrypt key iv) ((my-encrypt key iv) msg)) |
=> #"There is a cat in the box." |
8.3 Public Key Cryptography
The public key API uses the pkey type to encapsulate keys:
(define privk (generate-key pkey:rsa 1024)) |
(define pubk (pkey->public-key privk)) |
Signatures are computed using sign with the private key, and verified
using verify with the public key:
(let ((sig (sign privk digest:sha1 msg))) |
(verify pubk digest:sha1 sig msg)) |
=> #t |
The key pair can be used for direct encryption as well:
(let ((ct (encrypt/pkey pubk msg))) |
(decrypt/pkey privk ct)) |
=> #"There is a cat in the box." |
However, public keys are rarely used directly for encryption. Rather, the
key pair is used to encrypt/decrypt a sealed key and then perform
symmetric encryption using a cipher. This pattern is simplified using
encrypt/envelope and decrypt/envelope:
(let-values (((skey iv ct) (encrypt/envelope pubk cipher:aes-128 msg))) |
(decrypt/envelope privk cipher:aes-128 skey iv ct)) |
=> #"There is a cat in the box." |
8.4 Diffie-Hellman Key Exchange
In order to perform a DH key exchange, a pair of peers each generates a key
pair using generate-key and exchange the public keys.
The shared key can then be computed using compute-key: