CyaSSL Manual

Chapter 10: CTaoCrypt Usage Reference



CTaoCrypt is the cryptography library primarily used by CyaSSL. It is optimized for speed, small footprint, and portability. CyaSSL interchange with other cryptography libraries as required.


Types used in the examples:


typedef unsigned char byte;

typedef unsigned int  word32;



10.1 Hash Functions



10.1.1 MD4


NOTE:  MD4 is outdated and considered broken. Please consider using a different hashing function if possible.


To use MD4 include the MD4 header "cyassl/ctaocrypt/md4.h". The structure to use is Md4, which is a typedef. Before using, the hash initialization must be done with the InitMd4() call. Use Md4Update() to update the hash and Md4Final() to retrieve the final hash


byte md4sum[MD4_DIGEST_SIZE];

byte buffer[1024];      

// fill buffer with data to hash


Md4 md4;

InitMd4(&md4);


Md4Update(&md4, buffer, sizeof(buffer));  // can be called again and again

Md4Final(&md4, md4sum);         


md4sum now contains the digest of the hashed data in buffer.



10.1.2 MD5


To use MD5 include the MD5 header "cyassl/ctaocrypt/md5.h". The structure to use is Md5, which is a typedef. Before using, the hash initialization must be done with the InitMd5() call. Use Md5Update() to update the hash and Md5Final() to retrieve the final hash


byte md5sum[MD5_DIGEST_SIZE];

byte buffer[1024];      

// fill buffer with data to hash


Md5 md5;

InitMd5(&md5);


Md5Update(&md5, buffer, sizeof(buffer));  // can be called again and again

Md5Final(&md5, md5sum);         


md5sum now contains the digest of the hashed data in buffer.



10.1.3 SHA / SHA-256 / SHA-384 / SHA-512


To use SHA include the SHA header "cyassl/ctaocrypt/sha.h". The structure to use is Sha, which is a typedef. Before using, the hash initialization must be done with the InitSha() call. Use ShaUpdate() to update the hash and ShaFinal() to retrieve the final hash:


byte shaSum[SHA_DIGEST_SIZE];

byte buffer[1024];      

// fill buffer with data to hash


Sha sha;

InitSha(&sha);


ShaUpdate(&sha, buffer, sizeof(buffer));  // can be called again and again

ShaFinal(&sha, shaSum);


shaSum now contains the digest of the hashed data in buffer.


To use either SHA-256 or SHA-512, follow the same steps as shown above, but use either the “cyassl/ctaocrypt/sha256.h” or “cyassl/ctaocrypt/sha512.h”.  The SHA-256 and SHA-512 functions are named similarly to the SHA functions.  


For SHA-256, the functions InitSha256(), Sha256Update(), and Sha256Final() will be used with the structure Sha256.


For SHA-512, the functions InitSha512(), Sha512Update(), and Sha512Final() will be used with the structure Sha512.



10.1.4 RIPEMD-160


To use RIPEMD-160, include the header "cyassl/ctaocrypt/ripemd.h". The structure to use is RipeMd, which is a typedef. Before using, the hash initialization must be done with the InitRipeMd() call. Use RipeMdUpdate() to update the hash and RipeMdFinal() to retrieve the final hash


byte ripeMdSum[RIPEMD_DIGEST_SIZE];

byte buffer[1024];      

// fill buffer with data to hash


RipeMd ripemd;

InitRipeMd(&ripemd);


RipeMdUpdate(&ripemd, buffer, sizeof(buffer));  // can be called again and again

RipeMdFinal(&ripemd, ripeMdSum);         


ripeMdSum now contains the digest of the hashed data in buffer.



10.2 Keyed Hash Functions



10.2.1 HMAC


CTaoCrypt currently provides HMAC for message digest needs. The structure Hmac is found in the header "cyassl/ctaocrypt/hmac.h". HMAC initialization is done with HmacSetKey().  3 different types are supported with HMAC; MD5, SHA, and SHA-256. Here's an example with SHA-256.


Hmac    hmac;

bytekey[24];    // fill key with keying material

bytebuferr[2048];   // fill buffer with data to digest

bytehmacDigest[SHA256_DIGEST_SIZE];


