Home

About Us

Books

Free Stuff

Oh, So That's How It Works!

Fellow Magicians

Useful Links



WizardWrx Logo

Free Stuff
Some Fun and Some Serious

 

Overview

Name:

P6CryptAES

Synopsis:

Encrypt and decrypt strings of up to 65,520 bytes using the Advanced Encryption Standard (Rijendael) block cipher algorithm.

Version:

6.0.0.3

Author:

David Gray of Simple Soft Services, Inc., d/b/a WizardWrx, North Richland Hills, Texas, USA.

Copyright:

© 2005-2007, Simple Soft Services, Inc., d/b/a WizardWrx, North Richland Hills, Texas, USA. All rights reserved world wide.

Description:

P6CryptAES is a dynamic link library (DLL) for Microsoft Windows programmers. The library implements encryption and decryption of strings of up to P6CRYPT_MAX_PT, or 65,520 bytes, using the Advanced Encryption Standard (Rijendael) algorithm, with a single function call.

Cipher strength is further enhanced by using Cipher Block Chaining Mode, as described in RFC 2405 and concisely defined in Cipher Block Chaining (CBC) and in a glossary on the Microsoft MSDN Web site.

This library is a vast improvement over the standard implementations of block ciphers (and stream ciphers, for that matter), which require the programmer to write a loop to process the many short blocks into which the text must be broken. Since any program that uses the AES (Rijndael) algorithm must implement the same loop, and I had several such programs in the works, and a prospect of many more, I wanted to write the loop once and for all, and make it as efficient as possible, short of implementing it in Assembly. I was further motivation by my desire to teach myself the C programming language, so that I can undertake projects that require a working knowledge of, and some programming in, that language, and eventually C++.

I am indebted to Dr. Brian Gladman for both his implementation of the AES algorithm, which I used without modification, and for the working example program, aesxam.c, upon which I based the single call encryption and decryption functions in the DLL.

Credit is also gratefully extended to Daryl Buckman, US Army Corps of Engineers, Omaha, Nebraska, USA, Information Management Office, Computer Systems & Communications Branch, for identifying and reporting a bug in function AESDecryptFromFile_P6C() that could have led to a run-on string, which could, theoretically, be exploited, through underlying C function DecryptFromFile_P6C(), to execute arbitrary code. The error was corrected on 2006/06/28, in version 6, 0, 0, 2 (extender version 41007).

How to Use The Library

The DLL exposes six new functions, in addition to the required DLLMain and functions aes_dec_blk, aes_dec_key, aes_enc_blk, and aes_enc_key, all of which were written by Dr. Gladman and included without modification. The table below sets forth the six new functions and their uses.

Function Name

Description

EncryptString_P6C

Encrypt a text string of up to up to 65,520 bytes.

DecryptString_P6C

Decrypt a text string of up to up to 65,535 bytes.

EncryptFile_P6C

Encrypt the contents of a file of arbitrary size, and store the ciphertext in another file.

DecryptFile_P6C

Decrypt the contents of a file of arbitrary size and store the plaintext in another file.

EncryptToFile_P6C

Encrypt the contents of a string of arbitrary length, and store the ciphertext in a buffer.

DecryptFromFile_P6C

Decrypt the contents of a file of arbitrary size and store the plaintext in a buffer.

EncryptString_VB_P6C

This is an alternate entry point for EncryptString_P6C that returns a BSTR. This function is intended to be called from Visual Basic or VBA.

DecryptString_VB_P6C

This is an alternate entry point for DecryptString_P6C that returns a BSTR. This function is intended to be called from Visual Basic or VBA.

DecryptFromFile_VB_P6C

Encrypt the contents of a string of arbitrary length, and store the ciphertext in a buffer.

DecryptFromFile_P6C

Decrypt the contents of a file of arbitrary size and store the plaintext in a buffer.

CryptStatus_P6C

Return status information about the last call to any of the four cryptography functions. A positive value indicates the number of bytes returned by a successful call to the function. A negative value indicates one of several error conditions. A zero indicates that no cryptography functions have yet been called.

ZeroMemory_P6C

Clear a memory block of up to 65,535 bytes. Though not strictly required in order to use the encryption and decryption functions, this provides easy access to a general purpose function from the standard C run-time library that is handy to have available for any code that does cryptography, or processes sensitive data.

