15. Bigloo
A ``practical Scheme compiler''
User manual for version 3.4a
July 2010 -- Cryptography
Bigloo provides several functions for encrypting and decrypting documents. These are described in the chapter. Unless explicitly mentioned all functions presented in this document are accessible via the crypto library.

None of the cryptographic functions are protected against timing attacks. No effort has been spent on protecting used memory.

Here is an example of a module that uses this library:

;; Encrypt a string using AES.
(module aes-encrypt
   (library crypto)
   (main main))

(define (main argv) (when (pair? (cdr argv) (cddr argv)) (let ((encrypt? (string=? "-e" (cadr argv))) (passwd (caddr argv)) (input (read-string))) (if encrypt? (display (encrypt 'aes input passwd)) (display (decrypt 'aes input passwd))))))


15.1 Symmetric Block Ciphers

Bigloo supports some common block ciphers. Block ciphers work on blocks of fixed size. A mode of operation defines the way bigger input is handled. For instance in ECB (Electronic Codebook mode) the blocks are all encrypted separately, whereas CBC (Cipher-Block Chaining) chains all blocks.

All modes that chain the blocks need an IV (Initial Vector) to ``bootstrap'' the chaining.

Block ciphers by themselves can only work on full blocks. Some modes are constructed in a way that even incomplete blocks can be safely processed. For the remaining blocks a padding function needs to be given.

Most block ciphers only work with keys of specific length. The following functions take passwords (strings of arbitrary length) as input, and preprocess the given password by a :string->key function. The result must then be of correct length.

encrypt::bstring cipher plain password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
encrypt-string::bstring cipher plaintext::bstring password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
encrypt-mmap::bstring cipher plaintext::mmap password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
encrypt-port::bstring cipher plaintext::input-port password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
encrypt-file::bstring cipher filename::bstring password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
encrypt-sendchars cipher in::input-port out::output-port password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
The procedure encrypt encrypts its input using the chosen cipher. The result is returned as string. encrypt dispatches depending on the type of plain. Strings are processed by encrypt-string (and not encrypt-file).

The function encrypt-sendchars reads from an input-port in and encrypts its output directly into an output-port out.

The symbol cipher can be one of:
  • des: Data Encryption Standard (DES). DES works on blocks of 64 bits. DES requires keys of length 64 (bits), but only 56 of these bits are actually used. Bigloo's implementation therefore accepts both. DES is considered to be insecure and its usage is discouraged.
  • des3: Triple DES, Triple Data Encryption Algorithm (DES3, TDEA). DES3 works on blocks of 64 bits. DES3 requires keys of length 128 or 192 (bits), but only 112/168 of these bits are actually used. Bigloo's implementation therefore accepts the smaller keys too.
  • des-np: Same as des, but the initial and final permutations are not performed.
  • des3-np: Same as des3, but the initial and final permutations are not performed.
  • aes: Advanced Encryption Standard (AES). AES works on blocks of 128 bits. AES requires keys of length 128, 192 or 256 bits.
  • cast-128: CAST-128 (CAST5). CAST-128 works on blocks of 64 bits. CAST-128 requires a key-length of 40-128 bits.
  • idea: International Data Encryption Algorithm (IDEA). IDEA works on blocks of 64 bits. It requires keys of length 128 (in bits). IDEA is patented in many countries (including the USA and most European countries) but it is free for non-commercial use.
The given password must be a string. An optional parameter :string->key should transform this password so that it has the correct length for the cipher. A small list of possible functions are provided in the String to Key section.

By default string->key-hash with SHA-1 will be used. The key-length will depend on the chosen cipher:
  • des: 56 bits.
  • des3: 112 bits.
  • des-np: Same as des.
  • des3-np: Same as des3.
  • aes: 192 bits.
  • cast-128: 128 bits.
  • idea: 128 bits.
Bigloo supports the following block cipher modes (:mode):
  • ecb: Electronic codebook.
  • cbc: Cipher-block chaining.
  • pcbc: Propagating cipher-block chaining.
  • cfb: Cipher feedback.
  • ofb: Output feedback.
  • ctr: Counter.
By default cfb is chosen.

Electronic codebook mode en/decodes each block independently and is hence the closest to the block cipher. It is however inherently unsafe as blocks with the same content are encrypted to the same output.

