mzcrypto

Contents

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.

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

Computes a message digest using the specified digest algorithm.

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

Equivalent to (hash <digest> input)

procedure: (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).

procedure: (generate-key <cipher>)
-> values: bytes bytes

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

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

Encipher using the specified cipher algorithm with key and iv.

procedure: (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:

procedure: (encrypt <cipher> key iv)
-> values: 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.

procedure: (decrypt <cipher> key iv)
-> values: 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.

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

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

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

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

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

Enciphers a plaintext byte string.

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

Deciphers a ciphertext byte string

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

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

procedure: (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.

procedure: (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.

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

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

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

Verify a signature using the public key pkey.

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

Encrypts data using public key pkey

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

Decrypts data using private key pkey

procedure: (encrypt/envelope pkey <cipher> ...)
-> values: 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.

procedure: (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.

procedure: (generate-key <dh>)
-> values: 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.

procedure: (compute-key dhkey bytes)
-> bytes

Computes a shared secret to complete a DH exchange.

Utilities

Digest Utilities

procedure: (available-digests)
-> list

List of available digest algorithms

procedure: (digest-size <digest>)

The output size of a digest algorithm

Cipher utilities

procedure: (available-ciphers)
-> list

List of available cipher algorithms

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

Cipher algorithm parameters

Public key utilities

procedure: (pkey? obj)
-> bool

Predicate for pkey objects

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

Equality comparison for the public components of two or more keys

procedure: (pkey-size pkey)
-> uint

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

procedure: (pkey-bits pkey)
-> uint

Strength of a pkey in bits

procedure: (pkey-private? pkey)
-> bool

True if the pkey is a private key

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

Exports/imports the private components of a pkey

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

Exports/imports the public components of a pkey.

procedure: (pkey->public-key pkey)
-> pkey

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

procedure: (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

procedure: (dh-bits <params>)

Strength of the specified dh parameters

procedure: (dhkey? object)
-> bool

True if object is a dhkey

procedure: (dhkey-size dhkey)
-> uint

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

Randomness

procedure: (random-bytes k)
-> bytes
procedure: (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")

procedure: (hex bytes)
-> bytes
procedure: (unhex bytes)
-> bytes

hex-encodes/decodes a byte string

procedure: (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.

procedure: (digest-new algorithm)
-> digest-object
procedure: (digest? object)
-> bool
procedure: (digest-update! obj bytes [start-k end-k])
procedure: (digest-final! obj [bytes [start-k end-k]])
-> values: bytes count
procedure: (digest-copy obj)
-> digest-object
procedure: (digest->bytes obj)
-> bytes
procedure: (digest-sign obj pkey [bytes [start-k end-k]])
-> values: bytes count
procedure: (digest-verify obj pkey bytes [start-k end-k])
-> bool
procedure: (cipher-encrypt algorithm (key : bytes) (iv: bytes))
-> cipher-object
procedure: (cipher-decrypt algorithm (key : bytes) (iv: bytes))
-> cipher-object
procedure: (cipher? object)
-> bool
procedure: (cipher-update! obj bytes [bytes [start-k end-k start-k end-k]])
-> values: bytes count
procedure: (cipher-final! obj [bytes [start-k end-k]])
-> values: 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