Crypto++(CryptoPP)库初始化以及使用注意事项

时间:2022-05-19 19:46:55

开篇提示:本文为本人原创,本文欢迎转载,但必须注明本文出处,例如。
“该文引用自 CruiseYoung的:Crypto++(CryptoPP)库初始化以及使用注意事项
http://blog.csdn.net/fksec/article/details/41012391”
否则说明阁下愿意支付以100元人民币每字计的稿费,敬请留意。

1 官网

地址:http://www.cryptopp.com/

2 重要资料来源

2.1 源代码中的“Readme.txt”文件;
2.2 源代码中的测试工程“dlltest”中的“dlltest.cpp”;

3 使用注意事项

3.1 重要文档摘录;

*** MSVC-Specific Information ***

On Windows, Crypto++ can be compiled into 3 forms: a static library
including all algorithms, a DLL with only FIPS Approved algorithms, and
a static library with only algorithms not in the DLL.
(FIPS Approved means Approved according to the FIPS 140-2 standard.)
The DLL may be used by itself, or it may be used together with the second
form of the static library. MSVC project files are included to build
all three forms, and sample applications using each of the three forms
are also included.

To compile Crypto++ with MSVC, open the "cryptest.dsw" (for MSVC 6 and MSVC .NET
2003) or "cryptest.sln" (for MSVC 2005 - 2010) workspace file and build one or
more of the following projects:

cryptopp - This builds the DLL. Please note that if you wish to use Crypto++
as a FIPS validated module, you must use a pre-built DLL that has undergone
the FIPS validation process instead of building your own.
dlltest - This builds a sample application that only uses the DLL.
cryptest Non-DLL-Import Configuration - This builds the full static library
along with a full test driver.
cryptest DLL-Import Configuration - This builds a static library containing
only algorithms not in the DLL, along with a full test driver that uses
both the DLL and the static library.

To use the Crypto++ DLL in your application, #include "dll.h" before including
any other Crypto++ header files, and place the DLL in the same directory as
your .exe file. dll.h includes the line #pragma comment(lib, "cryptopp")
so you don't have to explicitly list the import library in your project
settings. To use a static library form of Crypto++, make the "cryptlib"
project a dependency of your application project, or specify it as
an additional library to link with in your project settings.
In either case you should check the compiler options to
make sure that the library and your application are using the same C++
run-time libraries and calling conventions.

*** DLL Memory Management ***