With the exception of ecb all other modes can be initialized with an IV (Initialization vector). If :IV is false, then a random one will be generated. During encryption this randomly generated IV will be prefixed to the result. When calling the decryption routine without any IV the procedure will use the first block of the input as IV.

In ctr (counter) mode the IV parameter serves as nonce. Two additional key-parameters :nonce-init and :nonce-update are then used to initialize and update the block-sized nonce string. Before encrypting the first block nonce-init will be invoked with an empty block-sized string and the initial nonce (IV). It must initialize the string with the nonce. For each block nonce-update will be called with the string, the nonce, and the number of already encrypted blocks (hence 0 at the very beginning). By default nonce-init takes the IV-string and blits it into the given string. nonce-update simply increments the string (treating the given string as one big number).

Note that the initial nonce (passed using IV) may be of any type. As long as nonce-init and nonce-update correctly initialize and update the passed string.

The input's length of modes ecb, cbc and pcbc must be a multiple of the block-size. Should this not be the case a padding algorithm must be specified (:pad). Currently are implemented (examples for hexadecimal string ``DD'' and cipher block size 4):

  • none: No padding. Raises an error should the input not be a multiple.
  • bit: Bit padding. Add a '1' bit and then '0' bits. Example: ``DD 80 00 00''.
  • ansi-x.923: Byte padding. Fill with #x00s followed by the number of added bytes (the counter inclusive). Example: ``DD 00 00 03''.
  • iso-10126: Fill with random characters followed by the number of added bytes (the counter inclusive). Example: ``DD 42 31 03''.
  • pkcs7: Fill with the number of added bytes. Example: ``DD 03 03 03''.
  • zero: Fill with zeros. This is only reversible if the input is guaranteed not to finish with a zero character. Example: ``DD 00 00 00''.
Alternatively users can supply their own (un)pad functions (instead of a symbol). The signature of a padding function is (pad::bool str::bstring valid-chars::long). It receives the last block of the input. Should the input be of correct length then the an empty block will be sent to the padding function. valid-chars indicates the number of read characters. It ranges from 0 to blocksize-1. The padding function should fill the block and return #t if this last block should be encoded. By returning #f the last block will be discarded. This makes only sense if valid-chars was equal to 0.

The unpadding procedure has the signature (unpad::long str::bstring). The input string will have the length of the block-size. The unpadding function may modify the string and must return the number of characters that are valid.

decrypt::bstring cipher ciphertext password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
decrypt-string::bstring cipher ciphertext::bstring password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
decrypt-mmap::bstring cipher ciphertext::mmap password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
decrypt-port::bstring cipher ciphertext::input-port password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
decrypt-file::bstring cipher filename::bstring password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
decrypt-sendchars cipher in::input-port out::output-port password [:string->key] [:mode 'cfb] [:IV #f] [:pad 'none] [:nonce-init!] [:nonce-update!]Bigloo Cryptography procedure
Counterpart to the encryption functions. With the same parameters the decrypt function will decrypt the result of an encrypt call. Without :IV (Initial Vector) the decrypt function will use the first block as IV.




For compatibility the following functions remain in Bigloo. They are in the default library and not inside the crypto library.

aes-ctr-encrypt text password [nbits 128]bigloo procedure
aes-ctr-encrypt-mmap mmap password [nbits 128]bigloo procedure
aes-ctr-encrypt-string string password [nbits 128]bigloo procedure
aes-ctr-encrypt-port iport password [nbits 128]bigloo procedure
aes-ctr-encrypt-file filename password [nbits 128]bigloo procedure
These functions are equivalent to a call to aes-encrypt with mode set to ctr and a special :string->key parameter. The optional argument nbits must either be 128, 192, or 256 and determines the size of the key.

aes-ctr-decrypt text password [nbits 128]bigloo procedure
aes-ctr-decrypt-mmap mmap password [nbits 128]bigloo procedure
aes-ctr-decrypt-string string password [nbits 128]bigloo procedure
aes-ctr-decrypt-port iport password [nbits 128]bigloo procedure
aes-ctr-decrypt-file filename password [nbits 128]bigloo procedure
Counterpart to aes-ctr-encrypt.

15.1.1 String to Key

The following string->key algorithms take a password string and transform it to a key string of a given length. In all the functions the len is expressed in bytes.