For documentation and other information about the four functions written by Dr. Gladman, please see his AES page. If you insist on calling these cryptographic functions directly, please feel free to do so. However, you are on your own, though you are welcome to use his C sources as references. Except for adding clone functions to process disk files, I have coded the last direct call to them that I intend to write.

Declarations

The declarations for the ten functions, which are defined in C header P6CryptAES.h, are as follows.

     LPTSTR APIENTRY EncryptString_P6C (    // Encrypt string, returning pointer to encrypted data
        LPCVOID plpstrPlaintext ,           // Pointer to invariant plaintext string
        LPCTSTR plpszPassword               // Pointer to invariant password string
    )

    LPTSTR APIENTRY DecryptString_P6C (     // Derypt string, returning pointer to decrypted data
        LPCVOID plpCipherText ,             // Pointer to invariant encrypted textstring
        LPCTSTR plpszPassword ,             // Pointer to invariant password string
        unsigned int puintCTxtLen           // Length, in bytes, of data to which 
                                            // plspstrCipherText points
    )

    BSTR APIENTRY EncryptString_VB_P6C (    // Encrypt string, returning BSTR containing encrypted data
        LPCVOID plpstrPlaintext ,           // Pointer to invariant plaintext string
        LPCTSTR plpszPassword               // Pointer to invariant password string
    )

    BSTR APIENTRY DecryptString_VB_P6C (    // Decrypt string, returning BSTR containing decrypted data
        LPCVOID plpCipherText ,             // Pointer to invariant encrypted text string
        LPCTSTR plpszPassword ,             // Pointer to invariant password string
        unsigned int puintCTxtLen           // Length, in bytes, of data to which 
                                            // plspstrCipherText points
    )

    long APIENTRY EncryptFile_P6C (         // Encrypt file, storing ciphertext in another file
        LPCTSTR ,                           // Pointer to invariant string containing name of input file
        LPCTSTR ,                           // Pointer to invariant string containing name of output file
        LPCTSTR                             // Pointer to invariant password string
    ) ;

    long APIENTRY DecryptFile_P6C (         // Decrypt file, storing plaintext in another file
        LPCTSTR ,                           // Pointer to invariant string containing name of input file
        LPCTSTR ,                           // Pointer to invariant string containing name of output file
        LPCTSTR                             // Pointer to invariant password string
    ) ;

    long APIENTRY EncryptToFile_P6C (       // Encrypt string, storing ciphertext in a file
        LPVOID ,                            // Pointer to invariant string containing name of input file
        LPCTSTR ,                           // Pointer to invariant string containing name of output file
        LPCTSTR ,                           // Pointer to invariant password string
        long                                // Length, in bytes, of data to which plspstrPlainText points
    ) ;

    LPVOID APIENTRY DecryptFromFile_P6C (   // Decrypt file, storing plaintext in a buffer
        LPCTSTR ,                           // Pointer to invariant string containing name of input file 
        LPCTSTR                             // Pointer to invariant password string
    ) ;

	BSTR APIENTRY DecryptFromFile_VB_P6C (  // Decrypt file, storing plaintext in a buffer
        LPCTSTR ,                           // Pointer to invariant string containing name of input file 
        LPCTSTR                             // Pointer to invariant password string
    ) ;

    long APIENTRY CryptStatus_P6C ( )

    void APIENTRY ZeroMemory_P6C (          // Utility function to clear a block of memory
        LPVOID plpMemoryBlock ,             // Pointer to memory block.
        WORD plngBlockSize                  // Size, in bytes, of memory block.
    )

The three functions with names that end in _VB_P6C, all of which return a BSTR, are intended for use with Microsoft Visual Basic 6.0 (VB) and Visual Basic for Applications (VBA) applications. The three functions are wrappers for the like named functions with names that end only in _P6C.

In addition to the standard WINAPI (C/C++) interface, this library exposes a WinBatch (Windows Interface Language) interface, which is fully documented in P6CRYPTAES.HLP, which is included in the binary distribution of this package.

Arguments

The table below defines the arguments, which are the same for all four cryptography functions.

C Type

VB/VBA Type

Name

Description

LPCVOID/LPTSTR (Note 1)

Any (Note 2)

plpstrPlaintext