HmacSetKey(&hmac, SHA256, key, sizeof(key));

HmacUpdate(&hmac, buffer, sizeof(buffer));

HmacFinal(&hmac, hmacDigest);


hmacDigest now contains the digest of the hashed data in buffer.



10.3 Block Ciphers



10.3.1 AES


CTaoCrypt provides support for AES with key sizes of 16 bytes (128 bits), 24 bytes (192 bits), or 32 bytes (256 bits). CBC mode is supported for encryption/decryption and is provided through AesCbcEncrypt() and AesCbcDecrypt(). Please include the header "cyassl/ctaocrypt/aes.h"  to use AES. AES has a block size of 16 bytes and the IV should also be 16 bytes. Function usage is usually as follows:


Aes enc;

Aes dec;


const byte key[] = {  // some 24 byte key };

const byte iv[] = { // some 16 byte iv };


byte plain[32];   // an increment of 16, fill with data

byte cipher[32];


// encrypt

AesSetKey(&enc, key, sizeof(key), iv, AES_ENCRYPTION);

AesCbcEncrypt(&enc, cipher, plain, sizeof(plain));


cipher now contains the cipher text from the plain text.


// decrypt

AesSetKey(&dec, key, sizeof(key), iv, AES_DECRYPTION);

AesCbcDecrypt(&dec, plain, cipher, sizeof(cipher));


plain now contains the original plaintext from the cipher text.



10.3.2 DES and 3DES


CTaoCrypt provides support for DES and 3DES (Des3 since 3 is an invalid leading C identifier). To use these include the header "cyassl/ctaocrypt/des.h". The structures you can use are Des and Des3. Initialization is done through Des_SetKey() or Des3_SetKey(). CBC encryption/decryption is provided through Des_CbcEnrypt() / Des_CbcDecrypt() and Des3_CbcEncrypt() / Des3_CbcDecrypt(). Des has a key size of 8 bytes (24 for 3DES) and the block size is 8 bytes, so only pass increments of 8 bytes to encrypt/decrypt functions. If your data isn't in a block size increment you'll need to add padding to make sure it is. Each SetKey() also takes an IV (an initialization vector that is the same size as the key size). Usage is usually like the following:


Des3 enc;

Des3 dec;


const byte key[] = {  // some 24 byte key };

const byte iv[] = { // some 24 byte iv };


byte plain[24];   // an increment of 8, fill with data

byte cipher[24];


// encrypt

Des3_SetKey(&enc, key, iv, DES_ENCRYPTION);

Des3_CbcEncrypt(&enc, cipher, plain, sizeof(plain));


cipher now contains the cipher text from the plain text.


// decrypt

Des3_SetKey(&dec, key, iv, DES_DECRYPTION);

Des3_CbcDecrypt(&dec, plain, cipher, sizeof(cipher));


plain now contains the original plaintext from the cipher text.

 


10.4 Stream Ciphers



10.4.1 ARC4


The most common stream cipher used on the Internet is ARC4. CTaoCrypt supports it through the header "cyassl/ctaocrypt/arc4.h".  Usage is simpler than block ciphers because there is no block size and the key length can be any length. The following is a typical usage of ARC4.


Arc4 enc;

Arc4 dec;


const byte key[] = {  // some key any length};


byte plain[27];   // no size restriction, fill with data

byte cipher[27];


// encrypt

Arc4SetKey(&enc, key, sizeof(key));

Arc4Process(&enc, cipher, plain, sizeof(plain));


cipher now contains the cipher text from the plain text.


// decrypt

Arc4SetKey(&dec, key, sizeof(key));

Arc4Process(&dec, plain, cipher, sizeof(cipher));


plain now contains the original plaintext from the cipher text.



10.4.2 RABBIT


A newer stream cipher gaining popularity is RABBIT. This stream cipher can be used through CTaoCrypt by including the header "cyassl/ctaocrypt/rabbit.h". RABBIT is very fast compared to ARC4, but has key constraints of 16 bytes (128 bits) and an optional IV of 8 bytes (64 bits). Otherwise usage is exactly like ARC4:


Rabbit enc;

Rabbit dec;


const byte key[] = {  // some key 16 bytes};

const byte iv[] = { // some iv 8 bytes };


byte plain[27];   // no size restriction, fill with data

byte cipher[27];


// encrypt

RabbitSetKey(&enc, key, iv);  // iv can be a NULL pointer

RabbitProcess(&enc, cipher, plain, sizeof(plain));


cipher now contains the cipher text from the plain text.


// decrypt

RabbitSetKey(&dec, key, iv);

RabbitProcess(&dec, plain, cipher, sizeof(cipher));


plain now contains the original plaintext from the cipher text.



10.4.3 HC-128


Another stream cipher in current use is HC-128, which is even faster than RABBIT (about 5 times faster than ARC4).  To use it with CTaoCrypt, please include the header "cyassl/ctaocrypt/hc128.h". HC-128 also uses 16 bytes keys (128 bits) but uses 16 bytes vs (128 bits) unlike RABBIT.


HC128 enc;

HC128 dec;


const byte key[] = {  // some key 16 bytes};

const byte iv[] = { // some iv 16 bytes };


byte plain[37];   // no size restriction, fill with data

byte cipher[37];


// encrypt

Hc128_SetKey(&enc, key, iv);  // iv can be a NULL pointer

Hc128_Process(&enc, cipher, plain, sizeof(plain));


cipher now contains the cipher text from the plain text.


// decrypt

Hc128_SetKey(&dec, key, iv);

Hc128_Process(&dec, plain, cipher, sizeof(cipher));


plain now contains the original plaintext from the cipher text.



10.5 Public Key Cryptography



10.5.1 RSA


CTaoCrypt provides support for RSA through the header "cyassl/ctaocrypt/rsa.h". There are two types of RSA keys, public and private. A public key allows anyone to encrypt something that only the holder of the private key can decrypt. It also allows the private key holder to sign something and anyone with a public key can verify that only the private key holder actually signed it. Usage is usually like the following:


RsaKey rsaPublicKey;


byte publicKeyBuffer[]  = { // holds the raw data from the key, maybe from a file

                               like RsaPublicKey.der };

word32 idx = 0;             //  where to start reading into the buffer


RsaPublicKeyDecode(publicKeyBuffer, &idx, &rsaPublicKey, sizeof(publicKeyBuffer));


byte in[] = { // plain text to encrypt };

byte out[128];

RNG rng;


InitRng(&rng);


word32 outLen = RsaPublicEncrypt(in, sizeof(in), out, sizeof(out), &rsaPublicKey, &rng);


Now ‘out’ holds the cipher text from the plain text ‘in’. RsaPublicEncrypt() will return the length in bytes written to out or a negative number in case of an error. RsaPublicEncrypt() needs a RNG (Random Number Generator) for the padding used by the encryptor and it must be initialized before it can be used. To make sure that the output buffer is large enough to pass you can first call RsaEncryptSize() which will return the number of bytes that a successful call to RsaPublicEnrypt() will write.


In the event of an error, a negative return from RsaPublicEnrypt(), or RsaPublicKeyDecode() for that matter, you can call CTaoCryptErrorString() to get a string describing the error that occurred.


void CTaoCryptErrorString(int error, char* buffer);


Make sure that buffer is at least MAX_ERROR_SZ bytes (80).


Now to decrypt out:


RsaKey rsaPrivateKey;


byte privateKeyBuffer[] = { // hold the raw data from the key, maybe from a file

                               like RsaPrivateKey.der };

word32 idx = 0;             //  where to start reading into the buffer


RsaPrivateKeyDecode(privateKeyBuffer, &idx, &rsaPrivateKey, sizeof(privateKeyBuffer));


byte plain[128];


word32 plainSz = RsaPrivateDecrypt(out, outLen, plain, sizeof(plain), &rsaPrivateKey);


Now plain will hold plainSz bytes or an error code. For complete examples of each type in CTaoCrypt please see the file ctaocrypt/test/test.c.  Note that the RsaPrivateKeyDecode function only accepts keys in raw DER format.



10.5.2 DH (Diffie-Hellman)


CTaoCrypt provides support for Diffie-Hellman through the header "cyassl/ctaocrypt/dh.h".  The Diffie-Hellman key exchange algorithm allows two parties to establish a shared secret key.  Usage is usually similar to the following example, where sideA and sideB designate the two parties.


In the following example, dhPublicKey contains the Diffie-Hellman public parameters signed by a Certificate Authority (or self-signed).  privA holds the generated private key for sideA, pubA holds the generated public key for sideA, and agreeA holds the mutual key that both sides have agreed on.


DhKeydhPublicKey;

word32idx = 0;  // where to start reading into the publicKeyBuffer

word32pubASz, pubBSz, agreeASz;

bytetmp[1024];

RNGrng;


byteprivA[128];

bytepubA[128];

byteagreeA[128];


InitDhKey(&dhPublicKey);


byte publicKeyBuffer[] = { // holds the raw data from the public key parameters, maybe from a file like dh1024.der }


DhKeyDecode(tmp, &idx, &dhPublicKey, publicKeyBuffer);


InitRng(&rng);  // Initialize random number generator


DhGenerateKeyPair() will generate a public and private DH key based on the initial public parameters in dhPublicKey.


DhGenerateKeyPair(&dhPublicKey, &rng, privA, &privASz, pubA, &pubASz);


After sideB sends their public key (pubB) to sideA, sideA can then generate the mutually-agreed key(agreeA) using the DhAgree() function.


DhAgree(&dhPublicKey, agreeA, &agreeASz, privA, privASz, pubB, pubBSz);


Now, agreeA holds sideA’s mutually-generated key (of size agreeASz bytes).  The same process will have been done on sideB.


For a complete example of Diffie-Hellman in CTaoCrypt, see the file ctaocrypt/test/test.c.



10.5.3 EDH (Ephemeral Diffie-Hellman)


A CyaSSL server can do Ephemeral Diffie-Hellman.  No build changes are needed to add this feature, though an application will have to register the ephemeral group parameters on the server side to enable the EDH cipher suites.  A new API can be used to do this:


int CyaSSL_SetTmpDH(CYASSL* ssl, unsigned char* p,int pSz,unsigned char* g,int gSz);


The example server and echoserver use this function from SetDH().



10.5.4 DSA (Digital Signature Algorithm)


CTaoCrypt provides support for DSA and DSS through the header "cyassl/ctaocrypt/dsa.h".  DSA allows for the creation of a digital signature based on a given data hash.  DSA uses the SHA hash algorithm to generate a hash of a block of data, then signs that hash using the signer’s private key.  Standard usage is similar to the following.  


We first declare our DSA key structure (key), initialize our initial message (message) to be signed, and initialize our DSA key buffer (dsaKeyBuffer).


DsaKey key;

byte message[] = { // message data to sign }

byte dsaKeyBuffer[] = { // holds the raw data from the DSA key, maybe from a file

                           like dsa512.der }


We then declare our SHA structure (sha), random number generator (rng), array to store our SHA hash (hash), array to store our signature (signature), idx (to mark where to start reading in our dsaKeyBuffer), and an int (answer) to hold our return value after verification.


Shasha;

RNGrng;

bytehash[SHA_DIGEST_SIZE];

bytesignature[40];

word32idx = 0;

intanswer;


Set up and create the SHA hash.  For more information on CTaoCrypt’s SHA algorithm, see section 10.1.3. The SHA hash of “message” is stored in the variable “hash”.


InitSha(&sha);

ShaUpdate(&sha, tmp, message);

ShaFinal(&sha, hash);


Initialize the DSA key structure, populate the structure key value, and initialize the random number generator (rng).


InitDsaKey(&key);

DsaPrivateKeyDecode(tmp, &idx, &key, dsaKeyBuffer);


InitRng(&rng);


The DsaSign() function creates a signature (signature) using the DSA private key, hash value, and random number generator.


DsaSign(hash, signature, &key, &rng);


To verify the signature, use DsaVerify(). If verification is successful, answer will be equal to “1”. Once finished, free the DSA key structure using FreeDsaKey().


DsaVerify(hash, signature, &key, &answer);

FreeDsaKey(&key);

Docs -> CyaSSL Manual

 

Embedded SSL