Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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)如何实现?

下一节,对称算法实现。