This is a long pointer to a buffer, usually a string, of up to 65,520 bytes that holds the input text.

  • On input to EncryptString_P6C, the string may be a constant value of up to 65,520 bytes.
  • Before you call either of the cryptography functions in the C interface (DecryptString_P6C and EncryptString_P6C), a second time, you must copy the output returned by the previous call into a local variable - that is - a variable that your program owns. The reason for this is that all the cryptography functions share the same private memory block, which they use as their output buffer. Consequently, each call overwrites the data returned by the previous call to the library.
  • The cryptography functions in the VB/VBA interface (DecryptString_VB_P6C and EncryptString_VB_P6C) are immune to this issue because they return a BSTR, which becomes the property of the caller.

LPCTSTR (Note 1)

String

plpszPassword

This is a long pointer to a string that holds a password of up to 32 characters. Additional characters, if present, cause an error, as does a null password.

unsigned int

Integer (Note 3)

puintCTxtLen

This is the number of bytes of text passed to the cryptography functions that take a string or buffer as input.

  • This value cannot be derived using functions that understand only null terminated strings, such as the standard strlen functions in C, because the ciphertext may contain embedded nulls. Use the value returned by the original call to EncryptString_P6C or EncryptString_VB_P6C or some other safe method to compute the number of bytes being passed.
  • Because Basic Strings (BSTRs) can contain embedded nulls, the built-in VB/VBA Len function computes the correct length of the returned string.

Notes

1

The input text is declared as type LPCVOID and the password is of type LPTCSTR. The C in both type declarations denotes that the inputs are constants. This causes the C compiler to warn about any code in functions that accept such arguments that tries to change the values of these arguments, even if they are passed by reference (which they are not). Since the code in this library compiled completely clean, you can assume that this library will never change any data that you pass to it.

1

Beware of the Any keyword in these declarations. Like its C equivalents, LPVOID and LPCVOID, they disable type checking and increase the risk of unchecked buffer overflows in your code. Use the Len function to calculate the value of the third argument immediately before you call these functions. Better yet, code the third argument as Len (FirstArgument) to be certain that the value passed to the function is always correct.

2

Since VBA supports only signed integers, yet some Windows API functions expect and return unsigned integers, Microsoft developed a kludge that you can (and must) wedge between your VBA code and any Windows API or other C function that expects or returns an unsigned integer. Because the third argument to all four cryptography functions is, and must be, an unsigned integer, we employed it in the sample code that demonstrates the VB/VBA interface. Although this module needs only one of the four, we included all of them in module mUIntConversions_P6C.BAS, which is included with this package. For further information, please see How To Convert Between Signed and Unsigned Numbers on the Microsoft TechNet Web site.

Return Values

Function

C Type

VB/VBA Type

Description

EncryptString_P6C

LPTSTR

No Equivalent

This is a long pointer to a memory block of up to 65,535 bytes that holds the encrypted text. (Note 1)

DecryptString_P6C

LPTSTR

No Equivalent

This is a long pointer to a string of up to 65,520 bytes that holds the decrypted text. (Note 1)

EncryptString_VB_P6C

BSTR

String

This is a long pointer to a memory block of up to 65,535 bytes that holds the encrypted text. (Note 2)

DecryptString_VB_P6C

BSTR

String

This is a long pointer to a string of up to 65,520 bytes that holds the decrypted text. (Note 2)

Notes

1

The LPTSTR returned by these functions points to a private memory block that the library owns and reuses on subsequent calls. Before you call any other cryptography function in this library, you must copy the data into memory that your program owns. Otherwise, it will be permanently lost.

1

The BSTR returned by these functions points to a cached memory block that your program inherits when the function returns.

You must always call CryptStatus_P6C, which takes no arguments, to get the size of the block returned if the function succeeded, or why the function failed. Failure is indicated by a return value of NULL (vbNullString if calling from VB or VBA) and a negative value returned by CryptStatus_P6C, as shown below.

C header file P6CryptAES.h, which is included in this package, defines the error codes reported by the library.

Examples in the C Programming Language

Both of the following examples are taken from P6CryptAES_TestHarness.c, which is included in this package in source and binary form.

