4.10 CryptoFactory架构:密码算法的“万能适配器“
一个问题:如何支持多种密码库?
假设你正在设计SoftHSM2。
你已经决定使用现有的密码库来实现密码算法,而不是自己写AES、RSA等算法。
但你面临一个问题:
应该用哪个密码库?
- OpenSSL:广泛使用,兼容性好
- Botan:现代设计,功能丰富
- 也许还有其他选项?
更深层的问题是:
如果用户想换密码库,怎么办?
“万能适配器“的设计思路
想象你在设计一个电器:
电器适配器类比:
问题:
├── 不同国家的插座不同
├── 美国插座:两扁脚
├── 欧洲插座:两圆脚
├── 英国插座:三方脚
└── 电器怎么适应所有插座?
解决方案:
├── 设计万能适配器
├── 电器内部电路不变
├── 只需更换适配器头
└── 用户可以选择适合的适配器
CryptoFactory就是这样的"万能适配器":
├── SoftHSM2核心逻辑不变
├── 只需更换密码后端
├── 用户可以选择OpenSSL或Botan
└── 甚至可以添加新的后端
为什么需要CryptoFactory?
SoftHSM2支持两种密码后端:
- Botan:开源密码库,功能丰富,C++原生设计
- OpenSSL:广泛使用的密码库,兼容性好
CryptoFactory是密码算法的抽象层,让SoftHSM2可以切换不同的密码后端,而不需要修改核心逻辑。
密码引擎架构:
SoftHSM核心逻辑(电器内部电路)
│
│ 不关心具体密码库
│ 只关心"加密"、"签名"等抽象操作
│
│ 调用
▼
CryptoFactory(万能适配器)
│
│ 根据配置选择后端
│
├── BotanCryptoFactory → Botan密码库
│ ├── BotanAES
│ ├── BotanRSA
│ ├── BotanSHA256
│ └── ...
│
└── OSSLCryptoFactory → OpenSSL密码库
├── OSSLAES
├── OSSLRSA
├── OSSLSHA256
└── ...
CryptoFactory类设计
CryptoFactory是抽象工厂模式的核心:
class CryptoFactory
{
public:
// 单例访问
static CryptoFactory* i();
static void reset();
// 初始化(选择适配器类型)
CK_RV init();
CK_RV finalize();
// 获取算法实例(获取具体设备)
// 对称算法(AES等)
SymmetricAlgorithm* getSymmetricAlgorithm(SymAlgo::Type type);
void recycleSymmetricAlgorithm(SymmetricAlgorithm* algo);
// 非对称算法(RSA等)
AsymmetricAlgorithm* getAsymmetricAlgorithm(AsymAlgo::Type type);
void recycleAsymmetricAlgorithm(AsymmetricAlgorithm* algo);
// 哈希算法(SHA等)
HashAlgorithm* getHashAlgorithm(HashAlgo::Type type);
void recycleHashAlgorithm(HashAlgorithm* algo);
// MAC算法(HMAC等)
MacAlgorithm* getMacAlgorithm(MacAlgo::Type type);
void recycleMacAlgorithm(MacAlgorithm* algo);
// 随机数生成器
RNG* getRNG();
void recycleRNG(RNG* rng);
private:
// 当前使用的后端
BackendType backend;
// 后端工厂实例
BotanCryptoFactory* botanFactory;
OSSLCryptoFactory* osslFactory;
};
后端选择机制
用户编译时选择使用哪个密码后端(编译时选项,不支持运行时切换):
CK_RV CryptoFactory::init()
{
// 实际SoftHSM2通过编译时CMake选项选择后端:
// --with-crypto-backend=botan
// --with-crypto-backend=openssl
// 以下为教学示意,展示两种后端各自的初始化路径
#if defined(USE_BOTAN_BACKEND)
backend = BACKEND_BOTAN;
botanFactory = new BotanCryptoFactory();
botanFactory->init();
#elif defined(USE_OPENSSL_BACKEND)
backend = BACKEND_OPENSSL;
osslFactory = new OSSLCryptoFactory();
osslFactory->init();
#else
// 默认使用Botan
backend = BACKEND_BOTAN;
botanFactory = new BotanCryptoFactory();
botanFactory->init();
#endif
return CKR_OK;
}
编译时选择后端(SoftHSM2通过CMake选项选择,不支持运行时切换):
# 编译命令(二选一,编译时确定)
# 使用Botan后端
cmake .. -DWITH_CRYPTO_BACKEND=botan
# 使用OpenSSL后端
cmake .. -DWITH_CRYPTO_BACKEND=openssl
算法实例获取
CryptoFactory根据后端类型返回对应的算法实例:
SymmetricAlgorithm* CryptoFactory::getSymmetricAlgorithm(SymAlgo::Type type)
{
SymmetricAlgorithm* algo = NULL;
#if defined(USE_BOTAN_BACKEND)
algo = botanFactory->getSymmetricAlgorithm(type);
#elif defined(USE_OPENSSL_BACKEND)
algo = osslFactory->getSymmetricAlgorithm(type);
#endif
return algo;
}
void CryptoFactory::recycleSymmetricAlgorithm(SymmetricAlgorithm* algo)
{
// 回收算法实例(归还设备)
#if defined(USE_BOTAN_BACKEND)
botanFactory->recycleSymmetricAlgorithm(algo);
#elif defined(USE_OPENSSL_BACKEND)
osslFactory->recycleSymmetricAlgorithm(algo);
#endif
}
算法实例的生命周期
算法实例的使用遵循“获取-使用-归还“模式:
// 在C_Encrypt中的使用示例
CK_RV SoftHSM::C_Encrypt(...)
{
// 1. 获取算法实例(借用设备)
SymmetricAlgorithm* algo = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES);
if (algo == NULL) {
return CKR_MECHANISM_INVALID;
}
// 2. 使用算法实例(使用设备)
algo->encryptInit(key, mode, iv);
algo->encryptUpdate(data, encrypted);
algo->encryptFinal(encrypted);
// 3. 回收算法实例(归还设备)
CryptoFactory::i()->recycleSymmetricAlgorithm(algo);
return CKR_OK;
}
为什么需要回收?
算法实例回收原因:
问题:
├── 每次加密都创建新实例
├── 实例包含内部状态(加密上下文)
├── 不回收会导致内存泄漏
└── 大量操作会耗尽内存
解决方案:
├── 使用后回收实例
├── 工厂可以重用实例(缓存池)
├── 或直接销毁实例
└── 防止内存泄漏
类比:
├── 借用设备后归还
├── 下次可以再借用
├── 不归还设备会被占满
└── 工厂可以维护设备池
BotanCryptoFactory实现
BotanCryptoFactory使用Botan密码库:
class BotanCryptoFactory
{
public:
SymmetricAlgorithm* getSymmetricAlgorithm(SymAlgo::Type type)
{
switch (type) {
case SymAlgo::AES:
return new BotanAES();
case SymAlgo::DES:
return new BotanDES();
case SymAlgo::DES3:
return new BotanDES3();
default:
return NULL;
}
}
AsymmetricAlgorithm* getAsymmetricAlgorithm(AsymAlgo::Type type)
{
switch (type) {
case AsymAlgo::RSA:
return new BotanRSA();
case AsymAlgo::DSA:
return new BotanDSA();
case AsymAlgo::ECDSA:
return new BotanECDSA();
case AsymAlgo::ECDH:
return new BotanECDH();
default:
return NULL;
}
}
HashAlgorithm* getHashAlgorithm(HashAlgo::Type type)
{
switch (type) {
case HashAlgo::SHA1:
return new BotanSHA1();
case HashAlgo::SHA256:
return new BotanSHA256();
case HashAlgo::SHA384:
return new BotanSHA384();
case HashAlgo::SHA512:
return new BotanSHA512();
default:
return NULL;
}
}
RNG* getRNG()
{
return new BotanRNG();
}
};
OSSLCryptoFactory实现
OSSLCryptoFactory使用OpenSSL密码库:
class OSSLCryptoFactory
{
public:
SymmetricAlgorithm* getSymmetricAlgorithm(SymAlgo::Type type)
{
switch (type) {
case SymAlgo::AES:
return new OSSLAES();
case SymAlgo::DES:
return new OSSLDES();
case SymAlgo::DES3:
return new OSSLDES3();
default:
return NULL;
}
}
AsymmetricAlgorithm* getAsymmetricAlgorithm(AsymAlgo::Type type)
{
switch (type) {
case AsymAlgo::RSA:
return new OSSLRSA();
case AsymAlgo::DSA:
return new OSSLDSA();
case AsymAlgo::ECDSA:
return new OSSLECDSA();
case AsymAlgo::ECDH:
return new OSSLECDH();
default:
return NULL;
}
}
HashAlgorithm* getHashAlgorithm(HashAlgo::Type type)
{
switch (type) {
case HashAlgo::SHA1:
return new OSSLSHA1();
case HashAlgo::SHA256:
return new OSSLSHA256();
case HashAlgo::SHA384:
return new OSSLSHA384();
case HashAlgo::SHA512:
return new OSSLSHA512();
default:
return NULL;
}
}
RNG* getRNG()
{
return new OSSLRNG();
}
};
Botan vs OpenSSL对比
两种后端各有特点:
Botan vs OpenSSL对比:
特性 Botan OpenSSL
────────────────────────────────────────────────────
设计风格 现代C++ 传统C+封装
API风格 面向对象 函数式EVP
内存管理 RAII自动 手动管理
类型安全 强类型 void指针
线程安全 内置支持 需要配置
编译复杂度 较高 较低
广泛度 较少 广泛使用
兼容性 Linux为主 跨平台
────────────────────────────────────────────────────
选择建议:
├── Botan:现代设计,C++原生,适合学习
├── OpenSSL:广泛部署,兼容性好,适合生产
└── 两者功能上等效
一个类比:万能插座适配器
万能插座适配器类比:
电器(SoftHSM2核心)
│
├── 内部电路(核心逻辑)
│ ├── 加密请求
│ ├── 签名请求
│ └── 不关心具体电源
│
├── 万能适配器(CryptoFactory)
│ │
│ ├── 根据地区选择适配器头
│ │
│ ├── Botan适配器头(美国插座)
│ │ ├── AES插头
│ │ ├── RSA插头
│ │ ├── SHA插头
│ │ └── RNG插头
│ │
│ └── OpenSSL适配器头(欧洲插座)
│ ├── AES插头
│ ├── RSA插头
│ ├── SHA插头
│ └── RNG插头
│
├── 使用流程:
│ ├── 配置选择适配器头(选择地区)
│ ├── 借用插头(获取算法实例)
│ ├── 使用插头(执行密码操作)
│ └── 归还插头(回收算法实例)
│
└── 优势:
├── 电器内部电路不变
├── 只需更换适配器头
├── 用户可以选择适合的后端
└── 可以添加新的后端
本篇小结
CryptoFactory是密码算法的抽象层:
设计目的:
- 支持多种密码后端(Botan、OpenSSL)
- 核心逻辑不变,只需更换后端
- 用户可以配置选择后端
工厂模式:
- CryptoFactory:抽象工厂
- BotanCryptoFactory:Botan后端工厂
- OSSLCryptoFactory:OpenSSL后端工厂
算法实例管理:
- getSymmetricAlgorithm:获取对称算法
- getAsymmetricAlgorithm:获取非对称算法
- getHashAlgorithm:获取哈希算法
- recycle*:回收算法实例
使用流程:
- 获取算法实例(借用设备)
- 使用算法实例(执行操作)
- 回收算法实例(归还设备)
Botan vs OpenSSL:
- Botan:现代C++设计,面向对象
- OpenSSL:广泛部署,兼容性好
- 功能上等效
下一节,我们将分析对称算法实现——AES如何在Botan和OpenSSL中实现。
【下集预告】
AES加密如何实现?
BotanAES与OSSLAES的区别?
加密模式(CBC/ECB/GCM)如何支持?
密钥包装(Key Wrap)如何实现?
下一节,对称算法实现。