doc.txt

== Introduction

==== _crypto.ss_
== Introduction

mzcrypto is a cryptographic library for mzscheme.

The library provides a high level interface for accessing primitives
from libcrypto.
To use the library you will need OpenSSL installed on your system.

To load the library:
>> (require (lib "crypto.ss" "crypto"))

To run some basic tests:
>> (require (only (lib "test.ss" "crypto") run-tests))
>> (run-tests)

=== License

mzcrypto: crypto library for mzscheme
Copyright (C) 2007 Dimitris Vyzovitis <vyzo@media.mit.edu>

This library 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 2.1 of the License, or (at your option) any later version.

This library 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 this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA

== API

-- Message Digests

> digest:md5
> digest:ripemd160
> digest:dss1
> digest:sha1
> digest:sha224
> digest:sha256
> digest:sha384
> digest:sha512

Message digest algorithms. Bound to #f when an algorithm is unavailable.

> (hash <digest> bytes-or-port) 
  -> bytes

Computes a message digest using the specified digest algorithm.

> (md5 bytes-or-port)
> (ripemed bytes-or-port)
> (dss1 bytes-or-port)
> (sha1 bytes-or-port)
> (sha224 bytes-or-port)
> (sha256 bytes-or-port)
> (sha384 bytes-or-port)
> (sha512 bytes-or-port)

Equivalent to (hash <digest> input)

> (hmac <digest> (key : bytes) bytes-or-port)
  -> bytes

Computes an HMAC with the specified digest algorithm, using key as the 
shared secret.

-- Ciphers

> cipher:des
> cipher:des-ede
> cipher:des-ede3
> cipher:idea
> cipher:bf
> cipher:cast5
> cipher:aes-128
> cipher:aes-192
> cipher:aes-256
> cipher:camellia-128
> cipher:camellia-192
> cipher:camellia-256

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).

> (generate-key <cipher>)
  -> (bytes bytes)

Generates a random key and a pseudo-random iv for symmetric encryption
with the specified cipher algorithm.

> (encrypt <cipher> (key : bytes) (iv : bytes) ...)

Encipher using the specified cipher algorithm with key and iv.

> (decrypt <cipher> (key : bytes) (iv : bytes) ...)

Decipher using the specified cipher algorithm with key and iv.

The behavior and return values of these functions depends on their arguments:

> (encrypt <cipher> key iv)
  -> (input-port output-port)

Creates an encryption pipe.

The result is two values: an input-port for reading the ciphertext
and an output-port for writing the plaintext.
Close the ciphertext port when you are done.

> (decrypt <cipher> key iv)
  -> (input-port output-port)

Creates a decryption pipe.

The result is two values: an input-port for reading the plaintext
and an output-port for writing the ciphertext. 
Close the plaintext port when you are done.

> (encrypt <cipher> key iv input-port)
  -> input-port

Enciphers plaintext from an input-port.
The result is a ciphertext input-port.

> (decrypt <cipher> key iv input-port)
  -> input-port

Deciphers ciphertext from an input-port.
The result is a plaintext input-port.

> (encrypt <cipher> key iv bytes)
  -> bytes

Enciphers a plaintext byte string.

> (decrypt <cipher> key iv bytes)
  -> bytes

Deciphers a ciphertext byte string

> (encrypt <cipher> key iv input-port output-port)

Enciphers plaintext from an input-port to an output port.

> (decrypt <cipher> key iv input-port output-port)

Deciphers ciphertext from an input-port to an output port

-- Public Key Cryptography

> pkey:rsa
> pkey:dsa

Public key algorithms. Bound to #f when an algorithm is unavailable.

Key-pairs for public key operations are contained in pkey objects.

> (generate-key <pkey> n ...)
  -> pkey

Generates a random n-bit key, as a pkey object, for public key operations
with the specified public key algorithm.

RSA key generation accepts as keyword #:exponent the public exponent, with
default value 65537.

> (sign pkey <digest> bytes-or-port)
  -> bytes

Sign using the private key pkey and the specified digest algorithm.

> (verify pkey <digest> (signature : bytes) bytes-or-port)
  -> bool

Verify a signature using the public key pkey.

> (encrypt/pkey pkey bytes [start-k end-k])
  -> bytes

Encrypts data using public key pkey

> (decrypt/pkey pkey bytes [start-k end-k])
  -> bytes

Decrypts data using private key pkey

> (encrypt/envelope pkey <cipher> ...)
  -> (bytes bytes ...)

Generates a random key and pseudo random iv and encrypts using the 
specified cipher algorithm.

The first value returned is the sealed secret key (encrypted with public 
key pkey), while the second value is the iv. 

> (decrypt/envelope pkey <cipher> (sk : bytes) (iv : bytes) ...)
  -> ...

Unseals the secret key sk using the private key pkey, and decrypts using
the specified cipher algorithm.

-- Diffie-Hellman Key Exchange

> dh:128
> dh:512
> dh:1024
> dh:2048
> dh:4096

Parameters for Diffie-Hellman key exchange. 
These are the defaults provided by the OpenSSL project. 

> (generate-key <dh>)
  -> (dhkey bytes)

Generates a key-pair to initiate a DH exchange with the specified parameters.

The result is two values: A private DH key as an opaque dh object and 
a public key as a byte string.

> (compute-key dhkey bytes)
  -> bytes

Computes a shared secret to complete a DH exchange.

-- Utilities

--- Digest Utilities

> (available-digests)
  -> list

List of available digest algorithms

> (digest-size <digest>)

The output size of a digest algorithm

--- Cipher utilities

> (available-ciphers)
  -> list

List of available cipher algorithms