Example 1 - EncryptString_P6C

    LPVOID          szCipherText = NULL ;       // Pointer to buffer to hold ciphertext
    LPVOID          szPlainText = NULL ;        // Pointer to buffer to hold plaintext
    FILE            *utpOutFile = 0 ;           // File I/O control structure
    long            dwBufSize = 0 ;             // Working buffer needs to be 1 byte longer.
    unsigned int    uintTextLen = 0 ;

    // Encrypt the test string.

    szCipherText = EncryptString_P6C ( pszPlainText , pszPassword ) ;
    mlngCryptStatus = CryptStatus_P6C ( ) ;
    if ( szCipherText != NULL ) {
        uintTextLen = mlngCryptStatus ;          // Unless return is NULL, this is number of BYTES written.
        dwBufSize = uintTextLen + 1 ;            // Local buffer needs room for the trailing null.
        printf ( "     Encrypted output string = %s\n", szCipherText ) ;

        if ( !( utpOutFile = fopen ( pszTestCipherTextFQFN , "wb" ) ) ) 
        {
            printf ( "     Unable to open OUTPUT file %s\n", pszTestCipherTextFQFN ) ;
            return OPEN_ERROR ;
        }
        if ( fwrite ( szCipherText ,
                      1 ,
                      uintTextLen ,
                      utpOutFile ) != uintTextLen ) 
        {
            printf ( "     Unable to write ciphertext to output file %s\n", pszTestCipherTextFQFN ) ;
            return WRITE_ERROR ;
        }

        if ( utpOutFile ) {
            fclose ( utpOutFile ) ;
        }
        printf ( "     Test Case written to output file %s\n", pszTestCipherTextFQFN ) ;

        // Copy the ciphertext into a local buffer, which we must pass to DecryptString_P6C,
        // so that the library can reuse the buffer. (Its first action is to erase its contents.

        if ( mlngBufSize ) {                    // If a buffer was allocated for a previous call,
            if ( dwBufSize > mlngBufSize ) {    // see if it's already big enough.
                mlpOutBuf = realloc ( mlpOutBuf , dwBufSize ) ;
            }
        } else {                                // Otherwise, do a first time allocation.
            mlpOutBuf = malloc ( dwBufSize ) ;
        }
        if ( mlpOutBuf == NULL ) {              // Make sure that Malloc gave us a buffer.
            return P6CRYPT_MALLOC_ERROR ;
        } else {
            if ( dwBufSize > mlngBufSize ) {    // If we enlarged the buffer, 
                mlngBufSize = dwBufSize ;       // record its new size.
            }
        }
        memset ( mlpOutBuf , 0 , mlngBufSize ) ;// ALWAYS Zero fill the ENTIRE buffer.
        memcpy ( mlpOutBuf ,                    // Copy ciphertext into local buffer.
                  szCipherText ,                // Remember that memcpy and its cousins
                  uintTextLen ) ;               // use reverse Polish notation.
    } else {
        printf ( "Library function EncryptString_P6C failed\n" ) ;
        mlngCryptStatus = CryptStatus_P6C ( ) ;
        printf ( "Return from CryptStatus_P6C = %d\n", mlngCryptStatus ) ;
    }

Example 2 - DecryptString_P6C

    LPVOID          szCipherText = NULL ;       // Pointer to buffer to hold ciphertext
    LPVOID          szPlainText = NULL ;        // Pointer to buffer to hold plaintext
    FILE            *utpOutFile = 0 ;           // File I/O control structure
    long            dwBufSize = 0 ;             // Working buffer needs to be 1 byte longer.
    unsigned int    uintTextLen = 0 ;

    szPlainText = DecryptString_P6C ( mlpOutBuf , pszPassword , uintTextLen ) ;
    mlngCryptStatus = CryptStatus_P6C ( ) ;
    if ( szPlainText != NULL )
    {
        printf ( "     Decrypted output string = %s\n     Reported string length = %d\n", szPlainText , mlngCryptStatus ) ;

        // Copy the plaintext into a local buffer if we intend to call either EncryptString_P6C
        // or DecryptString_P6C again. Otherwise, the next call will destroy our only copy.
        
        if ( mlngBufSize ) {                    // If a buffer was allocated for a previous call,
            if ( dwBufSize > mlngBufSize ) {    // see if it's already big enough.
                mlpOutBuf = realloc ( mlpOutBuf , dwBufSize ) ;
            }
        } else {                                // Otherwise, do a first time allocation.
            mlpOutBuf = malloc ( dwBufSize ) ;
        }
        if ( mlpOutBuf == NULL ) {              // Make sure that Malloc gave us a buffer.
            mlngCryptStatus = P6CRYPT_OB_TOO_SHORT ;
            return NULL ;
        } else {
            if ( dwBufSize > mlngBufSize ) {    // If we enlarged the buffer, 
                mlngBufSize = dwBufSize ;       // record its new size.
            }
            memset ( mlpOutBuf , '\0' , dwBufSize ) ;
        }
        strncpy ( mlpOutBuf ,                   // Copy ciphertext into local buffer.
                  szCipherText ,                // Remember that strncpy is reverse Polish,
                  lngTextLen ) ;                // just like most Assembler instructions.
        }
    } else {
        printf ( "Library function EncryptString_P6C failed\n" ) ;
        mlngCryptStatus = CryptStatus_P6C ( ) ;
        printf ( "Return from CryptStatus_P6C = %d\n", mlngCryptStatus ) ;
    }

