(crypto) - Cryptographic library

Deprecated library

This library is deprecated, please consider to use Cryptographic libraries instead.

This documentation does not describe cryptography itself. For example, it does not describe what initial vector is and how long it must be. So users must know about cryptography's this library supports.

This library uses libtomcrypt's functionalities. The library is public domain. Thank you for the great library.

Note: the libtomcrypt is a huge cryptographic library and I am not so good with cryptographics, so the (crypto) library is not totally tested. Just the functionalities which I usually use are tested. If you find a bug or wrong documentation, pleas report it.

Library (crypto)

This library is the top most library, it exports all the other libraries procedures. Users must import only this and not to use the others.

(crypto) library supports both symmetric cryptography and public/private key mechanism. For public/private key, it only supports RSA for now.

Function crypto-object? obj

Returns #t if obj is crypto-object.

crypto-object can be either cipher or key.

Cipher operations

Creates a cipher object.

type must be known cryptographic algorithm. Currently, (crypto)library exports the algorithm below.

The symmetric key algorithms.

Constant Blowfish
Constant X-Tea
Constant RC2
Constant RC5-32/12/b
Constant RC6-32/20/b
Constant SAFER+
Constant SAFER-K64
Constant SAFER-SK64
Constant SAFER-K128
Constant SAFER-SK128
Constant AES
Constant AES-128
Constant AES-192
Constant AES-256
Constant Twofish
Constant DES
Constant DES3
Constant DESede
Constant CAST5
Constant CAST-128
Constant Noekeon
Constant Skipjack
Constant Khazad
Constant SEED
Constant KASUMI
Constant Camellia

AES-128, AES-192 and AES-256 are fixed key size AES algorithms. AES allows key size of 16, 24 or 32 bytes, however, fixed sized version only accepts 16 for AES-128, 24 for AES-192 and 32 for AES-256.

The public key algorithm

Constant DSA
Constant ECDSA
Constant RSA

key must be a key object which will be created by key generate procedures described below.

mode specifies the symmetric cipher's encryption and description mode. If the cipher type is public key cipher, it will be ignored. Some modes require initial vector iv. The possible mods are below.

Constant MODE_ECB
Constant MODE_CBC
Constant MODE_CFB
Constant MODE_OFB
Constant MODE_CTR
Constant MODE_GCM

The keyword argument mode-parameter is specified, it must be a mode parameter object, then the object will be parsed properly by the cipher.

Returns given cipher type's recommended keysize.

cipher must cipher object created by cipher procedure.

test must be fixnum.

If test is too small for the cipher, it will raise an error.

Note: this procedure is for helper. It is designed to use check keysize you want to use.

Function cipher? obj

Returns #t if the obj is cipher object.

cipher must be a cipher object.

pt must be a bytevector.

encrypt encrypts given plain text pt according to the given cipher.

Similar with cipher-encrypt. The difference is that this procedure returns 2 values, encrypted pt and calculated tag if the given cipher supports authentication.

If the keyword argument tag-size is specified and must be an integer, then the returning tag has the specified size. If the cipher supports less size than the specified size, then the remaining tag contains unspecified value. To retrieve the maximum length of tag, use cipher-max-tag-size.

cipher must be a cipher object.

ct must be a bytevector.

decrypt decrypts given encrypted text ct according to the given cipher.

Similar with cipher-decrypt. The difference is that this procedure returns 2 values, decrypted ct and calculated tag if the given cipher supports authentication.

If the keyword argument tag-size is specified and must be an integer, then the returning tag has the specified size. If the cipher supports less size than the specified size, then the remaining tag contains unspecified value. To retrieve the maximum length of tag, use cipher-max-tag-size.

Similar with cipher-decrypt. The difference is that this procedure validates the calculated tag. If the given tag and calculated tag are not the same, then &decrypt is raised.

NOTE: if the tag is *not* calculated by the cipher, then this procedure always raises an error.

Returns the maximum length of tag size.

If the given cipher does not support authentication tag, then returning value is 0.

Updates the additional authentication data.

dst must be a bytevector.

Retrieves the authentication tag from given cipher.

