CryptoSysTM API Manual

Function List    Index

Contents

What is the CryptoSys API?

The CryptoSys API gives you the ability to call fast, efficient cryptographic functions in Visual Basic, VBA, VB.NET, C/C++, C#, and ASP. It can be called from VBA applications like Access, Excel and Word. It provides four of the major block cipher algorithms, a stream cipher algorithm, all the major secure message digest hash algorithms, the HMAC and CMAC message authentication algorithms, a data compression facility, a password-based key derivation function (PBKDF2), and a secure random number generator.

The block cipher algorithms provided are the Advanced Encryption Standard (AES) as specified in FIPS PUB 197; the original Data Encryption Standard (DES); Triple DES (TDEA, 3DES, DES-EDE3); and Bruce Schneier's Blowfish. Key Wrap algorithms for AES and Triple DES are provided [new in version 4.1]. The message digest hash functions are MD5, the Secure Hash Algorithm (SHA-1), SHA-256, SHA-384, SHA-512, and [new in version 4.1] SHA-224. The HMAC algorithm is provided for all these hash algorithms and the CMAC algorithm for the block ciphers Triple DES and AES. The PC1 stream cipher is fully compatible with RC4. The random number generator (RNG) generates cryptographically-secure random numbers to the strict NIST SP800-90 standard, now an Approved Random Number Generator for FIPS PUB 140-2.

The CryptoSys API functions allow you to encrypt, decrypt, hash and authenticate data in a variety of formats, as well as generating secure random keys to use in your applications. Your input data can generally be in a byte array, encoded as a hexadecimal string, or in a file. The functions can process the data in a one-off manner, or, for longer inputs, you can call the "update" functions sequentially after initialising. The block cipher algorithms work in Electronic Codebook (ECB), Cipher Block Chaining (CBC), Cipher Feedback (CFB), Output Feedback (OFB) and Counter (CTR) modes. You can generate random keys and nonces in a secure manner. All functions are thread-safe.

[Contents] [Index]

Introduction

The CryptoSys API provides functions to carry out primitive cryptographic operations intended to be used as part of a security-related application. It is up to you the programmer to ensure that keys, passwords and other private data in your application are kept secret, and to ensure that appropriate security policies and procedures are followed by end users.

This manual assumes you are familiar with the basics of cryptography and can program to a reasonably advanced level.

To get started, read the sections on Installation and General Programming Issues and the section on your programming language:

[Contents] [Index]

Features

[Contents] [Index]

Changes in Version 4.1

Changes in Version 4.0

Changes in Version 3.2

[Contents] [Index]

Conventions in this document

Code in classic Visual Basic (VB6/VBA) is shown shaded as follows (if your browser supports shading and colours):-
Dim strData As String
Dim nRet As Long
strData = "Hello world"
Debug.Print strData
Code in C/C++ is shown as:
char *str = "Hello world";
printf("%s\n", str);
Code in VB.NET (VB200x) is shown as:
Dim nDataLen As Integer
Dim abData() As Byte
If strData.Length = 0 Then Exit Function
abData = System.Text.Encoding.Default.GetBytes(strData)
nDataLen = abData.Length
Code in C# is shown as:
public static string ToHex(byte[] binaryData)
{
   int nBytes = binaryData.Length;
   Int32 nChars = 2 * nBytes;
   if (nBytes == 0) return String.Empty;
   StringBuilder sb = new StringBuilder(nChars);
   nChars = CNV_HexStrFromBytes(sb, nChars, binaryData, nBytes);
   return sb.ToString(0, nChars);
}
Code in VBScript/ASP is shown as:
Dim oGen
Set oGen = Server.CreateObject("diCryptOCX.gen")
Response.Write "Version=" & oGen.Version & Chr(13) & Chr(10)
Output from code samples is shown as:
Result=OK
All functions called directly in the CryptoSys API begin with 3 or 4 capital letters followed by an underscore "_", e.g.
nRet = API_ErrorLookup(strMsg, Len(strMsg), nCode)
For VB users, there are some wrapper functions provided in the module basCryptoSys.bas which avoid the complications of having to pre-dimension strings, etc. These begin with lowercase letters and have no underscore. They are shown in our examples as follows:
strErrMsg = apiErrorLookup(nCode)

[Contents] [Index]

Copyright Notice

Except where otherwise noted, the CryptoSys API executable, sample source code and this manual were written by David Ireland and are copyright (c) 2001-8 by DI Management Services Pty Limited, all rights reserved. They may not be distributed or reproduced separately by any means whatsoever without express permission. Users holding a valid developer's licence are permitted to distribute the executable as part of a value-added application according to the terms of their licence.

You may obtain latest version of CryptoSys API from <http://www.cryptosys.net>.

[Contents] [Index]

Background Basics

For a good introduction to the principles of cryptography refer to Bruce Schneier's Applied Cryptography [SCHN] or William Stallings Cryptography and Network Security [STAL]. For a more advanced treatment, see Handbook of Applied Cryptography by Menezes, van Oorschot and Vanstone [MENE].

Block cipher algorithms

All block cipher algorithms operate on a fixed-length block of data to produce a seemingly-random output of the same size. The security of the encryption process depends on a secret key, the length of which depends on the particular algorithm. It should be impossible (strictly, computationally infeasible) to derive the plaintext from the resultant ciphertext without knowing the key.

The block and key lengths supported in the CryptoSys API package are as follows:

AlgorithmBlock lengthKey length
DES 8 bytes (64 bits) 8 bytes (only 56 bits used out of 64)
Triple DES (TDEA, 3DES) 8 bytes (64 bits) 24 bytes (only 168 bits used out of 192)
Blowfish 8 bytes (64 bits) up to 56 bytes (variable up to 448 bits)
AES 16 bytes (128 bits)* 16 or 24 or 32 bytes (128/192/256 bits)

* The deprecated older-style AES functions still support 192- and 256-bit block lengths but these were not adopted in the FIPS 197 standard.

Block Cipher Modes and Initialization Vectors

The block cipher confidentiality modes in this module comply with Recommendation for Block Cipher Modes of Operation [SP80038A]. To quote from Section 5.3 of that document:

The input to the encryption processes of the CBC, CFB, and OFB modes includes, in addition to the plaintext, a data block called the initialization vector (IV), denoted IV. The IV is used in an initial step in the encryption of a message and in the corresponding decryption of the message.
 
The IV need not be secret; however, for the CBC and CFB modes, the IV for any particular execution of the encryption process must be unpredictable, and, for the OFB mode, unique IVs must be used for each execution of the encryption process.

In Electronic Codebook (ECB) mode, each block is encrypted independently. In Cipher Block Chaining (CBC) mode, an initialization vector (IV) is added to the first block of plaintext before encryption and the resultant ciphertext is added to the next block of plaintext before encryption, and so on. Decryption is the reverse process. The IV does not need to be kept secret and must be communicated to the receiving party along with the ciphertext.

Block ciphers in ECB or CBC mode require their input to be an exact multiple of the block length. Any odd bytes need to be padded to the next multiple. In general, this is the user's responsibility. However, for encrypting files, CryptoSys API adds a padding string using the convention described in Padding below. For all other encryption functions in this API, it is the user's responsibility to provide and handle appropriate padding where necessary for ECB and CBC modes. See Padding.

Cipher Feedback mode (CFB), Output Feedback mode (OFB) and Counter mode (CTR) do not require padding. We include CFB and OFB modes here for completeness where users may need to communicate with a system that requires it. We recommend using either CBC or CTR modes if you have the choice. CBC mode is supported in most encryption systems.

The CTR mode in this package treats the entire "IV" as a 64- or 128-bit "counter". So if the IV provided is, say, 0xFFFFFFFFFFFFFFFD for a 64-bit block cipher, then the counter values used will be:

fffffffffffffffd
fffffffffffffffe
ffffffffffffffff
0000000000000000
0000000000000001
...
It's up to the programmer to ensure that unique IV or counter values are provided for each message encrypted with the same key. Using an IV generated each time with the RNG_NonceData or RNG_NonceDataHex function should be perfectly adequate as the odds against producing a duplicate value are billions to one.

[Contents] [Index]

Padding

Before encrypting random-length plaintext with a block cipher algorithm in ECB or CBC mode it needs to be padded to an exact multiple of the block length.

There are many conventions used in practice, see our web page Using Padding in Encryption. It's up to you and your recipient which method you use, but you must agree on one method and use it consistently. If your data is always an exact multiple of the block length and the sender and the recipient agree then you can omit the padding string.

We recommend the convention from section 6.3 of RFC 3852 [CMS] (formerly RFC 3369 and RFC 2630), PKCS #5 [PKCS5] and PKCS #7 [PKCS7]; namely:

For a 64-bit block size: Append a padding string of between 1 and 8 bytes to make the total length an exact multiple of 8 bytes. The value of each byte of the padding string is set to the number of bytes added; namely, 8 bytes of value 0x08, 7 bytes of value 0x07, ..., 2 bytes of 0x02, or one byte of value 0x01. The length of the plaintext to be encrypted thus will be a multiple of 8 bytes and it will be possible to recover the message unambiguously from the decrypted ciphertext.

For a 128-bit block size (e.g. for AES), replace "8 bytes" in the above paragraph with "16 bytes" and replace "0x08" with "0x10", and reword accordingly.

See the functions PAD_BytesBlock, PAD_UnpadBytes, PAD_HexBlock and PAD_UnpadHex.

[Contents] [Index]

Stream ciphers

A stream cipher operates on streams of plaintext one bit or byte at a time. The PC1 stream cipher in this API has a variable key size and operates on one byte at a time. By an amazing coincidence the PC1 algorithm produces identical results to the proprietary RC4 stream cipher which is in common use, for example, in encrypting PDF files. So you can substitute "RC4" wherever you find "PC1" in this document. The key can be any number of bytes long. The algorithm is very fast. The output is always the same length as the input. There is no 'decrypt' mode: to decipher just encrypt again with the same key.

[Contents] [Index]

One-way message digest (hash) functions

A message digest hash function is a cryptographic primitive used for digital signatures and password protection. It maps a message of arbitrary length to a fixed-length hash value or "message digest". A cryptographic hash should be one-way and collision-resistant. "One-way" means that, given an n-bit hash value, it should require work equivalent to about 2^n hash computations to find any message that hashes to that value. "Collision-resistant" means that finding any two messages which hash to the same value should require work equivalent to about 2^n/2 hash computations. In other words, it should be computationally infeasible to find the original message from the digest or to create another message that produces the same result.

SHA-1 is a 160-bit (20-byte) hash function specified in FIPS PUB 180-2 Secure Hash Standard [FIPS180].

SHA-256 is the newer standard intended as a companion for the new Advanced Encryption Standard (AES) to provide a similar level of enhanced security. SHA-256 is a 256-bit (32-byte) hash and is meant to provide 128 bits of security against collision attacks. SHA-256 is also specified in FIPS PUB 180-2 [FIPS180].

SHA-384 and SHA-512 provide greater levels of security, but at a greater computing cost. Both use the same algorithm but SHA-384 has a different starting value and a shorter digest value.

MD5 is an older, less-secure but faster hash algorithm still in common use.

Message authentication code (MAC) functions

A message authentication code (MAC) is used to establish the authenticity and, hence, the integrity of a message. MACs have two functionally distinct parameters, a message input (data, text) and a secret key known only to the message originator and intended receiver.

MACs based on cryptographic hash functions are known as HMACs. The HMAC algorithm is described in [FIPS198] and RFC 2104 [HMAC]. HMACs can have a key of any length and produce a digest of the same length as the underlying message digest function.

The CMAC algorithm is based on a symmetric key block cipher and is equivalent to the one-key CBC MAC1 (OMAC1) algorithm. CMAC is described in SP800-38B [SP80038B]. CMAC uses either Triple DES or one of the three AES functions. The key length for CMAC is the same as the underlying block cipher. The output is the same length as the block length: 64 bits for Triple DES and 128 bits for AES.

It is permissible to truncate a MAC value, at a cost of reduced security.

[Contents] [Index]

Data Compression in Cryptography

Compressing data before encryption not only makes for shorter messages to be transmitted or stored, but also improves security by reducing the redundancy in the plaintext and making cryptanalysis harder.

CryptoSys API includes compression (deflate) and decompression (inflate) functions based on Jean-loup Gailly's excellent zlib product.

You will need to devise a packet format to store the uncompressed length of the data along with the compressed data itself. There is an example of this posted on our web site - see Using Compression with CryptoSys. Just remember to compress before you encrypt.

[Contents] [Index]

Secure Random Number Generator

Many procedures use a random session key to encrypt the body of the message. If this key is ever compromised - because the random numbers are predictable or can be manipulated before being generated - an opponent who has had access to your encrypted messages can decipher them at his leisure. You never use the standard VB6 Rnd() or C stdlib rand() functions to generate your keys! For more examples of potential problems see [GUTM] and [KELS98].

RNG Mechanisms

The random number generator used in the CryptoSys API has been redesigned as of Version 4.0 to conform to the more conservative NIST Special Publication 800-90 Recommendation for Random Number Generation Using Deterministic Random Bit Generators [SP80090], first published June 2006. Entropy is accumulated in "Fortuna" pools as described in Ferguson and Schneier, Practical Cryptography, [FERG03]. Under any circumstances, this algorithm provides more secure random numbers than ANSI X9.31 Appendix A [AX931]. The full technical details are published on our web site.

The underlying RNG functions use the algorithms recommended in NIST SP 800-90 [SP80090] (the "DRBG Standard") to provide a Deterministic Random Bit Generator (DRBG). The HMAC_DRBG mechanism is used with SHA-1 as the underlying hash function. This outputs a sequence of binary bits that appears to be statistically independent and unbiased. The output is effectively random so long as internal actions of the process are hidden from observation. In particular the algorithm provides good Backtracking Resistance and, depending how it is used, good Prediction Resistance.

Entropy is accumulated at startup and whenever certain functions in the library are called. Only inobtrusive methods of collecting entropy are used, so you can use the API safely in any application. The "Fortuna" method of pooling is used to prevent certain attacks from someone who controls some but not all of the entropy sources (see chapter 10 of [FERG03]). The more times your application calls the functions in the library before needing some random data, the more entropy will be accumulated. The user cannot control how or when the Fortuna entropy is added to the RNG process - this is by design. The advantage of the Fortuna system is that the level of entropy does not need to be measured. There is, however, a period of vulnerability just after start up when there may not be sufficient entropy in the pools. This can be overcome by initializing with a seed file.

We strongly recommend that you use and initialize with a seed file wherever possible.

Techniques to add known security strength to the RNG process

1. Use a seed file
Use the RNG_Initialize function to specify a seedfile with a known minimum amount of entropy to initialise the PRNG. This seed file is updated automatically when used. You can optionally call the RNG_UpdateSeedFile from time to time in your application, and use RNG_MakeSeedFile to create a new one. The security of this method is as good as the security you have over the seed file. If an attacker controls the seed file, it does not mean they control the random output data; it just means that using a seedfile does not increase the security strength of the PRNG.
2. Make the user enter random keystrokes
Use the RNG_BytesWithPrompt function when generating random data to force the user to generate entropy using random keystrokes and mouse movements. RNG_MakeSeedFile also uses such a prompt. This works provided you know the user's keyboard strokes and mouse movements are secure (e.g. are not being transmitted over a network).
3. Add your own entropy
If you have your own independent source of entropy, add this "additional input" to the RNG process as a "seed" when using the RNG_KeyBytes function. If you assume zero security strength for the internally-generated entropy and you add input with, say, 128 bits of security strength, then the output from the RNG will have at least 128 bits of security strength.

User-supplied entropy (seeds)

User-supplied entropy (a.k.a. a "seed") is added as "additional input" to the generation process. It does not affect the accumulation pools and cannot be used by an attacker to control the output.

Remember it's not how "random" your user-supplied entropy is, but how little an attacker knows about it. Using the current time is no use. If you can provide 32 bytes* of data of which an attacker knows nothing and cannot later discover, then you have added 128 bits of security strength.
* The bytes must have been selected randomly from the range 0 to 255.

For more details on the security aspects of the random number generator, see the technical details published on our web site.

CryptoSys API also lets you generate nonces - a term used in security engineering meaning "number used once". Use a nonce where random but not-necessarily-unpredictable numbers are required: e.g. for initialization vectors, SSL cookies and random padding data.

[Contents] [Index]

Installation

Use the setup.exe program to install CryptoSys API onto your computer. To uninstall, use the the Start>Settings>Control Panel>Add/Remove Programs option from Windows. Instructions on how to distribute the product to third-party users are provided with the Licensed Developer version - see the file distrib.txt for more details.

Important: You must use the setup.exe program to install the Personal and Server Trial versions on your system and you must have administrator rights when installing or uninstalling either of these versions.

Core executable DLL

The core executable file is diCryptoSys.dll which is a Win32 DLL. This file must exist in the library search path on the user's system for all programming language interfaces. The executable diCryptoSys.dll is not registered with RegSvr32 (it can't be). The VB6/VBA and C/C++ interfaces access this core executable directly.

Wrapper DLLs