The above example illustrates the correct way to preserve data following a call to either of the cryptography functions. Both examples are taken from P6CryptAES_TestHarness.c, the test program that I wrote and used to test the library.

Note the use of strncpy to copy the data into the caller's address space. This is the recommended method, as it is immune to run-on string errors that could lead to memory corruption.

You can avoid copying the returned data into your own address space so long as no other function in P6CryptAES.dll is called until you are completely finished using the data.

Important: I strongly urge you to use the ZeroMemory_P6C function, in this library, RtlZeroMemory, in the Windows API, or memset, in the C Runtime Library, to clear all buffers, especially those containing passwords, as soon as possible. If you are calling the library from VB or VBA code, your best options are ZeroMemory_P6C and RtlZeroMemory.

Examples in the Visual Basic Programming Language

Example 3 - EncryptString_P6C

    Private Declare Function EncryptString_P6C _
        Lib "F:\_P6C_DLLs\P6CryptAES\P6CryptAES_TestHarness\Release\P6CryptAES.dll" _
        Alias "EncryptString_VB_P6C" _
        (ByVal lpstrPlaintext As Any, _
        ByVal lpszPassword As String, _
        ByVal intBufSize As Integer) _
                As String

    Private Declare Function CryptStatus_P6C _
        Lib "F:\_P6C_DLLs\P6CryptAES\P6CryptAES_TestHarness\Release\P6CryptAES.dll" _
        () As Long

    Dim hOutFile as Integer

    Dim lngCryptResult as Long

    Dim pszTestCipherTextFQFN as String
    Dim strCipherText as String
    Dim strOutputText as String

    strCipherText = EncryptString_P6C(pstrPlainText, pszPassword,UnsignedToInteger(Len(pstrPlainText)))
    lngCryptResult = CryptStatus_P6C()            ' Get length of ciphertext block or error code.
    If strCipherText <> vbNullString And lngCryptResult > 0 Then
        Debug.Print "     Writing encrypted output string of " & lngCryptResult & " bytes to file"
        hOutFile = FreeFile
        Open pszTestCipherTextFQFN For Binary Access Write As #hOutFile
        strOutputText = Left(strCipherText, lngCryptResult)
        Debug.Print "     Length of strOutputText = " & Len(strOutputText)
        Put #hOutFile, , strOutputText
        Close hOutFile
        Debug.Print "     Test Case written to output file " & pszTestCipherTextFQFN
    Else
        Debug.Print "Test function DoTestCase returned error code: " & lngResult
    End If

Example 4 - DecryptString_P6C

    Private Declare Function DecryptString_P6C _
        Lib "F:\_P6C_DLLs\P6CryptAES\P6CryptAES_TestHarness\Release\P6CryptAES.dll" _
        Alias "DecryptString_VB_P6C" _
        (ByVal lspstrCipherText As Any, _
        ByVal lpszPassword As String, _
        ByVal intBufSize As Integer) _
                As String

    Private Declare Function CryptStatus_P6C _
        Lib "F:\_P6C_DLLs\P6CryptAES\P6CryptAES_TestHarness\Release\P6CryptAES.dll" _
        () As Long
    Dim lngCryptResult as Long
    Dim lngPlainTextLen as Long

    Dim strPlainText as String
    Dim strOutputText as String

    strPlainText = DecryptString_P6C(strCipherText, _
                                     pszPassword, _
                                     UnsignedToInteger(lngCryptResult))
    lngCryptResult = CryptStatus_P6C()          ' Get length of ciphertext block or error code.
    If strPlainText <> vbNullString And lngCryptResult > 0 Then
        lngPlainTextLen = CryptStatus_P6C()     ' Get length of plaintext block.
        strOutputText = Left(strPlainText, lngPlainTextLen)
        Debug.Print "Decrypted output string = " & strOutputText
    Else
        Debug.Print "Test function DoTestCase returned error code: " & lngResult
    End If

