The Crypto++ User Group occasionally receives questions on Crypto++ and Microsoft's Environments. The questions are usually basic such as, "VC++ can't find a header file - how [where] do I..." or more generic statements such as, "I can't compile." This article will attempt to resolve these common issues, and provide basic background information.
The Crypto++ source code can be downloaded from the website at Crypto++ homepage. If the website is down, use the SourceForge page, or use an archiving service such as archive.org here.
There are four sources of documentation for Crypto++. They are the Source Code, the Crypto++ Usenet Group, the Crypto++ FAQ, and the Crypto++ Wiki. Wei maintains an FAQ which can be found here. The Crypto++ users group can be found here. The Crypto++ Wiki can be found here. Finally, Dennis Bider has authored a User Guide and Help File which can be found here. My most used reference is the source code, which can be found online at the Crypto++ Library Reference Manual and Crypto++ Class Index.
Ugo Chirico maintains a port of Crypto++ 5.5.2 to Windows Mobile 2005 at Crypto++ 5.5.2 on Windows Mobile 2005. Dr. Chirico posts announcements to the Crypto++ user group. His initial post can be found at Crypto++ Users.
There are no special steps in using managed code. Note that if we are using the FIPS DLL, we might find that some functionality is missing (see the discussion below). For a well written example, see Mike Sinclair's CodeProject.com article, RSA Encryption with .NET 2.0 Cryptography Services and Crypto++ Wrapped as a Managed C++ Class Library.
FIPS 140-2 certification means the library produces correct results and complies with certain cryptographic protocols. Protocols would include zeroing the memory of key material after the library is finished using it. When we refer to the FIPS compliant DLL, we will state FIPS DLL.
The FIPS DLL must be used in binary form as distributed by Wei (even though we have the source code and can build the same binary). This means we cannot build the Crypto++ DLL and claim it is FIPS compliant.
Version 5.5.2 is the last version of the library which Wei plans to submit for testing and validation. Details can be found here.
The module certification FAQ can be found under the Cryptographic Module Validation Program.
In all cases, the Crypto++ library should be built using multi-threaded libraries. This was an issue with Visual C++ 6.0 and previous. At times, the Project Wizard would output a project using Singe Threaded project (/ML and /MLd).
When integrating Crypto++, the Crypto++ library must use the same runtime library linker setting as our Visual Studio project. The runtime library refers to the C Runtime Library. A stock Crypto++ distribution is built using static linking against the runtime (/MT and /MTd).
A default Visual Studio project created by the wizard will use dynamic runtime linking. The project would specify the /MD or /MDd linker switch for dynamic runtime linking, while the Crypto++ library would be using static linking (/MT or /MTd) from its build. This will cause a plethora of LINK2005 errors when linking. To resolve the Crypto++ library must be rebuilt. Table 1 below summarizes this discussion
Project Setting | Project Link Switch | Desired Runtime Linking | Action Required |
Static Runtime Linking | /MT or /MTd | Static | None |
Dynamic Runtime Linking | /MD or /MDd | Dynamic | Rebuild Crypto++ Library |
Rebuild Crypto++ Library means to rebuild the Crypto++ library after changing the settings to compile and link against dynamic versions of the runtime. Also see the section Unsupported Configuration below.
The Crypto++ library is distributed as a statically linked library. Static linking is usually preferred (versus the DLL or FIPS DLL). According to Wei Dai:
... there should not be any problems linking a DLL against a DLL. But using the static library saves on code size and I'd suggest it unless you need to use the DLL for some reason (such as FIPS compliance).
When creating a statically linked Visual Studio project, no additional settings need to be changed.
When dynamically linking to the C Runtime (/MD or /MDd), the Crypto++ library must be rebuilt using the same link settings are the main project. Open the Crypto++ project and change the Crypto++ project setting for both Cryptlib and CryptDll. The settings should be changed to /MD or /MDd. For good measure, the setting should also be changed for Cryptest (and the validation test re-run: issue cryptest v).
Runtime linking presents two difficult situations for the software author. First is the desire to link dynamically against the C runtime while using the FIPS DLL. The issue is derived as follows: Dynamic C Runtime linking is used by (/MD or /MDd) the application, but the distributed FIPS DLL is static (/MT or /MTd). The best solution is using the /NODEFAULTLIB switch, and hope that no runtime issues occur. This situation will create hard to track down runtime bugs and obscure initialization failures. Note that rebuilding the DLL using dynamic runtime linking is not available since we are using the FIPS DLL.
The second situation is created when using additional third party components. This includes MFC and ATL. Suppose we need to use the FIPS DLL. We change the Project settings to use the static version of the runtime, and link using the FIPS DLL. Next, we add the third party component which only offers dynamic linking against the C Runtime. We now have the situation previously described. The preferred work around it to contact the third party vendor, and acquire a library which uses the same runtime settings as our Project and Crypto++.
When using the DLL or FIPS DLL, the newsgroup occasional receives reports of LNK2001 and LINK2019 such as below. This is because the DLL and FIPS DLL only includes certified algorithms. So the DLL exports AES, but it does not export DES (DES has been deprecated in various standards). Also missing from the FIPS DLL are supporting classes such as Base64Encoder.
Crypto.obj : error LNK2019: unresolved external symbol
"public: virtual void __thiscall CryptoPP::Base64Encoder::IsolatedInitialize
(class CryptoPP::NameValuePairs const &)"
(? IsolatedInitialize@Base64Encoder@CryptoPP@@UAEXABVNameValuePairs@2@@Z)
referenced in function "public: __thiscall CryptoPP::Base64Encoder::Base64Encoder
(class CryptoPP::BufferedTransformation *,bool,int)"
(??0Base64Encoder@CryptoPP@@QAE@PAVBufferedTransformation@1@_NH@Z)
or
dlltest.obj : error LNK2001: unresolved external symbol "__declspec(dllimport)
public: __thiscall CryptoPP::DH_Domain<class CryptoPP::DL_GroupParameters_GFP_DefaultSafePrime,
struct CryptoPP::EnumToType<enum CryptoPP::CofactorMultiplicationOption,0>
...
DLL_Debug/dlltest.exe : fatal error LNK1120: 1 unresolved externals
To resolve, first read the "MSVC-Specific Information" in the readme.txt. Wei offers two solutions to the issue:
There are two ways you can deal with this, either change Crypto++ to export those classes, by using CRYPTOPP_DLL macro, or link with both the DLL export library and a static library that contains the non-DLL classes and functions. The latter can be built by using the "DLL-Import" configuration of the cryptlib project.
Note that in Wei's first solution, we are rebuilding the DLL (not the FIPS DLL) to export the additional functions we require by using the CRYPTO_DLL macro. We may also have to add the source files to the cryptdll project in the solution. In the second offering, we are using the FIPS DLL and supplementing it with functionality from Crypto++'s static library, since the FIPS DLL does not contain all the Crypto++ functionality we need.
At time, we might have to force Crypto++ to use new and delete from another library rather than the standard runtime. For this, we would want to callSetNewAndDeleteFunctionPointers
. See dll.cpp for Wei's use of setting the function pointers for the standard runtime.
Also be aware that this usually has to be done early in the initialization process. This creates additional issues not related to Crypto++, such as linking libraries in the wrong order. Please see Knowledge Base Article 148652, LNK2005 error occurs when the CRT library and MFC libraries are linked in the wrong order in Visual C++.
Visit the Crypto++ homepage and fetch a version for download. This article is based on version 5.2.1, but any version should do. We should review the "Platforms" Matrix when choosing a Crypto++ distribution. When using Visual Studio 6.0, Microsoft's Processor Pack is recommended for Crypto++ 5.1 and earlier; and is required for Crypto++ 5.2 and later.
Create a directory on the hard drive for the distribution of Crypto++ downloaded. Locate the cryptest.dsw or cryptest.sln file, and open it. In this example, the ZIP file was extracted to C:/CryptoPP 5.2.1/.
From the Build Menu, Select Batch Build
For the purposes of this article, build only the Static Library by un-checking the appropriate selections.
This document will add the library to the Visual Studio environment rather than the Project environment. This means the settings affect every project, not just a Crypto++ project. Please see John Deters's comment below for reasons not to do so. It is well crafted and explained commentary which should prove useful. Once the build is complete, drill into the C:/CryptoPP 5.2.1/Debug/ folder. Rename the library file from cryptlib.lib to cryptlibd.lib (notice the addition of the "d" for Debug).
Move the Debug Library to the location of the Header and Source Files. In this example, the location is C:/CryptoPP 5.2.1/. Also, move (without renaming) the Release version to the same folder.
Add the location of the Header Files, Source Files, and Libraries to the VC++ Environment. Select Tools | Options, Directories Tab. Make the appropriate entry for the previously mentioned items in the drop down menu.
Add the location of the Header Files, Source Files, and Libraries to the VC++ Project.
This step will allow us to #include"ecp.h"
, rather than including ecp.h, all of its dependencies; and specifying full or relative paths. Also, since the Library is on path (and appropriately named), one can now issue the following #pragma
to have the linker include the library:
// Crypto++ Library #ifdef _DEBUG # pragma comment ( lib, "cryptlibd" ) #else # pragma comment ( lib, "cryptlib" ) #endif
If interested, a project configuration exists which allows for building Crypto++ using both static and dynamic runtime linking. However, don't expect Wei to support it. The authors have used it for quite some time with both Visual Studio 8.0 and Visual Studio 9.0.
Unfortunately, the x64 build settings have been removed by the IDE because the x64 compiler and headers were not installed during installation. Fortunately, they can be easily added back into the project using the Configuration Manager.
The alternate configuration renames the cryptlib project to cryptlib.static. It also adds cryptlib.dynamic (with settings copied form cryptlib.static). Both the static and dynamic projects build debug and release libraries. ".dynamic" and ".static" were chosen rather than 'd' and 's' suffixes so that debug builds would not be confused with dynamic c runtime linking builds. Files offered by the configurations are:
To use the configuration, unzip the files over top of the Crypto++ files, replacing as required. For those who concern themselves with library size (before the linker removes unused functions), dynamic runtime linking produces considerably smaller code.
After building the four variant, use copylib.cmd to copy the libraries to the root of the Crypto++ distibution. Finally, include CryptlibInclude.h in the project.CryptlibInclude.h performs a switch based on _DLL
(defined when using dynamic runtime linking) and DEBUG
:
Also note that both the static and dynamic libraries use dll.cpp, even though we are not building the dll . If we don't use dll.cpp, we will receive LNK2001 errors stsing that a function (using _thiscall) could not be found, despite the fact that we specify _cdecl for compilation in the source file's properties. Below,VerifyHash (an ATL project which requires dynamic runtime linking) is using cryptlib.dynamic without dll.cpp.
We receive 20 errors (10 pairs) similar to below. The first error claims that the program cannot be linked because of a missing function in VerifyHash.obj. The second (referring to the same function) claims the function cannot be found in the Crypto++ library.
VerifyHash.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall CryptoPP::IteratedHashBase<unsigned int,class CryptoPP::HashTransformation>::Update(unsigned char const *,unsigned int)" (?Update@?$IteratedHashBase@IVHashTransformation@CryptoPP@@@CryptoPP@@UAEXPBEI@Z)
cryptlibd.dynamic.lib(md5.obj) : error LNK2001: unresolved external symbol "public: virtual void __thiscall CryptoPP::IteratedHashBase<unsigned int,class CryptoPP::HashTransformation>::Update(unsigned char const *,unsigned int)" (?Update@?$IteratedHashBase@IVHashTransformation@CryptoPP@@@CryptoPP@@UAEXPBEI@Z)
I can't explain why functions from iterbase.h and iterbase.cpp are affected by inclusion or exclusion of dll.cpp.
This section will discuss common compiler and liner errors encountered when using the Crypto+ library. They are usually encountered because of an oversight in following these instructions. Once you have verified that these instructions were followed, please post your question to the Crypto++ User Group.
If you receive Internal Compile Error COMPILE 1001 (C1001) shown below
You should perform the following:
Depending on the version of Visual Studio, some compile time changes are invoked. One suspect to pay particular attention to is _MSC_VER < 1300
. If using Visual Studio 7.1 or above, changing to below may do the trick.
// how to declare class constants #if defined(_MSC_VER) && _MSC_VER <= 1300 # define CRYPTOPP_CONSTANT(x) enum {x}; #else # define CRYPTOPP_CONSTANT(x) static const int x; #endif
Function A { ... } Function B { ... }
Change the above to:
Function B { ... } Function A { ... }
I can't explain this one, but it has worked for me in the past when working with Crypto++ Elliptic Curve functions.
If you do not add the path to the Crypto++ header files to the Visual C++ environment or your Project, COMPILE 1083 (C1083) Errors similar to below will be displayed.
If you incorrectly match the C Runtime with MFC (for example, MFC as a DLL, Crypto++ and C Runtime as a Static Library), COMPILE 1189 (C1189), errors similar to those below will be displayed.
You should revisit the section Static Versus Dynamic Linking. MFC uses dynamic runtime linking.
If you receive Compile Warning COMPILE 4530 (C4530) ...
... then you should enable exception handling.
If you receive LINK 1103 (LNK1103) "debugging information corrupt" when using Visual C++ 6.0 and the latest Platform SDK (shown below) with libraries uuid.lib,shell32.lib, msxml2.lib, etc ...
... then you should roll back the Platform SDK to February 2003. One may be able to change the directory order in Visual C++ 6.0.
If you do not install MFC Unicode Library Versions (mfc42u.lib, mfc42ud.lib, etc.), but define UNICODE, LINK 1104 (LNK1104), then errors similar to those below will be displayed. This is a Visual C++ 6.0 and previous error, since Visual Studio 7.0 and above do not allow a non-Unicode installation.
To resolve, rerun setup and install the Unicode Libraries (performing a custom installation).
If you do not place the Crypto++ Library on the VC++ IDE path, LINK 1104 (LNK1104), then errors similar to those below will be displayed.
If you do not link the Crypto++ Library to the project, LINK 2001 (LNK2001), errors similar to those below will be displayed.
To resolve this, add the following to StdAfx.h (if using precompiled headers) or to the source file using Crypto++.
// Crypto++ Library #ifdef _DEBUG # pragma comment ( lib, "cryptlibd" ) #else # pragma comment ( lib, "cryptlib" ) #endif
Alternately, one can add the Crypto++ Library through the Visual C++ IDE.
The Crypto++ output libraries are located at Win32/output/debug/cryptlib.lib and Win32/output/release/cryptlib.lib. The DLL and its export library are inWin32/dll_output. Note the "dll_" in the path name. Verify that you are using the correct paths.
If you do not change C Runtime Library settings on the Project, LINK 2005 (LNK2005), then errors similar to those below will be displayed.
You should use the Multithreaded versions of the C++ Runtime Library:
Should you encounter LNK2005 when using ATL, recompile the Crypto++ library using the Multithreaded DLL and Multithreaded Debug DLL choices of the runtime library. This was not an issue in Visual C++ 6.0, but it is an issue in Visual Studio 2005.
This error is due to the FIPS DLL only exporting certified algorithms such as AES. Wei offers two solutions to the issue. First, you can statically link against the library. Second, you must use the DLL version of the library (not the FIPS DLL). Then, to export the missing classes of interest, add the CRYPTOPP_DLL macro to the class declaration. Then rebuild the DLL-Import project.
As distributed, the Integer class displays a suffix ('o', '.', or 'h') to denote base. In addition, the library uses uppercase characters for all hexadecimal output. To change the behavior so that Integer does not use a suffix and honors ios::uppercase
flag, perform the following. First, remove the declaration for suffix
and change the switch
statement.
switch(f) { case std::ios::oct : base = 8; block = 8; break; case std::ios::hex : base = 16; block = 4; break; default : base = 10; block = 3; }
Next, add the following.
const char* vec = NULL; const char upper[]="0123456789ABCDEF"; const char lower[]="0123456789abcdef"; if( out.flags() & (long)std::ios::uppercase ) { vec = upper; } else { vec = lower; } ... // No longer can return out << suffix; return out;
std::cout
FormattingThis article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
Garth J Lancaster |
|
Other popular Programming Tips articles:
|