Two wrapper executables are provided to allow COM and .NET programming access to the core executable. Both require the core Win32 DLL to exist in the library search path.
  1. diCryptOCX.dll is an ActiveX DLL which exposes various classes to allow programming access from ASP, VBScript and other COM applications including VB. This DLL does require registering. To register, copy the diCryptOCX.dll to a convenient folder, open a command-line window, and type
    REGSVR32 diCryptOCX.dll
    
  2. diCrSysAPINet.dll is a .NET Class Library which exposes various classes to allow programming access from C# and VB.NET projects. This file is referenced from your .NET project. It is not registered.
For more information on the executables, see Technical Details.

[Contents] [Index]

General Programming Issues

Storing and representing ciphertext

Ciphertext is not text!
The input to and output from an encryption function is, strictly speaking, a bit string. A `bit string' is an ordered sequence of `bits', each of value either `0' or `1'. There isn't a convenient `bit string' type in the usual programming languages so we use an ordered sequence of `bytes' instead, 8 bits to one byte, and we almost always choose to work with values that are an exact multiple of 8 like 64 bits or 256 bits to make life easier.

The input to an encryption function is usually a representation of a text string like "Hello world!". Different systems store text in different ways. You need to convert the text to an unambiguous sequence of bytes before you encrypt it. For ECB and CBC modes you need to add padding bytes as well to ensure the input block is an exact multiple of the cipher block size.

Do not store ciphertext bytes in a string.

Once encrypted, the output is another sequence of bytes known as ciphertext. This sequence of bytes is generally not printable - it shows up as garbage. You can safely save this sequence of bytes directly to a binary file. It's often more convenient to encode the ciphertext bytes into a hexadecimal or base64 string, which is much easier to handle. But you do not convert the ciphertext back to text. It won't work.

When decrypting, after you've deciphered the ciphertext back to plaintext, you still have a sequence of bytes. You need to convert these bytes back to a string of text before you can read it, provided your decryption was successful.

Use the functions below to convert a string of text to an unambiguous array of bytes and vice versa.

Converting strings to bytes and vice versa

In VB6/VBA, use the StrConv function.

Dim abData() As Byte
Dim Str As String
Dim i As Long
Str = "Hello world!"
' Convert string to bytes
abData = StrConv(Str, vbFromUnicode)
For i = 0 To UBound(abData)
    Debug.Print Hex(abData(i)); "='" & Chr(abData(i)) & "'"
Next
' Convert bytes to string
Str = StrConv(abData, vbUnicode)
Debug.Print "'" & Str & "'"
48='H'
65='e'
6C='l'
6C='l'
6F='o'
20=' '
77='w'
6F='o'
72='r'
6C='l'
64='d'
21='!'
'Hello world!'

In VB.NET use System.Text.Encoding.

Dim abData() As Byte
Dim Str As String
Dim i As Long
Str = "Hello world!"
' Convert string to bytes
abData = System.Text.Encoding.Default.GetBytes(Str)
For i = 0 To UBound(abData)
    Console.WriteLine(Hex(abData(i)) & "='" & Chr(abData(i)) & "'")
Next
' Convert bytes to string
Str = System.Text.Encoding.Default.GetString(abData)
Console.WriteLine("'" & Str & "'")
You could be more explicit by replacing .Default with .GetEncoding(1252), and then use the appropriate code page for your character set (1252 is Western European).

In C#, use System.Text.Encoding, which has identical behaviour to the function in VB.NET.

byte[] abData;
string Str;
int i;
Str = "Hello world!";
// Convert string to bytes
abData = System.Text.Encoding.Default.GetBytes(Str);
for (i = 0; i < abData.Length; i++)
{
	Console.WriteLine("{0:X}", abData[i]);
}
// Convert bytes to string
Str = System.Text.Encoding.Default.GetString(abData);
Console.WriteLine("'{0}'", Str);
In C and C++, the distinction between a string and an array of bytes is often blurred. A string is a zero-terminated sequence of char types and bytes are stored in the unsigned char type. A string needs an extra character for the null terminating character; a byte array does not, but it needs its length to be stored in a separate variable.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static void pr_hexbytes(const unsigned char *bytes, int nbytes)
/* Print bytes in hex format + newline */
{
   int i;
   for (i = 0; i < nbytes; i++)
   	printf("%02X ", bytes[i]);
   printf("\n");
}

int main()
{
   char szStr[] = "Hello world!";
   unsigned char *lpData;
   long nbytes;
   char *lpszCopy;

   /* Convert string to bytes */
   /* (a) simply re-cast */
   lpData = (unsigned char*)szStr;
   nbytes = strlen(szStr);
   pr_hexbytes(lpData, nbytes);

   /* (b) make a copy */
   lpData = malloc(nbytes);
   memcpy(lpData, (unsigned char*)szStr, nbytes);
   pr_hexbytes(lpData, nbytes);

   /* Convert bytes to a zero-terminated string */
   lpszCopy = malloc(nbytes + 1);
   memcpy(lpszCopy, lpData, nbytes);
   lpszCopy[nbytes] = '\0';
   printf("'%s'\n", lpszCopy);

   free(lpData);
   free(lpszCopy);

   return 0;
}
48 65 6C 6C 6F 20 77 6F 72 6C 64 21
48 65 6C 6C 6F 20 77 6F 72 6C 64 21
'Hello world!'

The types char and unsigned char might be identical on your system, or they might not be. We strongly recommend that you explictly distinguish between strings and byte arrays in your code by using the correct type and consistently treating them differently.

If your string is a Unicode string, then it consists of a sequence of wchar_t types. Converting wide-character strings to a sequence of bytes in C is more problematic. You can either convert the Unicode string directly to a string of bytes (in which case every second byte will be zero for US-ASCII characters), or use the stdlib wcstombs function or the Windows WideCharToMultiByte function to convert to a sequence of multi-byte characters (some will be one byte long, some two) and then convert the multi-byte string to bytes (you can do this with a simple cast). Each party encrypting and decrypting must agree on which way to do it.

[Contents] [Index]

Hexadecimal versus Bytes

Almost all the functions in CryptoSys API have a `Bytes' and a `Hex' version. The Bytes version expects its input as an array of bytes (unsigned char* in C/C++). The Hex version expects its input as a hexadecimal-encoded string consisting only of the characters [0-9A-Fa-f] where two hex characters represent an 8-bit byte.

In all these cryptographic algorithms, the underlying operations are carried out on 8-bit bytes (sometimes referred to as octets). See Storing and representing ciphertext.

In practice, especially with VB and VBScript, you may find it more convenient to use the 'Hex' versions and pass all your data to the API functions as hexadecimal-encoded strings.

Use the CNV_BytesFromHexStr and CNV_HexStrFromBytes functions to convert between bytes and hexadecimal strings. Use the Visual Basic StrConv function to convert between a String and an array of Byte values. See Converting strings to bytes and vice versa.

Note that the CNV_BytesFromHexStr function will - by design - filter invalid hex characters and return the resulting bytes from whatever is left without error. The hex versions of the encryption functions are stricter and will fail if any invalid hex characters are found in the input.

If your input data is in Unicode or UTF-16 format (e.g. your operating system is set up for CJK characters), then you are strongly recommended to convert your input data to unambiguous hexadecimal format before trying to use the functions in this API. Do not try and use the Visual Basic String type or it will end in tears.

For various historical reasons the Hex encryption functions return their results in upper case and the hash digest functions in lower case. Just be careful if you use the case-sensitive strcmp() function in the C string.h library or if your Visual Basic options are set to Option Compare Binary.

It's your decision which way you do it, but please be consistent.

[Contents] [Index]

Return Values

All the core VB6/C functions in this API return a 32-bit signed integer value, that is a Long in VB6/VBA and a long in C/C++, but an Integer in VB.NET and an int in C#. The wrapper functions provided in the .NET and ActiveX interfaces behave differently (and more conveniently) - please refer to the detailed documentation on those interfaces.

Functions either

  1. return zero to indicate success or a non-zero error code; or
  2. return a positive value to indicate, say, a required length or CRC value, or a negative error code.

The exception is the _Init functions which return a non-zero context handle on success or zero if an error has occurred. Always check the return value before continuing. Use the _InitError function to find out the code for the error that has occurred. The value itself of the context handle is unimportant, but do not change its value.

[Contents] [Index]

Using with Classic Visual Basic and VBA

To call the CryptoSys API functions from a classic Visual Basic project or VBA application, just add the module basCryptoSys.bas to your project (VBA users should delete the first line Attribute VB_Name = "basCryptoSys").

The VB functions work in the same way as you would call the Win32 API functions from VB. You must use the correct variable types and must pre-dimension strings and byte arrays that are to receive output or you will suffer the wrath of the great god Gee-pee-eff.

For examples, see the test code provided in the distribution in the folder C:\Program Files\CryptoSys\VB6.

Pre-dimensioning for VB