Because it's possible for the Crypto++ DLL to delete objects allocated
by the calling application, they must use the same C++ memory heap. Three
methods are provided to achieve this.
1. The calling application can tell Crypto++ what heap to use. This method
is required when the calling application uses a non-standard heap.
2. Crypto++ can tell the calling application what heap to use. This method
is required when the calling application uses a statically linked C++ Run
Time Library. (Method 1 does not work in this case because the Crypto++ DLL
is initialized before the calling application's heap is initialized.)
3. Crypto++ can automatically use the heap provided by the calling application's
dynamically linked C++ Run Time Library. The calling application must
make sure that the dynamically linked C++ Run Time Library is initialized
before Crypto++ is loaded. (At this time it is not clear if it is possible
to control the order in which DLLs are initialized on Windows 9x machines,
so it might be best to avoid using this method.)

When Crypto++ attaches to a new process, it searches all modules loaded
into the process space for exported functions "GetNewAndDeleteForCryptoPP"
and "SetNewAndDeleteFromCryptoPP". If one of these functions is found,
Crypto++ uses methods 1 or 2, respectively, by calling the function.
Otherwise, method 3 is used.

3.2 通常,我们在使用一个库时,要么引用该库的静态库(static),要么引用改库的动态库(dll);

       而改库却有三种引用方式:
第一种:即通常的静态库引用方式,此处我们称为“全静态库”引入方式,记为:Static方式;
该种方式提供了所有的算法,无须做任何初始化。
第二种:“纯动态库”形式,记为:DLL-Only方式;
此种方式仅仅提供FIPS算法,即FIPS 140-2标准所规定的算法,在使用前必须检查FIPS140-2算法是否在编译期间打开。
        程序编写方式:见后附的文件fips140_sample_application.cpp;
第三种:同时使用静态库和动态库,记为:DLL-Import方式;
注意此时,工程的C++运行库(CRT,C++ Run Time Library)引入了(MT/MTD),此时可能和您的工程所设置的CRT有冲突,可能会出现非常多的千奇百怪的错误。
见文件:dll.h
#ifdef CRYPTOPP_IMPORTS

#ifdef _DLL
// cause CRT DLL to be initialized before Crypto++ so that we can use malloc and free during DllMain()
#ifdef NDEBUG
#pragma comment(lib, "msvcrt")
#else
#pragma comment(lib, "msvcrtd")
#endif
#endif

#pragma comment(lib, "cryptopp")

#endif// #ifdef CRYPTOPP_IMPORTS
3.3 总结
Static方式:
预定义宏:无
依赖库:cryptlib.lib;odbc32.lib;odbccp32.lib;Ws2_32.lib;
DLL方式:
以下两种方式,需要注意两点:
注意1:在引入Crypto++(CryptoPP)库任何头文件前必须先引入dll.h头文件;
注意2:由于在dll.h文件已经有语句#pragma comment(lib, "cryptopp"),所以不需要自己明确依赖“cryptopp.lib”库,但必须在工程的属性中的“附加库目录”中填写“cryptopp.lib”目录;
注意3:都需要进行库初始化,即保证库使用相同的内存堆, 否则程序运行过程中会崩溃;见dlltest.cpp文件;
#ifdef CRYPTOPP_IMPORTS

static PNew s_pNew = NULL;
static PDelete s_pDelete = NULL;

extern "C" __declspec(dllexport) void __cdecl SetNewAndDeleteFromCryptoPP(PNew pNew, PDelete pDelete, PSetNewHandler 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
DLL-Only方式:
预定义宏:CRYPTOPP_DLL_ONLY;
依赖库:odbc32.lib;odbccp32.lib;
程序编写方式:见后附的文件fips140_sample_application.cpp;
DLL-Import方式:
预定义宏:CRYPTOPP_IMPORTS;
注意4:CRYPTOPP_IMPORTS在第dll.h文件中已经定义,但此处要求定义,是为了使用后面总结的“cryptopp_dll_init.h”头文件。
依赖库:cryptlib.lib;Ws2_32.lib;

3.4 在引入以下头文件时,必须先定义#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1,且在类名前使用Weak::
#include <arc4.h>
#include <md2.h>
#include <md4.h>
#include <md5.h>
原文:
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.

4 Crypto++(CryptoPP)库初始化头文件

文件:cryptopp_dll_init.h

#ifndef CRYPTOPP_DLL_INIT_HEADER_
#define CRYPTOPP_DLL_INIT_HEADER_


#if defined (CRUISE_HAVE_PRAGMA_ONCE)
#pragma once
#endif


#ifndef CRYPTOPP_DLL_ONLY
#define CRYPTOPP_DEFAULT_NO_DLL
#endif


/***************************************************************************/
/* To use the Crypto++ DLL in your application, #include "dll.h" before including */
/* any other Crypto++ header files, and place the DLL in the same directory as */
/* your .exe file. */
/***************************************************************************/
#if defined(CRYPTOPP_DLL_ONLY) || defined(CRYPTOPP_IMPORTS)
#include "dll.h"

//USING_NAMESPACE(CryptoPP)
//USING_NAMESPACE(std)
#endif


/*******************************************************************************/
/* 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


/************************************************************************/
/* 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)
inline void __cdecl SetNewAndDeleteFromCryptoPP(
CryptoPP::PNew pNew,
CryptoPP::PDelete pDelete,
CryptoPP::PSetNewHandler pSetNewHandler)
{
s_pNew = pNew;
s_pDelete = pDelete;
}

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

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

#endif


/************************************************************************/
/* Check FIPS140 before the program enters a function mian */
/************************************************************************/
#ifdef CRYPTOPP_DLL_ONLY

// check FIPS validity
/*static/inline*/
inline int CHECK_FIPS140(void)
{
USING_NAMESPACE(CryptoPP)
USING_NAMESPACE(std)

if (!FIPS_140_2_ComplianceEnabled())
{
cerr << "FIPS 140-2 compliance was turned off at compile time.\n";
abort();
}

// perform the power - up self test
DoDllPowerUpSelfTest();

// check self test status
if (GetPowerUpSelfTestStatus() != POWER_UP_SELF_TEST_PASSED)
{
cerr << "Automatic power-up self test failed.\n";
abort();
}
cout << "Automatic power-up self test passed.\n";

// simulate a power-up self test error
//SimulatePowerUpSelfTestFailure();

return 0;
}

// Check FIPS140 before the program enters a function mian
static int g_fips_validity = CHECK_FIPS140();

#endif


#endif

使用方式:
第一:只需如3.3节所示,定义各种引入方式的预定义宏即可,引入对应的依赖库;
第二:在引入Crypto++(CryptoPP)库任何头文件之前引入该文件即可,库初始化已在头文件中自动完成。

5 PIPS140-2算法使用方法

文件:fips140_sample_application.cpp
#include "cryptopp_dll_init.h"


void fips140_sample_application()
{
#ifdef CRYPTOPP_DLL_ONLY

USING_NAMESPACE(CryptoPP)
USING_NAMESPACE(std)

// encrypt and decrypt
const byte key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
const byte iv[] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef };
const byte plaintext[] = {// "Now is the time for all " without tailing 0
0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20 };
byte ciphertext[24];
byte decrypted[24];

CFB_FIPS_Mode<DES_EDE3>::Encryption encryption_DES_EDE3_CFB;
encryption_DES_EDE3_CFB.SetKeyWithIV(key, sizeof(key), iv);
encryption_DES_EDE3_CFB.ProcessString(ciphertext, plaintext, 24);

CFB_FIPS_Mode<DES_EDE3>::Decryption decryption_DES_EDE3_CFB;
decryption_DES_EDE3_CFB.SetKeyWithIV(key, sizeof(key), iv);
decryption_DES_EDE3_CFB.ProcessString(decrypted, ciphertext, 24);

if (memcmp(plaintext, decrypted, 24) != 0)
{
cerr << "DES-EDE3-CFB Encryption/decryption failed.\n";
abort();
}
cout << "1. DES-EDE3-CFB Encryption/decryption succeeded.\n";

// hash
const byte message[] = { 'a', 'b', 'c' };
const byte expectedDigest[] = { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D };
byte digest[20];

SHA1 sha;
sha.Update(message, 3);
sha.Final(digest);

if (memcmp(digest, expectedDigest, 20) != 0)
{
cerr << "SHA-1 hash failed.\n";
abort();
}
cout << "2. SHA-1 hash succeeded.\n";

// create auto-seeded X9.17 RNG object, if available
#ifdef OS_RNG_AVAILABLE
AutoSeededX917RNG<AES> rng;
#else
// this is used to allow this function to compile on platforms that don't have auto-seeded RNGs
RandomNumberGenerator &rng(NullRNG());
#endif

// generate DSA key
DSA::PrivateKey dsaPrivateKey;
dsaPrivateKey.GenerateRandomWithKeySize(rng, 1024);
DSA::PublicKey dsaPublicKey;
dsaPublicKey.AssignFrom(dsaPrivateKey);
if (!dsaPrivateKey.Validate(rng, 3) || !dsaPublicKey.Validate(rng, 3))
{
cerr << "DSA key generation failed.\n";
abort();
}
cout << "3. DSA key generation succeeded.\n";

// encode DSA key
std::string encodedDsaPublicKey, encodedDsaPrivateKey;
dsaPublicKey.DEREncode(StringSink(encodedDsaPublicKey).Ref());
dsaPrivateKey.DEREncode(StringSink(encodedDsaPrivateKey).Ref());

// decode DSA key
DSA::PrivateKey decodedDsaPrivateKey;
decodedDsaPrivateKey.BERDecode(StringStore(encodedDsaPrivateKey).Ref());
DSA::PublicKey decodedDsaPublicKey;
decodedDsaPublicKey.BERDecode(StringStore(encodedDsaPublicKey).Ref());

if (!decodedDsaPrivateKey.Validate(rng, 3) || !decodedDsaPublicKey.Validate(rng, 3))
{
cerr << "DSA key encode/decode failed.\n";
abort();
}
cout << "4. DSA key encode/decode succeeded.\n";

// sign and verify
byte signature[40];
DSA::Signer signer(dsaPrivateKey);
assert(signer.SignatureLength() == 40);
signer.SignMessage(rng, message, 3, signature);

DSA::Verifier verifier(dsaPublicKey);
if (!verifier.VerifyMessage(message, 3, signature, sizeof(signature)))
{
cerr << "DSA signature and verification failed.\n";
abort();
}
cout << "5. DSA signature and verification succeeded.\n";


// try to verify an invalid signature
signature[0] ^= 1;
if (verifier.VerifyMessage(message, 3, signature, sizeof(signature)))
{
cerr << "DSA signature verification failed to detect bad signature.\n";
abort();
}
cout << "6. DSA signature verification successfully detected bad signature.\n";

// try to use an invalid key length
try
{
ECB_Mode<DES_EDE3>::Encryption encryption_DES_EDE3_ECB;
encryption_DES_EDE3_ECB.SetKey(key, 5);

// should not be here
cerr << "DES-EDE3 implementation did not detect use of invalid key length.\n";
abort();
}
catch (InvalidArgument &e)
{
cout << "7. Caught expected exception when using invalid key length. Exception message follows: ";
cout << e.what() << endl;
}

cout << "\nFIPS 140-2 Sample Application completed normally.\n";
#endif
}

6 个人使用总结

6.1 综合3种引入方式,最方便,最不易出错的方式为“Static方式”;

6.2 DLL-Import引入方式,个人最不推荐,因为3.2所述原因,它可能导致整个工程编译不过;