In Example 3 and Example 4 above, note the use of the Alias keyword in the declarations of the two cryptography functions. These are the actual names of the entry points that return Visual Basic strings. The other two functions will not work from Visual Basic or VBA.

Note also the use of the UnsignedToInteger function, used in the third argument to both cryptography functions to translate the signed integers used by VBA into unsigned integers required by the library functions.

Examples in the WInBatch/Windows Interface Language (WIL) Programming Language

Example 5 - EncryptString_P6C and DEcryptString_P6C

    P6CryptAESlibFQFN = StrCat ( FilePath ( IntControl ( 1004 , 0 , 0 , 0 , 0 ) ) , 'P6CryptAES.dll' )
    hP6CryptAES = DllLoad ( P6CryptAESlibFQFN )
    InternalActionCode = Char2Num ( StrUpper ( pAction ) )     ; Translate to drive SWITCH.
    switch InternalActionCode
        case 68
            if InputType == 64
                rTextOut = DllCall ( hP6CryptAES , lpstr:'DecryptString_P6C' , lpbinary:pTextIn , lpstr:PW , long:dwBufSize )
            else
                rTextOut = DllCall ( hP6CryptAES , lpstr:'DecryptString_P6C' , lpstr:pTextIn , lpstr:PW , long:dwBufSize )
            endif
            break
        case 69
            if InputType == 64
                rTextOut = DllCall ( hP6CryptAES , lpstr:'EncryptString_P6C' , lpbinary:pTextIn , lpstr:PW )
            else
                rTextOut = DllCall ( hP6CryptAES , lpstr:'EncryptString_P6C' , lpstr:pTextIn , lpstr:PW )
            endif
            break
        case InternalActionCode
            rTextOut = int ( -31 )                             ; Invalid pAction value.
            goto CryptAES_P6C_End
    endswitch
    dwResult = DllCall ( hP6CryptAES , long:'CryptStatus_P6C' )
    if dwResult < 0
        rTextOut = int ( dwResult * MINUS_ONE_P6C )            ; Return NEGATIVE of returned by DLL.
    endif

The above example is taken verbatim from User Defined Function CryptAES_P6C, which is included in this package as CryptAES_P6C.WIL. You may use the library by including that file in your source, then calling the function as follows.

    TextOut = CryptAES_P6C ( 'E' , TextIn , Password )
    if VarType ( TextOut ) == VARTYPE_INTEEGER
        LogMsg = StrCat ( 'Function CryptAES_P6C FAILED.' , @lf ,'Error code = ' , TextOut )
        Dummy = LogMsg_P6C ( LogMsg , LOGMSG_ABORT_P6C , aParm_P6C )
        goto MainEnd
    endif
    TextSize = StrLen ( TextOut )

Decryption is handled in much the same way. The above examples are taken from my demonstration and utility program, P6ClipCrypt, available here.

Why Did I Need My Own Cryptography Library?

Following the disclosure of serious flaws in the RC4 encryption employed widely by Microsoft in its Office products, we became generally concerned about the trustworthiness of the Microsoft Cryptographic Services that are included with Microsoft Windows. Rather than risk using them in programs such as demonstration and utility program P6ClipCrypt available here, I chose to write my own cryptography library.

Since common cryptographic algorithms such as Advanced Encryption Standard (Rijendael), RC4, Blowfish, and Twofish, among others, are readily available in source code form, this seemed to be a very feasible task. Though the work took several times as long as I anticipated, primarily due to my inexperience with writing code in the C programming language, my careful testing and use of a regression harness gives me the confidence to deploy this library in production code upon which others may depend to hide their secrets.