> (cipher-block-size <cipher>)
  -> uint
> (cipher-key-length <cipher>)
  -> uint
> (cipher-iv-length <cipher>)
  -> uint

Cipher algorithm parameters

--- Public key utilities

> (pkey? obj)
  -> bool

Predicate for pkey objects

> (pkey=? pkey pkey ...)
  -> bool

Equality comparison for the public components of two or more keys

> (pkey-size pkey)
  -> uint

Public key size.
This is the max input size for pkey encryption and the max output size
for pkey signatures.

> (pkey-bits pkey)
  -> uint

Strength of a pkey in bits

> (pkey-private? pkey)
  -> bool

True if the pkey is a private key

> (private-key->bytes pkey) 
  -> bytes
> (bytes->private-key <pkey> bytes)
  -> pkey

Exports/imports the private components of a pkey

> (public-key->bytes pkey)
  -> bytes
> (bytes->public-key <pkey> bytes)
  -> pkey

Exports/imports the public components of a pkey.

> (pkey->public-key pkey)
  -> pkey

Creates a pkey object that contains only the public components of pkey.

> (pkey-digest? <pkey> <digest>)

Checks whether a digest algorithm can be used with a public key algorithm.

In libcrypto-0.9.8 and earlier versions, dsa keys can only be used with dss1.
rsa keys can be used with any digest algorithm.

--- Diffie-Hellman utilities

> (dh-bits <params>)

Strength of the specified dh parameters

> (dhkey? object)
  -> bool
True if object is a dhkey

> (dhkey-size dhkey)
  -> uint

The size of the shared secret computed by a DH exchange with a dhkey

--- Randomness

> (random-bytes k)
  -> bytes
> (pseudo-random-bytes k)
  -> bytes

Generates k (pseudo-)random bytes

--- Miscellaneous

The following procedures are not provided by default. You can import them
by requiring (lib "util.ss" "crypto") 

> (hex bytes)
  -> bytes
> (unhex bytes)
  -> bytes

hex-encodes/decodes a byte string

> (shrink-bytes bytes length)
  -> bytes

Shrinks a byte string to a given length.

-- Low level API

The following procedures may be useful for incremental operation using
byte strings.

> (digest-new algorithm) 
  -> digest-object
> (digest? object) 
  -> bool
> (digest-update! obj bytes [start-k end-k])
> (digest-final! obj [bytes [start-k end-k]]) 
  -> (bytes count) 
> (digest-copy obj) 
  -> digest-object
> (digest->bytes obj) 
  -> bytes
> (digest-sign obj pkey [bytes [start-k end-k]])
  -> (bytes count)
> (digest-verify obj pkey bytes [start-k end-k])
  -> bool
> (cipher-encrypt algorithm (key : bytes) (iv: bytes)) 
  -> cipher-object
> (cipher-decrypt algorithm (key : bytes) (iv: bytes)) 
  -> cipher-object
> (cipher? object)
  -> bool
> (cipher-update! obj bytes [bytes [start-k end-k start-k end-k]])
  -> (bytes count)
> (cipher-final! obj [bytes [start-k end-k]])
  -> (bytes count)

=== Examples

;; let's play with the cat
(require (lib "crypto.ss" "crypto") 
         (lib "util.ss" "crypto")) ; for hex
(define msg #"There is a cat in the box.")

;; sha1 hash
(hex (sha1 msg))
=> #"2f888f0fa9a7cdd78fbbb15816f492d14b252e23"

;; same with a port
(hex (sha1 (open-input-bytes msg)))
=> #"2f888f0fa9a7cdd78fbbb15816f492d14b252e23"

;; an hmac with sha1
(define hkey (random-bytes 20))
(hex (hmac digest:sha1 hkey msg))
=> #"4e9474cd5b283133e152b884502025183d7d5b25"

;; and with a port
(hex (hmac digest:sha1 hkey (open-input-bytes msg)))
=> #"4e9474cd5b283133e152b884502025183d7d5b25"

;; aes encryption
(define-values (key iv) (generate-key cipher:aes-128))
(define ct (encrypt cipher:aes-128 key iv msg))
(decrypt cipher:aes-128 key iv ct)
=> #"There is a cat in the box."

;; with 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."

;; with pipes
(let-values (((pin) (open-input-bytes msg))
             ((cin cout) (make-pipe))
             ((pout) (open-output-bytes)))
  (encrypt cipher:aes-128 k iv pin cout)
  (close-output-port cout)
  (decrypt cipher:aes-128 k iv cin pout)
  (get-output-bytes pout))
=> #"There is a cat in the box."

(let-values (((cin pout) (encrypt cipher:aes-128 k iv))
             ((pin cout) (decrypt cipher:aes-128 k iv)))
      (write-bytes msg pout)
      (close-output-port pout)
      (write-bytes (read-bytes 128 cin) cout)
      (close-output-port cout)
      (read-bytes 128 pin))
=> #"There is a cat in the box."

;; public keys
(define privk (generate-key pkey:rsa 1024))
(define pubk (pkey->public-key privk))

;; Signatures
(define sig (sign privk digest:sha1 msg))
(verify pubk digest:sha1 sig msg)
=> #t

;; Direct encryption
(define ct (encrypt/pkey pubk msg))
(decrypt/pkey privk ct)
=> #"There is a cat in the box."

;; Envelope encryption
(define-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."

;; Diffie-Hellman key exchange
(define-values (priv1 pub1) (generate-key dh:1024))
(define-values (priv2 pub2) (generate-key dh:1024))
(define sk1 (compute-key priv1 pub2))
(define sk2 (compute-key priv2 pub1))
(equal? sk1 sk2)
=> #t