NOTE: this procedure must be called after either cipher-encrypt or cipher-decrypt. Otherwise the filled value is unspecified.

Retrieves the authentication tag from given cipher.

If the keyword argument size is specified, then the returning bytevector has the size length, otherwise maximum tag length.

NOTE: this procedure must be called after either cipher-encrypt or cipher-decrypt. Otherwise the filled value is unspecified.

public-cipher must be a cipher object created with public/private key algorithm.

data must be a bytevector.

Signs given data. This procedure is just a wrapper for the real implementations. Currently Sagittarius supports only RSA sign.

opt can specify the signer behaviour. Default supported RSA cipher can accept keyword argument encode.

encode specifies the encoder. The default encoder is pkcs1-emsa-pss-encode. And the rest keyword arguments will be passed to the encoder. Supported encoders are described below.

The following shows how to implement SHA256WithRSA signature

;; Importing a RSA private key.
(define private-key (import-private-key RSA #vu8(...)))

(define signer (make-cipher RSA private-key))
(cipher-signature signer #vu8() :encode pkcs1-emsa-v1.5-encode :hash SHA-256)

public-cipher must be a cipher object created with public/private key algorithm.

M and S must be bytevectors.

M is master message which will be compared with encoded message.

S is signed message.

The verity procedure verifies two messages.

opt can specify the verifier behaviour. Default supported RSA cipher can accept keyword argument verify.

verify specifies the verifier. The defaule verifier is pkcs1-emsa-pss-verify. And the rest keyword arguments will be passed to verifier. Supported verifiers are described below.

Mode parameters

Mode parameters are pareters which can be used by specified mode. For example, iv-parameter is a parameter contains an IV.

Returns #t if the given obj is a mode parameter, otherwise #f.

Creates a composite mode parameter.

A composite parameter can hold multiple parameters.

Record Type <iv-paramater>

Record type for initial vector (IV) parameter.

iv must be a bytevector or #f.

Creates an IV mode parameter.

IV is required by some modes. e.g. MODE_CBC.

Record Type <ctr-paramater>

Record type for counter mode parameter.

This parameter is a subclass of <iv-parameter>.

Creates a counter mode parameter. This is used by MODE_CTR.

iv is passed to parent constructor.

The followings are description of keyword parameters.

rounds specify how many times the cipher rounds the key.

ctr-mode specifies counter mode. The possible mode is blow.

Record type for AES-CTR mode parameter defined in RFC 3686.

This parameter is a subclass of <ctr-parameter>.

Creates RFC3686 mode parameter.

Record type for padding parameter.

Creates a padding mode parameter.

padder must be an procedure such as pkcs5-padder.

Key operations

type must be one of the supported symmetric algorithm.

key must be a bytevector and its length must satisfy the keysize which the given algorithm requires.

Returns a sercret key object.

type is for despatch. For default implementation, it must be RSA.

Generates a key pair object.

Default implementation supports RSA key geneartion and options can be keyword arguments described below.

size keyword argument is decides key length. Default value is 1024.

prng keyword argument is given, it will be passed to random-prime. For more detail, see (math random) library. Default value is (secure-random RC4).

e keyword argument is an exponent. Usually it does not have to be specified with other number. Default value is 65537.

type is for despatch. For default implementation, it must be RSA.

Returns private key object.

Default RSA implementation options can be these arguments.

modulus

The private key's modulus

private-exponent

The private key's exponent

public-exponent

keyword argument. Used for CRT private key object.

p

keyword argument. Used for CRT private key object.

q

keyword argument. Used for CRT private key object.

type is for despatch. For default implementation, it must be RSA.

Returns public key object.

Default RSA implementation opt can be these arguments.

modulus

The public key's modulus

exponent

The public key's exponent

Returns #t if given obj is keypair object, otherwise #f

Returns private key from keypair

Returns public key from keypair

Function key? obj

Returns #t if given obj is key object, otherwise #f

CLOS class of private key object.

CLOS class of public key object.

Returns #t if given obj is private key object, otherwise #f

Returns #t if given obj is public key object, otherwise #f

key must be a bytevector and plain key.

Splits the given key to count components and returns _count_values as key components.

The return values might be different each time.

Renaming export of bytevector-xor and bytevector-xor!respectively.

For more detail, see (util bytevector).

PKCS operations

The procedures described in this section is implemented according to PKCS#1. I don't have any intend to describe functionality. If you need to know what exactly these procedures do, please see the PKCS#1 document.

bv must be a bytevector.

block-size must be a non negative exact integer.

padding? must be a boolean.

Pads or Unpads paddings from bv according to PKCS#5.

If padding? is #t, the procedure will pad. otherwise it will unpad.

prng must be prng object. See (math random).

key must be either private or public key object.

block-type must be one of these.

Constant PKCS-1-EME
Constant PKCS-1-EMSA

Returns a padding procedure. The procedure signature is the same as pkcs5-padder.

_ :key (hash (hash-algorithm SHA-1) ) (mgf mgf-1) (salt-length #f) _ _ (prng (secure-random RC4) )

m must be a bytevector.

em-bits must be non negative exact integer.

Encodes given message m according to the PKCS#1 section 9.1.1.

The keyword arguments specified some behaviour.

hash specifies the hash algorithm. For more detail, see (math hash) library.

mgf specifies mask generation procedure.

Note: PKCS#1 only specifies MGF-1.

salt-length specifies salt's length. If it's #f encoder does not use salt.

prng is a pseudo random see (math random).

_ :key (hash (hash-algorithm SHA-1) ) (mgf mgf-1) _ _ (prng (secure-random RC4) )

m must be a bytevector.

em-bits must be non negative exact integer.

Verify given message m according to the PKCS#1 section 9.1.1.

Other keyword arguments are the same as pkcs1-emsa-pss-encode.

mgf-seed must be a bytevector.

mask-length must be a non negative exact integer.

hasher must be a hash algorithm. See (math random).

Creates a mask bytevector, according to PKCS#1 MGF-1.

m must be a bytevector.

em-bits must be non negative exact integer.

Encodes given message m according to the PKCS#1 section 9.2.

Other keyword arguments are the same as pkcs1-emsa-pss-encode.

m must be a bytevector.

em-bits must be non negative exact integer.

Verify given message m according to the PKCS#1 section 9.2. Other keyword arguments are the same as pkcs1-emsa-pss-encode.

Key wrapping

Returns AES key wrapping procedure which accepts one argument of bytevector to be wrapped.

The returning procedure wraps the given bytevector with AES Key Wrap algorithm specified by NIST or RFC 3394.

The keyword argument iv specifies initial value (IV) for data integrity. The default value is #vu8(#xa6 #xa6 #xa6 #xa6 #xa6 #xa6 #xa6 #xa6)specified by the specification.

Returns AES key unwrapping procedure which accepts one argument of bytevector to be unwrapped.

The returning procedure wraps the given bytevector with AES Key Wrap algorithm specified by NIST or RFC 3394.

The keyword argument iv specifies initial value (IV) for data integrity. The default value is #vu8(#xa6 #xa6 #xa6 #xa6 #xa6 #xa6 #xa6 #xa6)specified by the specification.

Cryptographic conditions

Condition Type &crypto-error

Subcondition of &error.

Base condition type of all cryptographic conditions.

Condition Type &encrypt-error

This condition will be raised when encrypt operation is failed.

Condition Type &decrypt-error

This condition will be raised when decrypt operation is failed.

Condition Type &encode-error

This condition will be raised when encoding operation is failed.

Condition Type &decode-error

This condition will be raised when decoding operation is failed.

who, message and irritants are the same as assertion-violation.

mechanism should be a name of cryptographic algorithm.

Raises &encrypt-error.

who, message and irritants are the same as assertion-violation.

mechanism should be a name of cryptographic algorithm.

Raises &decrypt-error.

who, message and irritants are the same as assertion-violation.

Raises &encode-error.

who, message and irritants are the same as assertion-violation.

Raises &decode-error.

Condition Type &integrity-error

Subcondition of &crypto-errorThis condition will be raised when key unwrap failed due to the integrity check error.

Creating own cipher

If Sagittarius does not support sufficient cipher algorithm for you, then you can write own cipher such as DSA. For this purpose, you might need to know how this library works. It will be described the bottom of this section. If you just want to create a new cipher, you just need to follow the example.

(import (rnrs) (crypto) (clos user) (sagittarius))

(define (sample-encrypt pt key) pt)
(define (sample-decrypt ct key) ct)

(define-class <sample-cipher-spi> (<cipher-spi>) ())
(define-method initialize ((o <sample-cipher-spi>) initargs)
  (slot-set! o 'name 'sample)
  (slot-set! o 'key #f)
  (slot-set! o 'encrypt sample-encrypt)
  (slot-set! o 'decrypt sample-decrypt)
  (slot-set! o 'padder #f)
  (slot-set! o 'signer (lambda _ #vu8()))
  (slot-set! o 'verifier (lambda _ #t))
  (slot-set! o 'keysize (lambda _ 0)))

(define sample :sample)
(register-spi sample <sample-cipher-spi>)
;; test sample-cipher
(define sample-cipher (cipher sample #f))
(define message (string->utf8 "sample message"))
(let ((encrypted-message (encrypt sample-cipher message)))
  (decrypt sample-cipher encrypted-message))
;; -> #vu8(115 97 109 112 108 101 32 109 101 115 115 97 103 101)

The sample code actually does nothing. If you want to see real working code, ext/crypto/crypto/key/rsa.scm might be a good example for you.

The basic idea of creating a new cipher is that you need to define own subclass of <cipher-spi> and register it.

The base class for all SPI (Service Provider Interface).

Subclass must set these slots.

encrypt

The value must be a procedure which takes 2 arguments.

decrypt

The value must be a procedure which takes 2 arguments.

NOTE: Default symmetric key ciphers use pkcs5-padder which takes 3 arguments, bytevector, block-size and padding flag. This is because the procedure can be used by multi ciphers. And custom cipher must know its own block size.

These slots are optional.

name

Describe the cipher.

key

The value will be passed to encrypt, decrypt, sign and verify to be used.

signer

A procedure for signing. The given procedure must accept at least 2 arguments.

verifier

A procedure for verifying. The given procedure must accept at least 3 arguments.

keysize

A procedure to get recommended keysize of this cipher. The given procedure must accept 1 argument.

padder

The value must be #f or a procedure which takes 2 arguments.

update-aad

The value must be #f or a procedure which takes 1 arguments. This is called when cipher-update-aad! is called.

tag

The value must be #f or a procedure which takes 1 arguments. This is called when cipher-tag! is called.

tagsize

The value must be an integer. This represents the maximum length of authentication tag.

NOTE: Even required slots, Sagittarius does not check if it's set or not.

During its initialisation, the initargs (the second argument of the initialize method) takes at least 3 arguments, key, :mode-parameter keyword and parameter passed to make-cipher. The rest of other arguments are also passed if exist.

Returns #t if the given object o is a cipher SPI. Otherwise #f.

Register custom cipher SPI.

mark can be any thing which returns #t then compared by equal?spi must be subclass of <cipher-spi>NOTE: We recommend to make mark the same as example code does and export the registered mark. And the mark must be unique enough not to overwrite existing SPI names.

e.g. :rsa, :dsa and :ecdsa are already used for RSA, DSA and ECDSA

The concept of this SPI is influenced by Java's JCE. The toplevel of cipher is just a wrapper for real implementaion (SPI). When a cipher is created, the cipher procedure actually creates an instance of SPI class and set it to the cipher object. So users need not to know about the implementation and if the implementation supply default parameter then users even can use it by default.

This is the class hierarchy of these crypto objects.

+ <top>
  + <crypto>
      + <cipher>
      + <cipher-spi>
          + <builtin-cipher-spi> <- default implementations of symmetric keys.
          + <rsa-cipher-spi>     <- default RSA implementation
      + <key>
          + <symmetric-key>
              + <builtin-symmetric-key> <- default symmetric key. ex. DES
          + <asymmetric-key>
              + <private-key>
                  + <rsa-private-key>
                      + <rsa-private-crt-key>
              + <public-key>
                  + <rsa-public-key>

The <cipher> and builtin- prefixed classes can not have any subclass.

Backward compatibility

The following procedures are kept for backward compatibility.