![]() |
Free Stuff |
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: |
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,
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
|
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 |
DecryptString_VB_P6C |
This is an alternate entry point for |
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.
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.
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.
|
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.
|
Notes
1 |
The input text is declared as type |
1 |
Beware of the |
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 |
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 |
1 |
The |
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.
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.
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.
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.
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.
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 |
This is the compiled and linked code of demonstration program |
CryptAES_P6C.WIL |
This is the WinBatch Include file that contains User Defined Function |
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 |
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.lib |
This is a library file against which you can link your C and VB code that calls |
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.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.DOC |
This Microsoft Word document contains the code in VB/VBA module |
P6CryptAES_TestHarness.exe |
This is the compiled and linked version of |
P6CryptAES_TestHarness_VBA.CMD |
This Windows NT command file is called from the VBA code in |
P6CryptAES_TestSet_18.ZIP |
This is the output from my final run of |
P6CryptAES_TestSet_19.ZIP |
This is the output from my final run of |
P6PAUSE.COM |
This is a small utility that I wrote over 15 years ago to replace the weak |
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.
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 |
2005/02/20 |
1, 0, 0, 4 |
DAG |
Add function |
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 |
|
2005/06/15 |
4, 0, 0, 1 |
DAG |
|
2006/01/25 |
5, 0, 0, 1 |
DAG |
fillrand and cycles
functions, used to generate random initialization vectors,
ioto their own module.
|
2006/01/26 |
5, 0, 0, 3 |
DAG |
Confirm that |
2006/03/11 |
6, 0, 0, 1 |
DAG |
|
2007/06/28 |
6, 0, 0, 2 |
DAG |
|
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. |
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.
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.