string->key-zero str lenBigloo Cryptography procedure
If the length of the input string str is greater or equal to len bytes then the first str characters are returned. Otherwise str is suffixed with '0' (#a000) characters.


string->key-hash str len hash-funBigloo Cryptography procedure
The input string str is run through the given hash function hash-fun. The result is then concatenated multiple times (with itself) until a string of the len bytes is obtained.

In the following example we encrypt some-message using a password "my password". The password will be transformed to 256 bits (32 bytes) using the string->key256 function.

(define (string->key256 password)
  (string->key-hash password 32
                    (lambda (str) (string-hex-intern (sha1sum str)))))
(encrypt 'aes some-message "my password" :string->key string->key256)
Note that the following example yields an identical result:

(define (string->key256 password)
  (string->key-hash password 32
                    (lambda (str) (string-hex-intern (sha1sum str)))))
(encrypt 'aes some-message (string->key256 "my password")
         :string->key (lambda (x) x))

string->key-simple str len hash-funBigloo Cryptography procedure
This function implements the simple s2k algorithm of OpenPGP (RFC 2440). Basically str is run through the hash-fun several times until the concatenation of the results is long enough. At each iteration the string is prefixed with count '0'-bytes (where count is the iteration counter).


string->key-salted str len hash-fun saltBigloo Cryptography procedure
This function implements the salted s2k algorithm of OpenPGP (RFC 2440). Similar to string->key-simple but the input string is first prefixed with salt.


string->key-iterated-salted str len hash-fun salt countBigloo Cryptography procedure
This function implements the iterated salted s2k algorithm of OpenPGP (RFC 2440). The variable count must be a long. This algorithm is an extension of string->key-salted where the hash function is applied repeatedly.





15.2 Public Key Cryptography

15.2.1 Rivest, Shamir, and Adleman (RSA)

Bigloo's implementation of RSA is based on RFC 3447, PKCS #1 v2.1. It does not feature multiprime RSA, though.

Bigloo's implementation is not secure against timing attacks. Furthermore some error codes might reveal information to attackers.

15.2.1.1 RSA Keys

There are two kinds of RSA keys inside Bigloo: complete and partial keys. A complete key contains the information of both the public and the private key (together with other information that could be reconstructed out of the private key). A partial key just contains the modulus and the private or public exponent.

RSA-KeyBigloo Cryptography class
Complete-RSA-KeyBigloo Cryptography class
(class Rsa-Key modulus::bignum exponent::bignum)
(final-class Complete-Rsa-Key::Rsa-Key
  ;; for the complete-rsa-key "exponent" takes the role of 'd'
  e::bignum p::bignum q::bignum
  exp1::bignum   ;; d mod (p-1)
  exp2::bignum   ;; d mod (q-1)
  coeff::bignum) ;; (inverse of q) mod p

RSA keys can be read and written using read-pem-key and write-pem-key (PEM).

generate-rsa-key [:key 1024] [:show-trace]Bigloo Cryptography procedure
This function generates a new RSA key (with its public and private components).

Do not use this function for critical applications. No special effort has been undertaken to guarantee the randomness of the generated prime numbers, nor to weed out insecure keys.

Complete keys can be accessed using the following functions:
extract-public-rsa-key complete-keyBigloo Cryptography procedure
Returns the public partial key of the given complete key.

This procedure is implemented as follows:
(define (extract-public-rsa-key::Rsa-Key key::Complete-Rsa-Key)
   (with-access::Complete-Rsa-Key key (modulus e)
      (make-Rsa-Key modulus e)))

extract-private-rsa-key complete-keyBigloo Cryptography procedure
Returns the private partial key of the given complete key.

rsa-key=? key1 key2Bigloo Cryptography procedure
Returns true if the two keys have the same modulus and public exponent. The exponent of a partial key is considered to be public.

15.2.1.2 RSA basic operations

RSA only works on bignums (up to the size of the modulus). The following procedures implement basic encryption, decryption, signing and signature verification.

rsa-encrypt key mBigloo Cryptography procedure
Encrypts the bignum m using the given key. If the key is a complete key then its public exponent is used. For partial keys only one exponent is available (which is assumed to be the public 'e' of the recipient). The result is again a bignum.

rsa-decrypt key cBigloo Cryptography procedure
Decrypts the bignum c using the given key. If the key is a complete key then its private exponent is used. For partial keys only one exponent is available (which is assumed to be the private 'd'). The result is again a bignum.

rsa-sign k mBigloo Cryptography procedure
Signs the bignum m using key k. Uses the private exponent of complete keys. The result is a bignum.

rsa-verify k m sBigloo Cryptography procedure
Verifies the signature s. Returns true if s is the signature of m. The key k should be the public key of the signer.

15.2.1.3 Examples

In this section we will present an example of using RSA.

Let's start by generating an RSA key in openssl:
$ openssl genrsa -out my_rsa_key.pem 1024
Our key will have 1024 bits (for the public modulus), and therefore RSA will only be able to work with bignums up to 1024 bits (128 bytes).

Now some Bigloo code that uses this key.

Start by loading the library.
(module rsa-example (library crypto))
Now read the key:
(define *key* (read-pem-key "my_rsa_key.pem"))
(define *public-key* (extract-public-rsa-key *key*))
The public portion of the key can be distributed:
;; publish the *public-key*:
(write-pem-key-string *public-key*)
Now let's sign the message ``My Important Message''. This message is sufficiently short to be signed directly, but in general it is better to get a hash of the message:
(define msg-hash (sha1sum "my message"))
(define msg-hash-bignum (octet-string->bignum msg-hash))
The result of sha1sum returns a human readable representation of the hash. It would hence be possible to transform it back to an internal representation before applying the octet-string->bignum function:
(define msg-hash-bignum (octet-string->bignum (string-hex-intern msg-hash)))
In our case both variants are small enough to fit into our keys. The latter version is however more often used.

Now that we have a message hash in bignum form we can sign it.
(define signature (rsa-sign *key* msg-hash-bignum))
The signature is again in bignum form. If needed there are several ways to transform it into string-form (for instance bignum->string or bignum->octet-string).

The signature can now be distributed. Anyone wanting to verify the signature simply has to create the same message-hash and call rsa-verify with our public key:

(rsa-verify *public-key* msg-hash-bignum signature) => #t
Encryption and decryption work in a similar way.

Suppose someone (let's say ``Alice'') wants to send us the following secret message ``Cryptography''. The encryption and decryption functions work, similar to the signature functions, on bignums. We could, as before, simply transform this short string into a bignum and directly encrypt the bignum. This approach would however not work for longer strings. In the following we will present the generic version that works with strings of any size.

Public key cryptography is relatively slow and Alice thus starts by encrypting our message a fast block cipher with a ``random'' password:
(define encrypted (encrypt 'aes "Cryptography" "my random password"))
Alice can already send us the encrypted message. We will just not yet be able to decrypt it, as we don't have the random password yet.

Alice now takes her random password string and encrypts it with our public key:
(define encrypted-key (rsa-encrypt *public-key* (octet-string->bignum "my random password")))
Alice simply sends us the encrypted-key. On our side we can now decrypt the key:
(define aes-key (bignum->octet-string (rsa-decrypt *key* encrypted-key)))
We can now decrypt the previously received message:
(decrypt 'aes aes-key encrypted) => "Cryptography"

15.2.1.4 RSA RFC 3447

The following functions have been defined in RFC 3447. We discourage its usage unless you need to implement parts (or all) of it.

RSAEP k mBigloo Cryptography procedure
RSADP k cBigloo Cryptography procedure
RSASP1 k mBigloo Cryptography procedure
RSAVP1 k sBigloo Cryptography procedure
These are the RFC 3447 names for encryption, decryption, signature and signature verification. Note that the verification does not receive the original message as parameter.

In fact rsa-verify is implemented as follows:
(define (rsa-verify k m s)
  (=bx m (RSAVP1 k s)))

RSAES-PKCS1-v1.5-encryptt key m-strBigloo Cryptography procedure
RSAES-PKCS1-v1.5-decrypt key c-strBigloo Cryptography procedure
RSASSA-PKCS1-v1.5-sign key msg-str [:hash-algo 'sha-1]Bigloo Cryptography procedure
RSASSA-PKCS1-v1.5-verify key msg-str S-strBigloo Cryptography procedure
RSASSA-PKCS1-v1.5-sign-bignum key msg-str [:hash-algo 'sha-1]Bigloo Cryptography procedure
RSASSA-PKCS1-v1.5-verify-bignum key msg-str SBigloo Cryptography procedure
RSAES-PKCS1-v1.5 functions work on strings. However their length is limited by the size of the modulus (to be exact: by key-len - 11). The -bignum functions skip the last step of converting the internal bignum to strings.

The optional :hash-algo must be either sha-1 or md5 (RFC 3447 allows other hash algorithms, but they are not yet implemented).

RSAES-OAEP-encrypt key m-str [:label ""]Bigloo Cryptography procedure
RSAES-OAEP-decrypt key cypher-str [:label ""]Bigloo Cryptography procedure
RSASSA-PSS-sign key msg-strBigloo Cryptography procedure
RSASSA-PSS-verify key msg-str sig-strBigloo Cryptography procedure
These functions pad, mask, etc the input string before they perform their operation on them. See RFC 3447 for more information.

15.2.2 Digital Signature Algorithm (DSA)

Bigloo has rudimentary (but usually sufficient) support for DSA. While it is not possible to generate new DSA keys inside Bigloo one can sign or verify with Bigloo.

DSA keys can be read and written using read-pem (PEM).

For consistency with RSA we have named DSA keys in a similar way as the RSA keys. The public part of a DSA key can be found in the class DSA-Key while the private part is added in the Complete-DSA-Key subclass.

DSA-KeyBigloo Cryptography class
Complete-DSA-KeyBigloo Cryptography class
(class Dsa-Key
   p::bignum q::bignum g::bignum y::bignum)
(final-class Complete-Dsa-Key::Dsa-Key
   x::bignum)) ;; the private key

extract-public-dsa-key complete-keyBigloo Cryptography procedure
Returns a DSA-Key without the private x.

dsa-sign m keyBigloo Cryptography procedure
Signs the bignum m using the private dsa key key. The result are two values: r and s.

A typical call to dsa-sign is hence of the following form
(receive (r s)
  (dsa-sign secret-key hashed-msg-bignum)
  (process-signature r s))

dsa-verify m key r sBigloo Cryptography procedure
Verifies a signature (consisting of r and s).

DSA works very similar to RSA. Have a look at RSA's example section.

15.2.3 ElGamal

Bigloo supports ElGamal encryption (but not signing). Bigloo's implementation is minimal.

For consistency with RSA ElGamal keys are similarly named as their RSA counterparts.

ElGamal-KeyBigloo Cryptography class
Complete-ElGamal-KeyBigloo Cryptography class
(class ElGamal-Key
  p::bignum
  g::bignum
  y::bignum)
(final-class Complete-ElGamal-Key::ElGamal-Key
  x::bignum)) ;; the private key

extract-public-elgamal-key complete-keyBigloo Cryptography procedure
Returns a copy of the public part (as ElGamal Key).

elgamal-encrypt key mBigloo Cryptography procedure
Encrypts the bignum m using the given public key. The result are two values c1 and c2.

Note that ElGamal encryption needs random bytes for every encryption. This means that this function may return different results with the same parameters. It furthermore implies that the result is insecure if the operating system provides bad random numbers, or if Bigloo's random-number generation is buggy. For critical applications be sure to verify both requirements.

elgamal-decrypt complete-key c1 c2Bigloo Cryptography procedure
Decrypts an ElGamal encrypted message (consisting of the two bignums c1 and c2) with the given private key.

ElGamal works very similar to RSA. Have a look at RSA's example section.

15.2.4 PEM

Bigloo is able to read and write RSA and DSA keys in PEM format. This is the default format used by OpenSSL.

The following example creates a new DSA key pair in OpenSSL and stores it in PEM format.
$ openssl dsaparam 1024 -out /tmp/dsaparam
$ openssl gendsa /tmp/dsaparam


read-pem-key inBigloo Cryptography procedure
read-pem-key-port input-portBigloo Cryptography procedure
read-pem-key-file filenameBigloo Cryptography procedure
read-pem-key-string strBigloo Cryptography procedure
These functions will read a PEM encoded key. The encoded file may contain a private or public RSA key, as well as a private or public DSA key.

The procedure read-pem-key accepts input-ports and strings. In the case of a string it will invoke read-pem-key-file (and not read-pem-key-string).

write-pem-key key out [public-key-only?]Bigloo Cryptography procedure
write-pem-key-port key out [public-key-only?]Bigloo Cryptography procedure
write-pem-key-file key out [public-key-only?]Bigloo Cryptography procedure
write-pem-key-string key [public-key-only?]Bigloo Cryptography procedure
These functions write the given key. The key may be a private/public RSA/DSA key.

The procedure write-pem-key accepts output-ports and strings as out parameter. If out is a string it will delegate to write-pem-key-file.



This Html page has been produced by Skribe.
Last update Thu Jul 1 16:19:21 2010.