To create a string of, say, length 40 characters, do either:
Dim sData As String * 40
or
Dim sData As String
sData = String(40, " ")
If you know the output string needs to be the same size as the input, do this:
Dim strInput As String
Dim strOutput As String
strInput = "......"
strOutput = String(Len(strInput), " ")
To create a byte array of a given length:
Dim abData() As Byte
Dim nLen As Long
nLen = 40
ReDim abData(nLen - 1)
Note that byte arrays in VB are indexed from 0 to nLen - 1.

To create a byte array of the same length as an existing array, do this:

Dim abOutput() As Byte
ReDim abOutput(Ubound(abInput))

To find the length of an existing byte array:

nLen = UBound(abData) - LBound(abData) + 1
Be careful, as this will cause a run-time error if abData() has not been ReDim'd. Look at the code for the function cnvHexStrFromBytes in basCryptoSys.bas to see how this can be handled.

Other Issues For VB6/VBA Users

[Contents] [Index]

Using with C and C++

To use with a C or C++ program, include the diCryptoSys.h file with your source code and link with the diCryptoSys.lib library. The only non-ANSI C requirement is that your complier supports the __stdcall calling convention to call Win32 API functions from a Win32 DLL. The sample C code API_Examples.c provided in the distribution carries out a variety of tests using known test vectors. There are examples given for each function.

You'll also realise that this manual is written primarily for Visual Basic programmers. Apologies, sort of, because we know you can easily work what to do from the examples given in the sample C programs and the rest of this manual.

The VB6/VBA functions and C/C++ functions are identical in form. The function names are identical, the arguments are the same (even though we may have used different parameter names in the VB and C syntaxes), and the same warnings given in the Remarks section apply to both. Just be careful to add an extra character for output string types in C.

Type Conversions

The following type conversions apply:-

Visual BasicC/C++
ByVal x As Stringchar *x
ByRef x As Byteunsigned char *x
ByVal x As Longlong x

Earlier versions used the Boolean type for the bEncrypt variable. This has been changed [Version 4.0] in the Declarations to take a 32-bit Long type, which still works in VB6 even if the variable passed has been dimensioned as a Boolean type, so this should not break any existing code. We recommend that you use the defined constants ENCRYPT and DECRYPT in your VB6 and C code.

Compiling with C

The API has been compiled and tested successfully with Microsoft Visual C++ (versions 5, 6, 7 and 8=VS2005/Express 2005) and Borland C++Builder version 5.5.

Here is some minimal code:-

/* myapisource.c */
#include <stdio.h>
#include "diCryptoSys.h"
int main()
{	
  char *message = "abc";
  long ret;
  char digest[41]; 
  ret = SHA1_StringHexHash(digest, message);
  printf("SHA1(%s)=\t%s\n", message, digest);
  printf("Correct =\t%s\n", "a9993e364706816aba3e25717850c26c9cd0d89d");
  return 0;
}
To create myapisource.exe with MSVC++:
cl myapisource.c diCryptoSys.lib
Running this program should result in
SHA1(abc)=      a9993e364706816aba3e25717850c26c9cd0d89d
Correct =       a9993e364706816aba3e25717850c26c9cd0d89d

Using With Borland C++

The lib file distributed with the program is made using MSVC. With Borland you need to generate a new .lib file directly from the DLL using the IMPLIB utility:
implib diCryptoSys.lib diCryptoSys.dll
To compile with Borland C++:
bcc32 myapisource.c diCryptoSys.lib

Cautions for C/C++ Users

We recommend using the defined constants like API_SHA1_CHARS and API_SHA1_BYTES rather than hard-coded numbers, e.g.
char sDigest_sha1[API_SHA1_CHARS + 1]; 
See the constants in diCryptoSys.h.

For examples, see the test code API_Examples.c and APICheck.c provided in the distribution.

[Contents] [Index]

Using with .NET: C# and VB.NET