Library P6CryptAES.dll, is based upon work published by Dr. Brian Gladman, to whom I am indebted not only for a working, tested, and well regarded implementation of the algorithm, but for the code upon which I modeled the main library functions. You can learn more about his version of the AES (Rijendael) algorithm here.

This library is published and licensed under the GNU Lesser General Public License.

Contents of This Package

The table below lists all the files that come in this package.

File Name

Purpose and Other Notes

aesxam.c

This is the C source code of demonstration program aesxam.exe, which I used as a model for the library functions and to test the library. This code came from here

aesxam.exe

This is the compiled and linked code of demonstration program aesxam.exe, which I used as a model for the library functions and to test the library. This code came from here

CryptAES_P6C.WIL

This is the WinBatch Include file that contains User Defined Function CryptAES_P6C, from which Example 5 above was taken.

mUIntConversions_P6C.BAS

This module contains the four VBA functions for converting signed integers to and from unsigned integers. For additional information, please see the notes above and How To Convert Between Signed and Unsigned Numbers on the Microsoft TechNet Web site.

mWin32API_P6C.BAS

This is a portion of a standard library of Windows API wrapper functions that I use in my VB and VBA code. I use it to run the output from the VBA demonstration program through test program aesxam.exe.

P6CryptAES.dll

This is the compiled and linked (binary) version of the P6 AES Cryptography library. This is the only file that must be distributed with your application.

P6CryptAES.h

This is the C header file that defines the functions exported by P6CryptAES.dll that are covered by this document. I wrote all of them; the others, documented in aes.h, are the work of Dr. Brian Gladman. Please see his AES page for additional documentation.

P6CryptAES.lib

This is a library file against which you can link your C and VB code that calls P6CryptAES.dll.

P6CryptAES_TestHarness.BAS

This is the VBA code that I used to test the VB/VBA interface and from which the Visual Basic examples in this document were taken. The code is installed in Microsoft Word document P6CryptAES_TestHarness.DOC.

P6CryptAES_TestHarness.c

This is the C code that I used to test the C interface and from which the C examples in the documentation were taken.

P6CryptAES_TestHarness.CMD

This Windows NT command file calls P6CryptAES_TestHarness.exe and aesxam.exe to exercise the functions in the library under a variety of conditions. Since P6CryptAES_TestHarness.exe was written in C, this shell script tests only the C interface.

P6CryptAES_TestHarness.DOC

This Microsoft Word document contains the code in VB/VBA module P6CryptAES_TestHarness.BAS and support modules mUIntConversions_P6C.BAS and mWin32API_P6C.BAS. Together with Windows NT command file P6CryptAES_TestHarness_VBA.CMD and aesxam.exe, this document exercises the Visual Basic interface.

P6CryptAES_TestHarness.exe

This is the compiled and linked version of P6CryptAES_TestHarness.c, which exercises the C interface.

P6CryptAES_TestHarness_VBA.CMD

This Windows NT command file is called from the VBA code in P6CryptAES_TestHarness.DOC, and calls aesxam.exe to exercise the functions in the library under a variety of conditions. Since the code in P6CryptAES_TestHarness.DOC was written in Visual Basic for Applications, this shell script tests only the Visual Basic interface.

P6CryptAES_TestSet_18.ZIP

This is the output from my final run of P6CryptAES_TestHarness.CMD to exercise the C interface.

P6CryptAES_TestSet_19.ZIP

This is the output from my final run of P6CryptAES_TestHarness_VBA.CMD to exercise the VB/VBA interface.

P6PAUSE.COM

This is a small utility that I wrote over 15 years ago to replace the weak PAUSE command built into every command interperter since MS-DOS 1.0. Unlike the built-in command, this program responds to only two things: ENTER and CTRL-C. It is written in pure Microsoft Macro Assembler 5.1 and works on all versions of Windows and DOS - IBM, Microsoft, and even 4DOS and Caldera DOS.

Installation

Though you may install and run P6CryptAES.dll anywhere, the most convenient place in which to install it is either the %SystemRoot%\System32\ directory or another general purpose directory into which you install shared application DLL files that are not part of the operating system.

Since there is no COM interface, the library is ready to run, requiring no registration.

Development History

The table below gives a brief development history of this program.

Date

Version

By Whom

Remarks

2005/01/29

1, 0, 0, 1

DAG

Initial release, containing only the Rijendael algorithm. This version requires two calls and external data structures and buffers. This version was highly experimental and was never put into production.

