0%

Crypto++ (Cryptopp)以动态链接库使用的注意事项

由于一个项目中可能有很多的库不同的库,不同的库链接方式并不统一,最终链接时会产生问题。
出于各种原因我必须使用动态链接的方法使用Crypto++这个库,在Windows下使用Crypto++这个库的时候遇到一点问题这里记录一下,以防踩坑。
正常的修改库寻找目录什么的就不多说了。
首先注意要使用Crypto++可能需要同时链接下面两个库文件

cryptlib.lib
cryptopp.lib

可以通过pragma指令完成

1
2
#pragma comment(lib,"cryptlib.lib")  
#pragma comment(lib,"cryptopp.lib")

当然使用过程中还会遇到其他的问题这里列出来。

链接出现LNK2019错误

1
2
3
4
5
6
7
Crypto.obj : error LNK2019: unresolved external symbol
"public: virtual void __thiscall CryptoPP::Base64Encoder::IsolatedInitialize
(class CryptoPP::NameValuePairs const &)"
(? [email protected]@[email protected]@[email protected]2@@Z)
referenced in function "public: __thiscall CryptoPP::Base64Encoder::Base64Encoder
(class CryptoPP::BufferedTransformation *,bool,int)"
(??0B[email protected]@@[email protected]@1@[email protected])

这类错误是由于项目中引用的部分函数并没有通过FIPS DLL导出导致的。
解决方法有两种。
1、使用CRYPTOPP_DLL宏
2、使用DLL-Import工程重新编译 LNK2001错误

链接出现LNK2001错误

1
2
3
4
5
6
7
1>Main.obj : error LNK2001: 无法解析的外部符号 "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const CryptoPP::DEFAULT_CHANNEL" ([email protected]@@3[email protected][email protected]@std@@[email protected]@2@@std@@B)
1>Main.obj : error LNK2001: 无法解析的外部符号 "bool (__cdecl* CryptoPP::g_pAssignIntToInteger)(class type_info const &,void *,void const *)" ([email protected]@@3[email protected]@[email protected])
1> LINK : 找到 MSIL .netmodule 或使用 /GL 编译的模块;正在使用 /LTCG 重新启动链接;将 /LTCG 添加到链接命令行以改进链接器性能
1>LINK : warning LNK4075: 忽略“/INCREMENTAL”(由于“/LTCG”规范)
1>Main.obj : warning LNK4075: 忽略“/EDITANDCONTINUE”(由于“/OPT:LBR”规范)
1>Main.obj : error LNK2001: 无法解析的外部符号 "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const CryptoPP::DEFAULT_CHANNEL" ([email protected]@@3[email protected][email protected]@std@@[email protected]@2@@std@@B)
1>Main.obj : error LNK2001: 无法解析的外部符号 "bool (__cdecl* CryptoPP::g_pAssignIntToInteger)(class type_info const &,void *,void const *)" ([email protected]@@3[email protected]@[email protected])

查阅资料,使用动态链接库版本的Crypto++,还需要做一些其他的工作。
以动态链接库方式使用Crypto++(CryptoPP)库任何头文件前必须先引入dll.h头文件,以及重写SetNewAndDeleteFromCryptoPP等和内存分配有关的函数。
过程比较麻烦,我直接贴上代码。
在工程中引入这些文件即可。
首先是:cryptopp_dll_init.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#ifndef _CRYPTOPP_DLL_INIT_HEADER_
#define _CRYPTOPP_DLL_INIT_HEADER_

#ifdef _MSC_VER
#pragma warning(disable:4251 4275 4101)
//cryptlib.lib
//#pragma comment(lib, "cryptlib")
#define CRYPTOPP_IMPORTS_WINDOWS_DLL
#endif //_MSC_VER

#ifdef CRYPTOPP_IMPORTS_WINDOWS_DLL
#include <cryptopp/dll.h>

/************************************************************************/
/* Because it's possible for the Crypto++ DLL to delete objects allocated */
/* by the calling application, they must use the same C++ memory heap. */
/* The following code block to achieve this. */
/************************************************************************/
#ifdef CRYPTOPP_IMPORTS
static CryptoPP::PNew s_pNew = NULL;
static CryptoPP::PDelete s_pDelete = NULL;

extern "C" __declspec(dllexport) void __cdecl SetNewAndDeleteFromCryptoPP(
CryptoPP::PNew pNew,
CryptoPP::PDelete pDelete,
CryptoPP::PSetNewHandler pSetNewHandler
);
void *__cdecl operator new (size_t size);
void __cdecl operator delete (void *p);
#endif //CRYPTOPP_IMPORTS

/*******************************************************************************/
/* Note: You may be using a weak algorithm that has been retained for backwards */
/* compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before */
/* including this .h file and prepend the class name with 'Weak::' to remove this */
/* warning." */
/******************************************************************************/
#if 0
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <arc4.h>
#include <md2.h>
#include <md4.h>
#include <md5.h>
#endif

#endif //CRYPTOPP_IMPORTS_WINDOWS_DLL

#endif //_CRYPTOPP_DLL_INIT_HEADER_

接着是:cryptopp_dll_init.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "cryptopp_dll_init.h"

#ifdef CRYPTOPP_IMPORTS_WINDOWS_DLL
#pragma warning(disable:4251 4275 4101 4100)


#ifdef CRYPTOPP_IMPORTS
//static CryptoPP::PNew s_pNew = NULL;
//static CryptoPP::PDelete s_pDelete = NULL;

extern "C" __declspec(dllexport) void __cdecl SetNewAndDeleteFromCryptoPP(
CryptoPP::PNew pNew,
CryptoPP::PDelete pDelete,
CryptoPP::PSetNewHandler pSetNewHandler
)
{
(void)(pSetNewHandler);
s_pNew = pNew;
s_pDelete = pDelete;
}

void * __cdecl operator new (size_t size)
{
return s_pNew(size);
}

void __cdecl operator delete (void * p)
{
s_pDelete(p);
}

#endif //CRYPTOPP_IMPORTS

#endif //CRYPTOPP_IMPORTS_WINDOWS_DLL

运行时触发 “Cryptographic algorithms are disabled after a power-up self test failed” 异常


使用CryptoPP::AESEncryption的过程中发现会触发异常。
异常内容为: “Cryptographic algorithms are disabled after a power-up self test failed”
原因:启用FIPS后有部分算法会不能使用,而很多常见算法都不包含在FIPS标准中。
解决办法:
直接定义宏

CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 = 0

可以通过修改编译器的预定义选项或者在cryptdll库的pch.h文件中添加如下宏定义:

1
2
3
4
5
6
7
8
#define CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 0
#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 == 1
#pragma message("FIPS Compliance is Enabled")
#elif CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 == 0
#pragma message("FIPS Compliance is Disabled")
#else
#pragma message("FIPS Compliance is Ambiguous")
#endif

运行时抛出堆异常

1
2
3
4
5
6
7
8
9
10
11
12
Microsoft Visual C++ Runtime Library
—————————
Debug Assertion Failed!

Program: C:\Users\…\cryptopp.dll
File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 996

Expression: __acrt_first_block == header

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

或者抛出异常

1
2
0x00007FF9EE785299 处(位于 XXXX.exe 中)引发的异常: Microsoft C++ 异常: std::bad_alloc,位于内存位置 0x000000BB820F8428 处。
Critical error detected c0000374

一般此类问题是项目中引用的库编译时使用的运行时编译选项不一致造成的。
cryptdll这个项目中的运行库选项,cryptdll默认是 /MT 和 /MTd
如果和项目中不一致就会出现这种问题,这里修改为 /MD 和 /MDd 就行了。