To use the .NET interface with C# and VB.NET:
  1. Copy the dotnet diCrSysAPINet.dll library file into a convenient folder.
  2. In your application, add a reference to the library:
    1. Project > Add Reference.
    2. In the .NET tab, click on the Browse button to find and select the library file diCrSysAPINet.dll.
    3. Click on OK and the wizard will add the reference of the class library to your project.
  3. Add the line (for C#)
    using CryptoSysAPI;
    
    or (for VB.NET)
    Imports CryptoSysAPI
    
    to your code.
  4. Call the methods in the various classes. Note that the methods in the .NET interface may have different parameters and return values to the functions in the core VB6/C DLL. Refer to the separate .NET Help File for the details.

Alternatively, with C#, you can just include the source code module CryptoSysAPI.cs in your project and there is no need to reference the class library DLL.

There are two different types of methods used in the .NET interface:-

  1. A simple static method. These carry out the cryptographic operation with the given parameters and return the result in a one-off operation. These are the simplest methods to use and are recommended in all environments if you know in advance what your data consists of.
  2. The object-oriented Init/Update/Dispose methods that create an instance and allow the user to add data continuously in blocks of any (valid) length. Use these methods when your data is not available in one chunk and you need to progressively operate on incoming data.

We recommend that you use the static methods if you only have a single block of data to operate on.

For examples, see the test code TestAPIcsharp.cs and TestAPIvbnet.vb provided in the distribution.

In Version 3.1 we suggested using direct upgrades of the VB6 code in VB.NET with all the pre-dimensioning and other unsafe practices. The .NET Class Library interface is cleaner, safer and more convenient. If you are writing VB.NET code from scratch, please use the .NET Class Library interface. If you need to upgrade old VB6 code, see Upgrading VB6 to VB.NET.

.NET Help File

The .NET classes and methods have different parameters and return values to the VB/C functions described in this manual. Full details are provided in the separate help file CryptoSysAPI.chm supplied with the distribution (Hint: it should be in the folder C:\Program Files\CryptoSys\DotNet).

[Contents] [Index]

Using with COM/ASP

The file diCryptOCX.dll is an ActiveX wrapper that provides an interface to most functions in the CryptoSys API. Strictly it's an ActiveX DLL, not an OCX, but we think three-letter acronyms with an "X" in them are cool.
  1. Install CryptoSys API on the target machine. Use the Developer or Server Test Version; the Personal Version will not work with IIS or ASP.
  2. Copy the file diCryptOCX.dll into a convenient directory on the target machine.
  3. Register the ActiveX DLL with the command
    regsvr32 diCryptOCX.dll
  4. Either in a VB project set a reference to diCryptOCX.dll (Project>References>Browse...) then
    Dim oGen = New diCryptoOCX.gen
    Debug.Print "Version=" & oGen.Version
    
  5. Or, in an ASP page
    Dim oGen
    Set oGen = Server.CreateObject("diCryptOCX.gen")
    Response.Write "Version=" & oGen.Version
    
Refer to the syntax and details of the classes and methods of the ActiveX interface.

Note: Almost all the functions require the data to be encoded in hexadecimal. Handling byte array types in VBScript is fraught with problems so we don't even offer the option.

For examples, see the test code apiocxtests.asp and other ASP test pages provided in the distribution (look in the folder C:\Program Files\CryptoSys\COM).

[Contents] [Index]

"Hello world" programs

The equivalent of the "Hello world" program for CryptoSys API is to call the API_Version function. The function will demonstrate that the API is properly installed. Here is some example source code in VB6, C, C#, VB.NET and ASP, respectively.
Public Sub ShowVersion()
   Dim nRet As Long
   nRet = API_Version()
   Debug.Print "Version=" & nRet
End Sub
#include <stdio.h>
#include "diCryptoSys.h"
int main(void) 
{
   long version;
   version = API_Version();
   printf("Version=%ld\n", version);
   return 0;
}
using CryptoSysAPI;
static void ShowVersion()
{
   int ver;
   ver = General.Version();
   Console.WriteLine("Version={0}", ver);
}
Imports CryptoSysAPI	
Shared Sub ShowVersion()
   Dim ver As Integer
   ver = General.Version()
   Console.WriteLine("Version={0}", ver)
End Sub
<%
   Dim oGen
   Set oGen = Server.CreateObject("diCryptOCX.gen")
   Response.Write "Version=" & oGen.Version & Chr(13) & Chr(10)
%>

[Contents] [Index]

Security Issues

  1. The functions and methods in this toolkit provide cryptographic primitives intended to be used as part of a security-related application. It is up to you the programmer to ensure that keys, passwords and other private data are kept secret, and to ensure that appropriate security policies and procedures are followed by end users.
  2. CryptoSys API is a 32-bit dynamically linked library (DLL) that provides encryption services to applications running on Microsoft Windows® operating systems. On Windows, it is designed for and supports multi-threaded operation.
  3. In FIPS 140-2 terms, CryptoSys API is a multi-chip standalone module, consisting of the file diCryptoSys.dll. It is intended to meet FIPS 140-2 security level 1. The cryptographic boundary for CryptoSys API is defined as the enclosure of the computer on which the cryptographic module is installed. As a pure software product, CryptoSys API provides no physical security by itself. The computer itself must be appropriately physically secured.
  4. Functions that advertise that they create files will overwrite any existing file of the same name without warning.
  5. No other files, temporary or permanent, are ever created by this toolkit.
  6. There is no communications functionality whatsoever in this module. It will never attempt to "dial home" or make any attempt to create a communications socket. If your firewall tells you there is an attempt to create an internet connection, you have a virus or trojan of some sort unrelated to the CryptoSys API module.
  7. The Developer version makes no attempts to read or write to the Windows registry whatsoever under normal operations. However, optional registry settings may be made and will be read and acted on in the unlikely event that a critical error occurs.
  8. The Personal version creates and updates registry entries in HKCU\Software\DI Management.
  9. The Personal and Trial Server versions read entries created by the setup utility in HKLM\Software\DI Management. Do not attempt to change these entries.
  10. Developer versions distributed to end users do not require any registry entries on the user's machine (but see optional registry settings).
  11. The DLL carries out self-tests when it is first attached to the parent Windows process including a check on the integrity of the software module, i.e. the DLL file itself. If this fails, the module will exit the process. This should only happen if someone has tampered with the DLL file.
  12. To check you have a valid version of the CryptoSys API executable, please check the CRC and hash digests published on our web site.
  13. VB/C functions that write output to a string or byte array require the output to be "pre-dimensioned" first. Make sure any specified length matches the size of the string or a GPF error will result. It is recommended to write simple wrapper functions to prevent such problems. Examples are given in the Visual Basic declarations modules and in the source code for the COM interface.

[Contents] [Index]

Self-Tests

The module performs power-up self-tests and conditional self-tests to ensure that it is functioning properly. Power-up self-tests are performed when the module is powered up, i.e. when the DLL is first attached to the parent Windows process. Conditional self-tests are performed when certain security functions are invoked.

Power-up Self-Tests

The following power-up self-tests are performed:-

Cryptographic algorithm test:

Software integrity test:

The integrity of the software module is tested using a 32-bit error detection code (EDC). The value of this EDC is set and stored when the module is created. On testing, the EDC is re-computed for the DLL module file being used and compared with the stored value. If the values do not match, the test fails.

In addition to this automatic software integrity test, the integrity of the entire DLL file can be independently verified by the user using published SHA-1 and MD5 message digest and CRC-32 values before and after installation.

Conditional Tests

The following conditional tests are performed:-

Continuous random number generator test

When the module is first loaded or instantiated in a new thread, the RNG generates a 64-bit block which not used but is saved in thread-safe memory for comparison with the next 64-bit block to be generated. Each subsequent generation of a 64-bit block is compared with the previously generated block. The test fails if any two compared 64-bit blocks are equal. In addition, each time the RNG function is called it compares the first 64-bit block generated with the first 64-bit block generated on the previous call. The test fails if these blocks are equal. No blocks are saved that have actually been previously output by the generator.

Action if a self-test fails

Any failure of a power-up test or conditional test will cause the following actions to take place:
  1. An error message will be logged to the event log (NT+ systems only).
  2. The system will (try to) save the error message in a log file* in the same directory as the calling process executable.
  3. A message box will display on the screen.
  4. The DLL will terminate the process to prevent further use of cryptographic functions.

* The error log file will be given a filename "apierr.log". If the process does not have permissions to write to that directory, no log file be created.

You can make settings in the machine's registry to prevent the message box displaying and to change the destination directory of the log file. See Optional Registry Settings. It is not possible to prevent the DLL from exiting if a critical error happens.

The user may call the power-up self-tests on demand with the API_PowerUpTests function. In the event that such an "on demand" test fails, the module will log the error event and return an error code but will not terminate the process.

Note that the automatic self-tests fail only in exceptional circumstances. You should never see one in practice unless the software module has been tampered with.

[Contents] [Index]

Optional Registry Settings

The following optional registry settings may be made to change the behaviour of the module if a critical error occurs.

Disclaimer Modifying the registry can cause serious problems that may require you to reinstall your operating system. We cannot guarantee that problems resulting from the incorrect use of the registry can be solved. Use the information provided at your own risk.

Disable message boxes if a critical error occurs

The default behaviour is to display a pop-up MessageBox if a critical error occurs. Users running the toolkit on an unattended server or within an IIS application can disable pop-ups to prevent problems (IIS gets a bit upset if an application displays a pop-up). Set the value to '1' to disable pop-up messages from appearing. Note that this will not prevent the 'first user' or expiry dialogs appearing with the Test Version.
Key: [HKEY_LOCAL_MACHINE\Software\DI Management\CryptoSys\Options]
Value Name: NoMessageBox
Data Type: REG_DWORD
Data: 1 = MessageBoxes disabled, 0 = MessageBoxes enabled (default)

Set directory to write error log file after a critical error

The default behaviour if a critical error occurs is to try to write to an error log file in the same directory as the parent executable file that called the DLL. To change this directory create a REG_SZ value of 'ErrorLogDir' in the key below and set the value to the directory you want, e.g. "C:\myfolder\subdir". The directory name should not have a trailing slash character.
Key: [HKEY_LOCAL_MACHINE\Software\DI Management\CryptoSys\Options]
Value Name: ErrorLogDir
Data Type: REG_SZ

Disable creation of error log file if a critical error occurs

To disable the creation of an error log file altogether, create a REG_DWORD value of 'NoErrorLog' in the key below. Set the value to '1' to disable.
Key: [HKEY_LOCAL_MACHINE\Software\DI Management\CryptoSys\Options]
Value Name: NoErrorLog
Data Type: REG_DWORD
Data: 1 = Error log file disabled, 0 = Error log file enabled (default)

Record event log messages properly

The following registry entry is required for the Event Log messages to be recorded properly. If this entry is not present, or the path to the DLL is wrong, the event log entries will be of the form:
The description for Event ID ( 8xxx ) in Source ( diCryptoSys ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer.
For correct formatting of the message, create the REG_SZ and REG_DWORD values in the key below. The message will still be recorded even if this entry is not present.
Key: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\diCryptoSys]
Value Name: EventMessageFile
Data Type: REG_SZ
Data: Full path to DLL file, e.g. "C:\WINNT\system32\diCryptoSys.dll"
 
Value Name: TypesSupported
Data Type: REG_DWORD
Data: 7 (0x7)

[Contents] [Index]

Upgrading from Older Versions

Upgrading VB6 to VB.NET

If you are writing VB.NET code from scratch, we recommend you use the classes and methods in the .NET Class Library. If you need to upgrade old VB6 code to VB.NET, please note the following:
  1. Change all variables dimensioned as Long to Integer. CryptoSys API always uses 32-bit integers.
  2. All strings in CryptoSys API are ANSI strings. Change statements of the form
    Declare Function Foobar
    to
    Declare Ansi Function Foobar
  3. Change statements of the form
    strBuffer = String(n, " ")
    to
    strBuffer = New String(" "c, n)
    Note the 'c' after the " ". This is required for the Strict On option.
  4. Use System.Text.Encoding.Default.GetBytes(Str) and System.Text.Encoding.Default.GetString(abData) to convert between text strings abd bytes instead of StrConv(Str, vbFromUnicode) and StrConv(abData, vbUnicode).

New AES Functions

Faster AES encryption functions were added in version 3 which have standardised on the 128-bit block size specified in FIPS 197. The additional 192- and 256-block sizes in the original Rijndael proposal were not adopted in the standard (CryptoSys API was first issued before the standard was published). There is a complete set of functions for each key size - AES128, AES192 and AES256 - rather than specifying it as a parameter.

Old-style:

AES_Hex(strOutput, strInput, strHexKey, 128, 128, True) ' Deprecated
AES_Hex(strOutput, strInput, strHexKey, 192, 128, True) ' Deprecated
AES_Hex(strOutput, strInput, strHexKey, 256, 128, True) ' Deprecated

Replace with:

AES128_Hex(strOutput, strInput, strHexKey, True)
AES192_Hex(strOutput, strInput, strHexKey, True)
AES256_Hex(strOutput, strInput, strHexKey, True)
The older-style but deprecated AES functions with variable 128/192/256 block sizes have been retained for compatibility with earlier versions.

[Contents] [Index]

Stricter input requirements for encryption functions

In Version 3 we have tightened up the requirements for input to the block encipher functions (AES, DES, Triple DES and Blowfish) to prevent the functions returning a seemingly-valid result for incorrect input. Earlier versions of the API would have substituted zeroes (or random values) for missing data or ignored trailing bytes.

Input Data: Input data to the block encipher functions in ECB or CBC mode must be an exact multiple of the block length (16 bytes for AES, 8 bytes for the others) or the functions will return an error. It is the user's responsibility to provide padding where necessary and to remove the padding after decryption. Failure to do this will result in one of these errors:-

Input not multiple of 8 bytes long
Input not multiple of block size
See Padding for more guidance on preparing your plaintext for encryption.

This rule on input lengths does not apply to the file encryption functions which automatically provide their own padding.

Keys and IV: All the keys and initialization vectors provided in hex format must be of the exact required length or the function will return an error:-

Invalid key length
Invalid initialization vector

Note also that the CNV_BytesFromHexStr function will - by design - filter invalid hex characters and return the resulting bytes from whatever is left without error. The hex versions of the encryption functions are stricter and will fail if any invalid hex characters are found in the input. See Hexadecimal versus Bytes for more details of the hex conversion functions.

[Contents] [Index]

Technical Details

The core executable diCryptoSys.dll is a Win32 DLL compiled with Microsoft Visual C++ 2005. All programming language interfaces require this DLL to exist in the library search path of the user's system. The core cryptographic functions are written in pure ANSI C with extensive internal checks for memory leaks and overflow issues. The executable diCryptoSys.dll is compatible with all versions of 32-bit Windows (95/98/Me/NT4/2K/XP/2003/Vista). It does not require any other special libraries to work apart from the standard Win32 libraries available in all 32-bit versions of Windows. It is totally independent of the Microsoft Cryptographic API. A version of the DLL compiled for x64 is also provided.

The wrapper executable diCryptOCX.dll is an ActiveX DLL created with Microsoft Visual Basic 6.0 SP6. It calls the functions in the core Win32 DLL via diCryptoSys.tlb, which is available in the ActiveX source code. The source code for this wrapper DLL is provided in the distribution. The executable diCryptOCX.dll must be registered on the end-user's system using REGSVR32.EXE. For more details on its use, see Using with COM/ASP.

The wrapper executable diCrSysAPINet.dll is a .NET Class Library created with Microsoft .NET Framework Version 2.0.50727 and Microsoft Visual C# 2005, compiled for all platforms. This should be upwards compatible with all later versions. It calls the functions in the core Win32 DLL using System.Runtime.InteropServices. The source code for this wrapper DLL is provided in the distribution. For more details on its use, see Using with .NET.

[Contents] [Index]

Compliance

AES complies with:

Triple DES (TDEA, 3DES, des-ede3) complies with:

DES complies with these now-withdrawn standards:

The block cipher modes of operation comply with

The SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 algorithms comply with:

The MD5 algorithm complies with:

The PBKDF2 algorithm complies with:

The random number generator conforms to

[Contents] [Index]

References

[Contents] [Index]

Function List

AES   Blowfish   DES   Triple DES (TDEA)   PC1 (RC4)   Key Wrap   Hash   SHA-1   SHA-256   MD5   MAC   RNG   Compression   PBE   Padding   Conversion   CRC   Misc   ActiveX  

Advanced Encryption Standard (AES)

The AES functions have a separate set of functions for each of the three key sizes. All operate with a block size of 16 bytes. All expect a key of the respective length to be provided.
CAUTION: all three sets share the same context for the Init-Update-Final functions.
AES128_Hex
AES128_HexMode
AES128_Bytes
AES128_BytesMode
AES128_B64Mode
AES128_File
AES128_FileHex
AES128_Init
AES128_InitHex
AES128_InitError
AES128_Update
AES128_UpdateHex
AES128_Final
AES192_Hex
AES192_HexMode
AES192_Bytes
AES192_BytesMode
AES192_B64Mode
AES192_File
AES192_FileHex
AES192_Init
AES192_InitHex
AES192_InitError
AES192_Update
AES192_UpdateHex
AES192_Final
AES256_Hex
AES256_HexMode
AES256_Bytes
AES256_BytesMode
AES256_B64Mode
AES256_File
AES256_FileHex
AES256_Init
AES256_InitHex
AES256_InitError
AES256_Update
AES256_UpdateHex
AES256_Final

[Contents] [Index]

Blowfish

Blowfish can have a key of variable length from one to 56 bytes. The Byte variants need you to specify the key length, but the Hex variants will use whatever length is provided in the key hex string. The block and IV are always 8 bytes long.

BLF_Hex
BLF_HexMode
BLF_Bytes
BLF_BytesMode
BLF_B64Mode
BLF_File
BLF_FileHex
BLF_Init
BLF_InitHex
BLF_InitError
BLF_Update
BLF_UpdateHex
BLF_Final

[Contents] [Index]

Data Encryption Standard (DES)

The key for DES is always 8 bytes long; the block length is 8 bytes. There is no need to specify the key length when calling the DES functions, but the input variables must be long enough. The parity bits in the key are ignored.

DES_Hex
DES_HexMode
DES_Bytes
DES_BytesMode
DES_B64Mode
DES_File
DES_FileHex
DES_Init
DES_InitHex
DES_InitError
DES_Update
DES_UpdateHex
DES_Final
DES_CheckKey
DES_CheckKeyHex

[Contents] [Index]

Triple Data Encryption Algorithm (TDEA, Triple DES, DES-EDE3)

The key for TDEA is always 24 bytes long; the block length is 8 bytes. There is no need to specify the key length when calling the TDEA functions, but the input variables must be long enough. The parity bits in the key are ignored.

TDEA_Hex
TDEA_HexMode
TDEA_Bytes
TDEA_BytesMode
TDEA_B64Mode
TDEA_File
TDEA_FileHex
TDEA_Init
TDEA_InitHex
TDEA_InitError
TDEA_Update
TDEA_UpdateHex
TDEA_Final

[Contents] [Index]

PC1 Stream Cipher

PC1 is a variable-key-size stream cipher. It produces identical output to the proprietary RC4 (TM) stream cipher. It operates on individual bytes. To decrypt, just encrypt again with the same key.

PC1_Bytes
PC1_File
PC1_Hex

[Contents] [Index]

Key Wrap

CIPHER_KeyWrap - Wraps (encrypts) a content-encryption key with a key-encryption key.
CIPHER_KeyUnwrap - Unwraps (decrypts) a content-encryption key with a key-encryption key.

[Contents] [Index]

Message Digest Hash

HASH_Bytes
HASH_File
HASH_HexFromBytes
HASH_HexFromFile
HASH_HexFromHex

[Contents] [Index]

Message Authentication Codes

MAC_Bytes
MAC_HexFromBytes
MAC_HexFromHex

[Contents] [Index]

Secure Hash Algorithm (SHA-1)

All the SHA-1 functions (except SHA1_BytesHash) output the message digest as a String in hexadecimal format. You must set the length of the output string to a minimum of 40 characters before calling the digest functions (41 characters in a C program). See Pre-dimensioning a string for instructions on how to do this.

SHA1_StringHexHash
SHA1_BytesHexHash
SHA1_BytesHash
SHA1_FileHexHash
SHA1_Init
SHA1_AddBytes
SHA1_AddString
SHA1_HexDigest
SHA1_Reset
SHA1_Hmac
SHA1_HmacHex

[Contents] [Index]

Secure Hash Algorithm (SHA-256)

The SHA-256 functions are identical in syntax and usage to their SHA-1 equivalents, except the string to receive the message digest must be set to a minimum of 64 characters (65 in a C program). See Pre-dimensioning a string.

SHA2_StringHexHash
SHA2_BytesHexHash
SHA2_BytesHash
SHA2_FileHexHash
SHA2_Init
SHA2_AddBytes
SHA2_AddString
SHA2_HexDigest
SHA2_Reset
SHA2_Hmac
SHA2_HmacHex

[Contents] [Index]

MD5 Hash Algorithm

The MD5 functions are identical in syntax and usage to their SHA-1 equivalents, except the string to receive the message digest must be set to a minimum of 32 characters (33 in a C program). See Pre-dimensioning a string.

MD5_StringHexHash
MD5_BytesHexHash
MD5_BytesHash
MD5_FileHexHash
MD5_Init
MD5_AddBytes
MD5_AddString
MD5_HexDigest
MD5_Reset
MD5_Hmac
MD5_HmacHex

[Contents] [Index]

Secure Random Number Generator (RNG)

RNG_KeyBytes
RNG_KeyHex
RNG_BytesWithPrompt
RNG_HexWithPrompt
RNG_NonceData
RNG_NonceDataHex
RNG_Test
RNG_Number (supersedes RNG_Long)
RNG_Initialize
RNG_MakeSeedFile
RNG_UpdateSeedFile

[Contents] [Index]

ZLIB data compression functions

Remember what happens to a football - you deflate it to make it smaller, and inflate it to make it bigger again. See also Data compression in cryptography.

ZLIB_Deflate
ZLIB_Inflate

[Contents] [Index]

Password-based encryption functions

PBE_Kdf2
PBE_Kdf2Hex

[Contents] [Index]

Padding functions

These functions add and remove padding according to the convention in PKCS#5, PKCS#7 and CMS - see Padding for more details. The outputs from the padding functions are always longer than the input, and the outputs from the 'Unpad' functions are always shorter. The 'Unpad' functions return a "decryption error" if the padding is not valid.

PAD_BytesBlock
PAD_UnpadBytes
PAD_HexBlock
PAD_UnpadHex

[Contents] [Index]

Conversion functions

These functions carry out conversions between bytes and hexadecimal-encoded strings, and bytes and base64-encoded strings.

CNV_BytesFromHexStr
CNV_HexStrFromBytes
CNV_HexFilter
CNV_BytesFromB64Str
CNV_B64StrFromBytes
CNV_B64Filter

[Contents] [Index]

Cyclic Redundancy Checks

These functions compute a CRC-32 checksum of some given data. They all return the value of the checksum directly.

CRC_Bytes
CRC_File
CRC_String

[Contents] [Index]

Miscellaneous Functions

These functions allow you to check the version and other module details, carry out the self-tests on demand, and securely wipe data.

API_CompileTime
API_ErrorLookup
API_LicenceType
API_ModuleName
API_PowerUpTests
API_Version
WIPE_Data
WIPE_File

[Contents] [Index]

ActiveX Interface

See ActiveX Classes and Methods.

Deprecated Functions

These still work but are no longer documented in this manual. See http://www.cryptosys.net/CryptoSysDeprecated.html.

AES_Bytes
AES_BytesMode
AES_Ecb
AES_EcbHex
AES_File
AES_FileHex
AES_Final
AES_Hex
AES_HexMode
AES_Init
AES_InitError
AES_InitHex
AES_Update
AES_UpdateHex
bf_BlockDec
bf_BlockEnc
bf_FileDec
bf_FileEnc
bf_Final
bf_Init
bf_StringDec
bf_StringEnc
BLF_Ecb
BLF_EcbHex
RAN_DESKeyGenerate
RAN_DESKeyGenHex
RAN_KeyGenerate
RAN_KeyGenHex
RAN_Long
RAN_Nonce
RAN_NonceHex
RAN_Seed
RAN_TDEAKeyGenerate
RAN_TDEAKeyGenHex
RAN_Test
RNG_KeyGenerate
RNG_KeyGenHex
RNG_Long

[Contents] [Index]

AES128_B64Mode

AES128_B64Mode encrypts or decrypts data represented as a base64 string using a specified mode. The key and initialization vector are represented as base64 strings.

VB6/VBA Syntax

Public Declare Function AES128_B64Mode Lib "diCryptoSys.dll" (ByVal strOutput As String, ByVal strInput As String, ByVal strKey As String, ByVal bEncrypt As Boolean, ByVal strMode As String, ByVal strIV As String) As Long

nRet = AES128_B64Mode(strOutput, strInput, strKey, bEncrypt, strMode, strIV)

Parameters

strOutput
[out] String of sufficient length to receive the output.
strInput
[in] String containing the input data in base64.
strKey
[in] String containing the key in base64.
bEncrypt
[in] Boolean direction flag: set as True to encrypt or False to decrypt.
strMode
[in] String specifying the confidentiality mode:
"ECB" for Electronic Codebook mode,
"CBC" for Cipher Block Chaining mode,
"CFB" for 128-bit Cipher Feedback mode,
"OFB" for Output Feedback mode, or
"CTR" for Counter mode.
strIV
[in] String containing the initialization vector (IV), if required, in base64.

C/C++ Syntax

long _stdcall AES128_B64Mode(char *strOutput, const char *strInput, const char *strKey, int bEncrypt, const char *strMode, const char *sIV);

Returns (VB6/C)

Long: If successful, the return value is 0; otherwise it returns a non-zero error code.

C# Syntax

Aes128.Decrypt Method (String, String, Mode, String, EncodingBase)
public static string Decrypt(string inputStr, string keyStr, Mode mode, string ivStr, EncodingBase encodingBase);
Aes128.Encrypt Method (String, String, Mode, String, EncodingBase)
public static string Encrypt(string inputStr, string keyStr, Mode mode, string ivStr, EncodingBase encodingBase);

VB.NET/VB200x Syntax

Aes128.Decrypt Method (String, String, Mode, String, EncodingBase)
Public Shared Function Decrypt(ByVal inputStr As String, ByVal keyStr As String, ByVal mode As Mode, ByVal ivStr As String, ByVal encodingBase As EncodingBase) As String
Aes128.Encrypt Method (String, String, Mode, String, EncodingBase)
Public Shared Function Encrypt(ByVal inputStr As String, ByVal keyStr As String, ByVal mode As Mode, ByVal ivStr As String, ByVal encodingBase As EncodingBase) As String

Returns (C#/VB.NET/VB200x)

Encrypted/decrypted data in encoded string or empty string on error.

Refer to the .NET Help File for more details.

Remarks

The length of the input string strInput must represent a multiple of the block size (16 bytes) when decoded. If not, an error will be returned. The initialization vector string strIV must represent exactly 16 bytes unless strMode is ECB, in which case strIV is ignored (use ""). The key strKey must also represent exactly 16 bytes, the required key length. The output string strOutput must be set up with at least the same number of characters as the input string before calling. The variables strOutput and strInput should be different.

Example

This example is the same data as for AES128_HexMode, except the data is in base64 format.
Dim nRet As Long
Dim strOutput As String
Dim strInput As String
Dim strKey As String
Dim strIV As String
Dim bEncrypt As Boolean
Dim sCorrect As String

' Case #4: Encrypting 64 bytes (4 blocks) using AES-CBC with 128-bit key
' Key       : 0x56e47a38c5598974bc46903dba290349
strKey = "VuR6OMVZiXS8RpA9uikDSQ=="
' IV        : 0x8ce82eefbea0da3c44699ed7db51b7d9
strIV = "jOgu776g2jxEaZ7X21G32Q=="
' Plaintext : 0xa0a1a2a3a4a5a6a7a8a9aaabacadaeaf
'               b0b1b2b3b4b5b6b7b8b9babbbcbdbebf
'               c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
'               d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
strInput = "oKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/" _
& "AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3w=="
' Ciphertext: 0xc30e32ffedc0774e6aff6af0869f71aa
'               0f3af07a9a31a9c684db207eb0ef8e4e
'               35907aa632c3ffdf868bb7b29d3d46ad
'               83ce9f9a102ee99d49a53e87f4c3da55
sCorrect = "ww4y/+3Ad05q/2rwhp9xqg868HqaManGhNsgfrDvjk" _
& "41kHqmMsP/34aLt7KdPUatg86fmhAu6Z1JpT6H9MPaVQ=="

' Set strOutput to be same length as strInput
strOutput = String(Len(strInput), " ")

Debug.Print "KY="; strKey
Debug.Print "IV="; strIV
Debug.Print "PT="; strInput
nRet = AES128_B64Mode(strOutput, strInput, strKey, ENCRYPT, "CBC", strIV)
Debug.Print "CT="; strOutput; nRet
Debug.Print "OK="; sCorrect

strInput = strOutput
nRet = AES128_B64Mode(strOutput, strInput, strKey, DECRYPT, "CBC", strIV)
Debug.Print "P'="; strOutput; nRet
This should result in output as follows:
KY=VuR6OMVZiXS8RpA9uikDSQ==
IV=jOgu776g2jxEaZ7X21G32Q==
PT=oKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/
AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3w==
CT=ww4y/+3Ad05q/2rwhp9xqg868HqaManGhNsgfrDvjk
41kHqmMsP/34aLt7KdPUatg86fmhAu6Z1JpT6H9MPaVQ== 0 
OK=ww4y/+3Ad05q/2rwhp9xqg868HqaManGhNsgfrDvjk
41kHqmMsP/34aLt7KdPUatg86fmhAu6Z1JpT6H9MPaVQ==
P'=oKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/
AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3w== 0 

See Also

AES128_HexMode AES128_BytesMode

[Contents] [Index]

AES128_Bytes

AES128_Bytes encrypts or decrypts an array of Bytes in one step in Electronic Codebook (EBC) mode.

VB6/VBA Syntax

Public Declare Function AES128_Bytes Lib "diCryptoSys.dll" (ByRef abOutput As Byte, ByRef abData As Byte, ByVal nDataLen As Long, ByRef abKey As Byte, ByVal bEncrypt As Boolean) As Long

nRet = AES128_Bytes(abOutput(0), abData(0), nDataLen, abKey(0), bEncrypt)

Parameters

abOutput
[out] Byte array of sufficient length to receive the output.
abData
[in] Byte array containing the input data.
nDataLen
[in] Long equal to length of the input data in bytes.
abKey
[in] Byte array containing the key.
bEncrypt
[in] Boolean direction flag: set as True to encrypt or False to decrypt.

C/C++ Syntax

long _stdcall AES128_Bytes(unsigned char *output, const unsigned char *input, long nbytes, const unsigned char *key, int bEncrypt);

Returns (VB6/C)

Long: If successful, the return value is 0; otherwise it returns a non-zero error code.

Remarks

The input array abData must be an exact multiple of 16 bytes long. If not, an error code will be returned. The key array abKey() must be exactly 16 bytes long. The output array abOutput must be at least as long as the input array. abOutput and abData may be the same. Note the (0) after the byte array variables.

This function is equivalent to

nRet = AES128_BytesMode(abOutput(0), abData(0), nDataLen, abKey(0), bEncrypt, "ECB", 0)

Example

    Dim nRet As Long
    Dim abBlock() As Byte
    Dim abKey() As Byte
    Dim abPlain() As Byte
    Dim abCipher() As Byte
    Dim nBytes As Long
    
    'FIPS-197
    'C.1 AES-128 (Nk=4, Nr=10)
    'PLAINTEXT: 00112233445566778899aabbccddeeff
    'KEY: 000102030405060708090a0b0c0d0e0f
    
    ' Convert input to bytes
    abKey = cnvBytesFromHexStr("000102030405060708090a0b0c0d0e0f")
    abPlain = cnvBytesFromHexStr("00112233445566778899aabbccddeeff")
    abCipher = cnvBytesFromHexStr("69c4e0d86a7b0430d8cdb78070b4c55a")
    
    abBlock = abPlain
    nBytes = UBound(abBlock) - LBound(abBlock) + 1
    Debug.Print "KY="; cnvHexStrFromBytes(abKey)
    Debug.Print "PT="; cnvHexStrFromBytes(abBlock)
    ' Encrypt in one-off process
    nRet = AES128_Bytes(abBlock(0), abBlock(0), nBytes, abKey(0), ENCRYPT)
    Debug.Print "CT="; cnvHexStrFromBytes(abBlock)
    Debug.Print "OK="; cnvHexStrFromBytes(abCipher)
    Debug.Assert (StrConv(abBlock, vbUnicode) = StrConv(abCipher, vbUnicode))
    
    ' Now decrypt back to plain text
    nRet = AES128_Bytes(abBlock(0), abBlock(0), nBytes, abKey(0), DECRYPT)
    Debug.Print "P'="; cnvHexStrFromBytes(abBlock)
    Debug.Assert (StrConv(abBlock, vbUnicode) = StrConv(abPlain, vbUnicode))
This should result in output as follows:
KY=000102030405060708090A0B0C0D0E0F
PT=00112233445566778899AABBCCDDEEFF
CT=69C4E0D86A7B0430D8CDB78070B4C55A
OK=69C4E0D86A7B0430D8CDB78070B4C55A
P'=00112233445566778899AABBCCDDEEFF

See Also

AES128_BytesMode

[Contents] [Index]

AES128_BytesMode

AES128_BytesMode encrypts or decrypts an array of Bytes using a specified mode. The key and IV data are in byte arrays.

VB6/VBA Syntax

Public Declare Function AES128_BytesMode Lib "diCryptoSys" (ByRef abOutput As Byte, ByRef abData As Byte, ByVal nDataLen As Long, ByRef abKey As Byte, ByVal bEncrypt As Boolean, ByVal strMode As String, ByRef abInitV As Byte) As Long

nRet = AES128_Bytes(abOutput(0), abData(0), nDataLen, abKey(0), bEncrypt, strMode, abInitV(0))

Parameters

abOutput
[out] Byte array of sufficient length to receive the output.
abData
[in] Byte array containing the input data.
nDataLen
[in] Long equal to length of the input data in bytes.
abKey
[in] Byte array containing the key.
bEncrypt
[in] Boolean direction flag: set as True to encrypt or False to decrypt.
strMode
[in] String specifying the confidentiality mode:
"ECB" for Electronic Codebook mode,
"CBC" for Cipher Block Chaining mode,
"CFB" for 128-bit Cipher Feedback mode,
"OFB" for Output Feedback mode, or
"CTR" for Counter mode.
abInitV
[in] Byte containing the initialization vector (IV), or zero (0) for ECB mode.

C/C++ Syntax

long _stdcall AES128_BytesMode(unsigned char *output, const unsigned char *input, long nbytes, const unsigned char *key, int bEncrypt, const char *lpszMode, const unsigned char *iv);

Returns (VB6/C)

Long: If successful, the return value is 0; otherwise it returns a non-zero error code.

C# Syntax

Aes128.Decrypt Method (Byte[], Byte[], Mode, Byte[])
public static byte[] Decrypt(byte[] input, byte[] key, Mode mode, byte[] iv);
Aes128.Encrypt Method (Byte[], Byte[], Mode, Byte[])
public static byte[] Encrypt(byte[] input, byte[] key, Mode mode, byte[] iv);

VB.NET/VB200x Syntax

Aes128.Decrypt Method (Byte[], Byte[], Mode, Byte[])
Public Shared Function Decrypt(ByVal input() As Byte, ByVal key() As Byte, ByVal mode As Mode, ByVal iv() As Byte) As Byte()
Aes128.Encrypt Method (Byte[], Byte[], Mode, Byte[])
Public Shared Function Encrypt(ByVal input() As Byte, ByVal key() As Byte, ByVal mode As Mode, ByVal iv() As Byte) As Byte()

Returns (C#/VB.NET/VB200x)

Encrypted/decrypted data in byte array or empty array on error.

Refer to the .NET Help File for more details.

Remarks

The input array abData must be an exact multiple of 16 bytes long. If not, an error code will be returned. The key array abKey() must be exactly 16 bytes long. The initialization vector abInitV() must be exactly the block size of 16 bytes long, except for ECB mode, where it is ignored (use 0). The output array abOutput must be at least as long as the input array. abOutput and abData may be the same. Note the (0) after the byte array variables.

Example

    Dim nRet As Long
    Dim strOutput As String
    Dim strInput As String
    Dim sCorrect As String
    Dim abKey()  As Byte
    Dim abInitV() As Byte
    Dim abResult() As Byte
    Dim abData() As Byte
    Dim nDataLen As Long

    ' Set up input in byte arrays
    strInput = "Now is the time for all good men"
    sCorrect = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E177"
    abKey = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687")
    abInitV = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210")
    abData = StrConv(strInput, vbFromUnicode)
    nDataLen = UBound(abData) - LBound(abData) + 1
    
    ' Pre-dimension output array
    ReDim abResult(nDataLen - 1)
    
    Debug.Print "KY="; cnvHexStrFromBytes(abKey)
    Debug.Print "IV="; cnvHexStrFromBytes(abInitV)
    Debug.Print "PT="; cnvHexStrFromBytes(abData)
    ' Encrypt in one-off process
    nRet = AES128_BytesMode(abResult(0), abData(0), nDataLen, abKey(0), _
        ENCRYPT, "CBC", abInitV(0))
    Debug.Print "CT="; cnvHexStrFromBytes(abResult)
    Debug.Print "OK="; sCorrect

    ' Now decrypt back
    nRet = AES128_BytesMode(abData(0), abResult(0), nDataLen, abKey(0), _
        DECRYPT, "CBC", abInitV(0))
    strOutput = StrConv(abData(), vbUnicode)
    Debug.Print "P'="; strOutput
    
    ' Check
    Debug.Assert (strOutput = strInput)
This should result in output as follows:
KY=0123456789ABCDEFF0E1D2C3B4A59687
IV=FEDCBA9876543210FEDCBA9876543210
PT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E
CT=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E177
OK=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E177
P'=Now is the time for all good men

See Also

AES128_Bytes

[Contents] [Index]

AES128_File

AES128_File encrypts or decrypts a file using a specified mode. The key and initialization vector are passed as arrays of bytes.

VB6/VBA Syntax

Public Declare Function AES128_File Lib "diCryptoSys.dll" (ByVal strFileOut As String, ByVal strFileIn As String, ByRef abKey As Byte, ByVal bEncrypt As Boolean, ByVal strMode As String, ByRef abInitV As Byte) As Long

nRet = AES128_File(strFileOut, strFileIn, abKey(0), bEncrypt, strMode, abInitV(0))

Parameters

strFileOut
[in] String with the full path name of the output file to be created.
strFileIn
[in] String with the full path name of the input file to be processed.
abKey
[in] Byte array containing the key.
bEncrypt
[in] Boolean direction flag: set as True to encrypt or False to decrypt.
strMode
[in] String specifying the confidentiality mode:
"ECB" for Electronic Codebook mode,
"CBC" for Cipher Block Chaining mode,