2005/02/11

1, 0, 0, 2

DAG

Add wrapper function to hide the context data structure, condense two calls to one, and accept a password of arbitrary length. Like the first version, this one was highly experimental and was never put into production.

2005/02/19

1, 0, 0, 3

DAG

Perfect encryption function EncryptString_P6C and add DecryptString_P6C to decrypt text. This version saw limited internal use.

2005/02/20

1, 0, 0, 4

DAG

Add function CryptStatus_P6C to return additional status information that is inconvenient to return by the usual methods, and function ZeroMemory_P6C to expose the memset function from the C run-time library. This version saw limited internal use.

2005/04/20

2, 0, 0, 1

DAG

Alter the C interface to handle all memory management, add an interface for Visual Basic, and add robust error checking. This is the first version that I believe is ready for production.

2005/04/20

2, 0, 0, 1

DAG

Alter the C interface to handle all memory management, add an interface for Visual Basic, and add robust error checking. This is the first version that I believe is ready for production.

2005/05/24

3, 0, 0, 1

DAG

  • Add WIL Extender interface.
  • Move memory cleanup code from DLLMain to new void function FreeOutputBuf_P6C, and remove DLLMain from this module. DLLMain, now in module WILExtender.C calls FreeOutputBuf_P6C when a process detaches.
  • Substitute module P6MemIO.c for the more primitive implementation of the same functions that were developed for the original version of this module. These more advanced versions were developed for P6Base64.dll; I pulled in copies.
  • Substitute HeapAlloc and HeapRealloc for Malloc and ReAlloc functions, to handle larger blocks.

2005/06/15

4, 0, 0, 1

DAG

  • Substitute Win32 file and memory I/O functions for those in the C run-time library, to gain larger capacity.
  • Link with Matt Pietrek's LIBCTINY.LIB.

2006/01/25

5, 0, 0, 1

DAG

  • Merge tested functions EncryptFile_P6C and DecryptFile_P6C, both from library P6AESFile, which I created over the last weekend. I am discarding that library.
  • Move fillrand and cycles functions, used to generate random initialization vectors, ioto their own module.
  • Add the following new core functions:
    • EncryptToFile_P6C - Encrypt buffer to file
    • DecryptFromFile_P6C - Decrypt file to buffer
    • DecryptFromFile_VB_P6C - VB wrapper for DecryptFromFile_P6C

2006/01/26

5, 0, 0, 3

DAG

Confirm that DecryptFromFile_P6C reports the number of plaintext bytes through SetLastError.

2006/03/11

6, 0, 0, 1

DAG

  • Add 192 and 256 bit functions.
  • Improve security by clearing all buffers at every exit point.
  • Incorporate all new entry points into the WinBatch extender interface.

2007/06/28

6, 0, 0, 2

DAG

  • Fix file decryption error reported by Daryl Buckman, US Army Corps of Engineers, Omaha, Nebraska, USA, Information Management Office Computer Systems & Communications Branch Communications Team Leader.
  • Change DecryptFromFile_P6C so that it returns the plaintext length, saved in dwLastError, directly and via SetLastError, so that it can be retrieved later, if necessary, by the caller.

2007/07/12

6, 0, 0, 3

DAG

Thorough documentation update prior to publication of changes made in version 6, 0, 0, 2, after allowing two weeks to elapse since the chages were submitted privately to the U. S. Army Corps of Engineers, who reported the bugs. Other than incrementing the internal version numbers, no code was changed.

Support

Please contact me through the inquiry form at the bottom of any page of my company Web site, www.p6c.com. Your inquiry will be handled on a best efforts basis, and any information you send us about your specific situation will be treated as confidential. We do, however, reserve the right to incorporate any ideas we get from our correspondence with you into future versions of P6CryptAES or other software either for internal use or for sale. Should we do so, we shall give full credit to its source in the accompanying documentation.

Availability

The binary distribution, including comprehensive documentation for its use in C, VB, VBA, and WinBatch programs, is incluaded in this archive, which has an MD5 digest of e2046aee78e1053151308e8b89f19966.

The source code is in this archive, which has an MD5 digest of ba081fb5699ab9c58b8d678ec4883f25.

The latest binary and source code are always posted at the above locations.


P6C Contact Info

Copyright and Legal Notice