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.11 对称算法实现:AES与DES的密码引擎

对称算法家族

SoftHSM2支持的对称算法:

对称算法家族:

SymmetricAlgorithm(抽象基类)
│
├── AES
│   ├── BotanAES  (Botan实现)
│   └── OSSLAES   (OpenSSL实现)
│   └── 支持模式:CBC, ECB, CTR, GCM, CFB, OFB
│   └── 密钥长度:128, 192, 256位
│
├── DES
│   ├── BotanDES  (Botan实现)
│   └── OSSLDES   (OpenSSL实现)
│   └── 支持模式:CBC, ECB
│   └── 密钥长度:64位
│
└── DES3 (Triple DES)
    ├── BotanDES  (Botan实现)
    └── OSSLDES   (OpenSSL实现)
    └── 支持模式:CBC, ECB
    └── 密钥长度:128, 192位

SymmetricAlgorithm抽象类

SymmetricAlgorithm定义了对称加密的通用接口:

struct SymAlgo
{
    enum Type
    {
        Unknown,
        AES,
        DES,
        DES3
    };
};

struct SymMode
{
    enum Type
    {
        Unknown,
        CBC,    // Cipher Block Chaining
        CFB,    // Cipher Feedback
        CTR,    // Counter
        ECB,    // Electronic Codebook
        GCM,    // Galois/Counter Mode
        OFB     // Output Feedback
    };
};

struct SymWrap
{
    enum Type
    {
        Unknown,
        AES_KEYWRAP,
        AES_KEYWRAP_PAD
    };
};

class SymmetricAlgorithm
{
public:
    SymmetricAlgorithm();
    virtual ~SymmetricAlgorithm() { }
    
    virtual bool encryptInit(const SymmetricKey* key, 
                              const SymMode::Type mode,
                              const ByteString& IV,
                              bool padding = true,
                              size_t counterBits = 0,
                              const ByteString& aad = ByteString(),
                              size_t tagBytes = 0);
    
    virtual bool encryptUpdate(const ByteString& data, 
                                ByteString& encryptedData);
    
    virtual bool encryptFinal(ByteString& encryptedData);
    
    virtual bool decryptInit(const SymmetricKey* key, 
                              const SymMode::Type mode,
                              const ByteString& IV,
                              bool padding = true,
                              size_t counterBits = 0,
                              const ByteString& aad = ByteString(),
                              size_t tagBytes = 0);
    
    virtual bool decryptUpdate(const ByteString& encryptedData, 
                                ByteString& data);
    
    virtual bool decryptFinal(ByteString& data);
    
    virtual bool wrapKey(const SymmetricKey* key, 
                          const SymWrap::Type mode,
                          const ByteString& in, 
                          ByteString& out) = 0;
    
    virtual bool unwrapKey(const SymmetricKey* key, 
                            const SymWrap::Type mode,
                            const ByteString& in, 
                            ByteString& out) = 0;
    
    virtual size_t getBlockSize() const = 0;
    
protected:
    const SymmetricKey* currentKey;
    SymMode::Type currentCipherMode;
    bool currentPaddingMode;
    size_t currentCounterBits;
    size_t currentTagBytes;
    
    enum { NONE, ENCRYPT, DECRYPT } currentOperation;
};

加密模式详解

CBC(Cipher Block Chaining)

CBC加密模式:

明文块
    │
    │ P1     P2     P3
    │        │      │
    ▼        ▼      ▼
┌───────┐ ┌───────┐ ┌───────┐
│ XOR   │ │ XOR   │ │ XOR   │
│ IV    │ │ C1    │ │ C2    │
└───────┘ └───────┘ └───────┘
    │        │      │
    │        │      │
    ▼        ▼      ▼
┌───────┐ ┌───────┐ ┌───────┐
│ AES   │ │ AES   │ │ AES   │
│ Enc   │ │ Enc   │ │ Enc   │
└───────┘ └───────┘ └───────┘
    │        │      │
    ▼        ▼      ▼
    C1       C2     C3

特点:
- 每个明文块与前一个密文块异或后加密
- 需要IV(初始向量)
- 相同明文产生不同密文
- 需要填充(PKCS#7)

ECB(Electronic Codebook)

ECB加密模式:

明文块
    │
    │ P1     P2     P3
    │        │      │
    ▼        ▼      ▼
┌───────┐ ┌───────┐ ┌───────┐
│ AES   │ │ AES   │ │ AES   │
│ Enc   │ │ Enc   │ │ Enc   │
└───────┘ └───────┘ └───────┘
    │        │      │
    ▼        ▼      ▼
    C1       C2     C3

特点:
- 每个明文块独立加密
- 不需要IV
- 相同明文产生相同密文(不安全)
- 需要填充

GCM(Galois/Counter Mode)

GCM加密模式:

特点:
- AEAD模式(认证加密)
- 不需要填充
- 生成认证标签
- 支持附加数据(AAD)

加密:
┌─────────────────────────────────────┐
│                                     │
│  IV + Counter → AES Enc → C1       │
│  IV + Counter+1 → AES Enc → C2     │
│  ...                                │
│                                     │
│  计算GMAC标签                       │
│                                     │
└─────────────────────────────────────┘

输出:
- 密文数据
- 认证标签

SymmetricKey类

SymmetricKey是对称密钥的抽象:

class SymmetricKey : public Serialisable
{
public:
    explicit SymmetricKey(size_t inBitLen = 0);
    
    virtual bool setKeyBits(const ByteString& keybits);
    virtual const ByteString& getKeyBits() const;
    virtual ByteString getKeyCheckValue() const;
    
    virtual ByteString serialise() const;
    
    virtual void setBitLen(const size_t inBitLen);
    virtual size_t getBitLen() const;

protected:
    ByteString keyData;   // 密钥数据
    size_t bitLen;        // 密钥长度(位)
};

AESKey类

class AESKey : public SymmetricKey
{
public:
    AESKey(size_t inBitLen = 0) : SymmetricKey(inBitLen) { }
    
    virtual ByteString getKeyCheckValue() const;
};

ByteString AESKey::getKeyCheckValue() const
{
    // KCV = AES-ECB(密钥, 0x0000000000000000)的前3字节
    // 用于验证密钥是否正确导入
    
    ByteString zeroBlock(16);  // 16字节全零
    
    // 调用AES加密
    SymmetricAlgorithm* aes = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES);
    aes->encryptInit(this, SymMode::ECB, ByteString(), false);
    
    ByteString kcv;
    aes->encryptUpdate(zeroBlock, kcv);
    aes->encryptFinal(kcv);
    
    CryptoFactory::i()->recycleSymmetricAlgorithm(aes);
    
    // 返回前3字节
    return kcv.substr(0, 3);
}

BotanAES实现

BotanAES使用Botan密码库实现AES:

class BotanAES : public BotanSymmetricAlgorithm
{
public:
    virtual ~BotanAES() { }
    
    virtual bool wrapKey(const SymmetricKey* key, 
                          const SymWrap::Type mode,
                          const ByteString& in, 
                          ByteString& out);
    
    virtual bool unwrapKey(const SymmetricKey* key, 
                            const SymWrap::Type mode,
                            const ByteString& in, 
                            ByteString& out);
    
    virtual size_t getBlockSize() const { return 16; }
    
protected:
    virtual std::string getCipher() const;
};

size_t BotanAES::getBlockSize() const
{
    return 16;  // AES块大小固定为16字节
}

std::string BotanAES::getCipher() const
{
    // 根据密钥长度和模式返回Botan cipher字符串
    
    size_t keyBits = currentKey->getBitLen();
    std::string cipherName;
    
    // 基础名称
    cipherName = "AES-" + std::to_string(keyBits);
    
    // 添加模式
    switch (currentCipherMode) {
        case SymMode::CBC:
            cipherName += "/CBC";
            break;
        case SymMode::ECB:
            cipherName += "/ECB";
            break;
        case SymMode::CTR:
            cipherName += "/CTR-BE";
            break;
        case SymMode::GCM:
            cipherName += "/GCM";
            break;
        case SymMode::CFB:
            cipherName += "/CFB";
            break;
        case SymMode::OFB:
            cipherName += "/OFB";
            break;
        default:
            return "";
    }
    
    // 添加填充
    if (currentPaddingMode) {
        cipherName += "/PKCS7";
    } else {
        cipherName += "/NoPadding";
    }
    
    return cipherName;
}

Botan加密实现

bool BotanSymmetricAlgorithm::encryptInit(const SymmetricKey* key, 
                                           const SymMode::Type mode,
                                           const ByteString& IV,
                                           bool padding,
                                           size_t counterBits,
                                           const ByteString& aad,
                                           size_t tagBytes)
{
    currentKey = key;
    currentCipherMode = mode;
    currentPaddingMode = padding;
    currentCounterBits = counterBits;
    currentTagBytes = tagBytes;
    currentOperation = ENCRYPT;
    
    // 获取cipher名称
    std::string cipherName = getCipher();
    
    // 创建Botan cipher对象
    Botan::Cipher_Mode* cipher = Botan::Cipher_Mode::create(cipherName, Botan::ENCRYPTION);
    if (cipher == NULL) {
        return false;
    }
    
    // 设置密钥
    cipher->set_key(Botan::SymmetricKey(key->getKeyBits().byte_str(), key->getKeyBits().size()));
    
    // 设置IV
    cipher->start(IV.byte_str(), IV.size());
    
    // GCM模式设置AAD
    if (mode == SymMode::GCM && aad.size() > 0) {
        cipher->process(aad.byte_str(), aad.size());
    }
    
    return true;
}

bool BotanSymmetricAlgorithm::encryptUpdate(const ByteString& data, 
                                             ByteString& encryptedData)
{
    if (currentOperation != ENCRYPT) {
        return false;
    }
    
    // Botan一次性加密
    Botan::SecureVector<Botan::byte> buffer;
    buffer.resize(data.size() + getBlockSize());
    
    cipher->process(data.byte_str(), data.size(), buffer, Botan::ENCRYPTION);
    
    encryptedData = ByteString(buffer.begin(), buffer.size());
    
    return true;
}

OSSLAES实现

OSSLAES使用OpenSSL EVP API:

class OSSLAES : public OSSLEVPSymmetricAlgorithm
{
public:
    virtual ~OSSLAES() { }
    
    virtual bool wrapKey(const SymmetricKey* key, 
                          const SymWrap::Type mode,
                          const ByteString& in, 
                          ByteString& out);
    
    virtual bool unwrapKey(const SymmetricKey* key, 
                            const SymWrap::Type mode,
                            const ByteString& in, 
                            ByteString& out);
    
    virtual size_t getBlockSize() const { return 16; }
    
protected:
    virtual const EVP_CIPHER* getCipher() const;
};

const EVP_CIPHER* OSSLAES::getCipher() const
{
    // 根据密钥长度和模式返回EVP_CIPHER
    
    size_t keyBits = currentKey->getBitLen();
    
    switch (currentCipherMode) {
        case SymMode::CBC:
            if (keyBits == 128) return EVP_aes_128_cbc();
            if (keyBits == 192) return EVP_aes_192_cbc();
            if (keyBits == 256) return EVP_aes_256_cbc();
            break;
            
        case SymMode::ECB:
            if (keyBits == 128) return EVP_aes_128_ecb();
            if (keyBits == 192) return EVP_aes_192_ecb();
            if (keyBits == 256) return EVP_aes_256_ecb();
            break;
            
        case SymMode::CTR:
            if (keyBits == 128) return EVP_aes_128_ctr();
            if (keyBits == 192) return EVP_aes_192_ctr();
            if (keyBits == 256) return EVP_aes_256_ctr();
            break;
            
        case SymMode::GCM:
            if (keyBits == 128) return EVP_aes_128_gcm();
            if (keyBits == 192) return EVP_aes_192_gcm();
            if (keyBits == 256) return EVP_aes_256_gcm();
            break;
            
        default:
            return NULL;
    }
    
    return NULL;
}

OpenSSL EVP加密实现

bool OSSLEVPSymmetricAlgorithm::encryptInit(const SymmetricKey* key, 
                                              const SymMode::Type mode,
                                              const ByteString& IV,
                                              bool padding,
                                              size_t counterBits,
                                              const ByteString& aad,
                                              size_t tagBytes)
{
    currentKey = key;
    currentCipherMode = mode;
    currentPaddingMode = padding;
    currentTagBytes = tagBytes;
    currentOperation = ENCRYPT;
    
    // 获取EVP_CIPHER
    const EVP_CIPHER* cipher = getCipher();
    if (cipher == NULL) {
        return false;
    }
    
    // 创建EVP_CTX
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    if (ctx == NULL) {
        return false;
    }
    
    // 初始化加密
    if (EVP_EncryptInit_ex(ctx, cipher, NULL, 
                           key->getKeyBits().byte_str(), 
                           IV.byte_str()) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return false;
    }
    
    // 设置填充
    EVP_CIPHER_CTX_set_padding(ctx, padding ? 1 : 0);
    
    // GCM模式设置IV长度和AAD
    if (mode == SymMode::GCM) {
        EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, IV.size(), NULL);
        
        if (aad.size() > 0) {
            int len;
            EVP_EncryptUpdate(ctx, NULL, &len, aad.byte_str(), aad.size());
        }
    }
    
    cipherCtx = ctx;
    return true;
}

bool OSSLEVPSymmetricAlgorithm::encryptUpdate(const ByteString& data, 
                                               ByteString& encryptedData)
{
    if (currentOperation != ENCRYPT) {
        return false;
    }
    
    int outlen;
    int maxLen = data.size() + getBlockSize();
    
    unsigned char* buffer = new unsigned char[maxLen];
    
    // 加密数据
    if (EVP_EncryptUpdate(cipherCtx, buffer, &outlen, 
                          data.byte_str(), data.size()) != 1) {
        delete[] buffer;
        return false;
    }
    
    encryptedData = ByteString(buffer, outlen);
    delete[] buffer;
    
    return true;
}

bool OSSLEVPSymmetricAlgorithm::encryptFinal(ByteString& encryptedData)
{
    int outlen;
    unsigned char buffer[getBlockSize()];
    
    // 完成加密
    if (EVP_EncryptFinal_ex(cipherCtx, buffer, &outlen) != 1) {
        return false;
    }
    
    encryptedData += ByteString(buffer, outlen);
    
    // GCM模式获取标签
    if (currentCipherMode == SymMode::GCM) {
        unsigned char tag[16];
        EVP_CIPHER_CTX_ctrl(cipherCtx, EVP_CTRL_GCM_GET_TAG, currentTagBytes, tag);
        encryptedData += ByteString(tag, currentTagBytes);
    }
    
    EVP_CIPHER_CTX_free(cipherCtx);
    cipherCtx = NULL;
    
    return true;
}

密钥包装(Key Wrap)

AES密钥包装用于安全导出密钥:

bool OSSLAES::wrapKey(const SymmetricKey* key, 
                       const SymWrap::Type mode,
                       const ByteString& in, 
                       ByteString& out)
{
    const EVP_CIPHER* wrapCipher = getWrapCipher(mode, key);
    if (wrapCipher == NULL) {
        return false;
    }
    
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    
    // 初始化包装
    EVP_EncryptInit_ex(ctx, wrapCipher, NULL, 
                       key->getKeyBits().byte_str(), NULL);
    
    int outlen;
    int maxLen = in.size() + 16;
    unsigned char* buffer = new unsigned char[maxLen];
    
    // 执行包装
    EVP_EncryptUpdate(ctx, buffer, &outlen, in.byte_str(), in.size());
    int finallen;
    EVP_EncryptFinal_ex(ctx, buffer + outlen, &finallen);
    
    out = ByteString(buffer, outlen + finallen);
    
    delete[] buffer;
    EVP_CIPHER_CTX_free(ctx);
    
    return true;
}

const EVP_CIPHER* OSSLAES::getWrapCipher(const SymWrap::Type mode, 
                                          const SymmetricKey* key) const
{
    size_t keyBits = key->getBitLen();
    
    if (mode == SymWrap::AES_KEYWRAP) {
        if (keyBits == 128) return EVP_aes_128_wrap();
        if (keyBits == 192) return EVP_aes_192_wrap();
        if (keyBits == 256) return EVP_aes_256_wrap();
    } else if (mode == SymWrap::AES_KEYWRAP_PAD) {
        if (keyBits == 128) return EVP_aes_128_wrap_pad();
        if (keyBits == 192) return EVP_aes_192_wrap_pad();
        if (keyBits == 256) return EVP_aes_256_wrap_pad();
    }
    
    return NULL;
}

DES实现

DES和3DES实现类似AES:

class BotanDES : public BotanSymmetricAlgorithm
{
public:
    virtual size_t getBlockSize() const { return 8; }  // DES块大小8字节
    
protected:
    virtual std::string getCipher() const;
};

std::string BotanDES::getCipher() const
{
    std::string cipherName;
    
    if (currentKey->getBitLen() == 64) {
        cipherName = "DES";
    } else if (currentKey->getBitLen() == 128) {
        cipherName = "TripleDES-2key";  // 2-key 3DES
    } else if (currentKey->getBitLen() == 192) {
        cipherName = "TripleDES-3key";  // 3-key 3DES
    }
    
    switch (currentCipherMode) {
        case SymMode::CBC:
            cipherName += "/CBC/PKCS7";
            break;
        case SymMode::ECB:
            cipherName += "/ECB/PKCS7";
            break;
        default:
            return "";
    }
    
    return cipherName;
}

对称加密完整流程

对称加密完整流程:

C_GenerateKey
    │
    │ CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES)
    │ algo->generateKey(key, rng)
    ▼
密钥创建(AESKey对象)
    │
    │ C_EncryptInit
    │ CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES)
    │ algo->encryptInit(key, mode, IV)
    ▼
加密初始化
    │
    │ C_Encrypt
    │ algo->encryptUpdate(data, encrypted)
    ▼
加密数据
    │
    │ C_EncryptFinal
    │ algo->encryptFinal(encrypted)
    ▼
加密完成
    │
    │ CryptoFactory::i()->recycleSymmetricAlgorithm(algo)
    ▼
回收算法实例

一个类比:保险箱的密码锁

保险箱密码锁类比:

密码锁(对称算法)
│
├── 密钥
│   ├── AESKey:128位密码(16字符)
│   ├── AESKey:256位密码(32字符)
│   └── DESKey:64位密码(8字符)
│
├── 加密模式(锁的工作方式)
│   │
│   ├── CBC模式(链式锁)
│   │   ├── 每次开锁依赖上次结果
│   │   ├── 需要初始状态(IV)
│   │   └── 相同密码每次产生不同结果
│   │
│   ├── ECB模式(独立锁)
│   │   ├── 每次开锁独立工作
│   │   ├── 不需要初始状态
│   │   ├── 相同密码产生相同结果(不安全)
│   │
│   └── GCM模式(认证锁)
│   │   ├── 加密同时验证
│   │   ├── 产生认证标签
│   │   ├── 可附加额外验证数据
│   │
│   └── CTR模式(计数锁)
│   │   ├── 使用计数器加密
│   │   ├── 不需要填充
│   │   ├── 支持并行处理
│   │
│   └── OFB/CFB模式(流式锁)
│       ├── 输出反馈加密
│       ├── 流式加密
│       ├── 不需要填充
│
└── 操作流程
    ├── 设置密码(encryptInit)
    ├── 输入数据(encryptUpdate)
    ├── 输出结果(encryptFinal)
    └── 回收锁(recycleSymmetricAlgorithm)

本篇小结

今天我们分析了SoftHSM2的对称算法实现。

SymmetricAlgorithm抽象类

  • encryptInit/Update/Final:加密接口
  • decryptInit/Update/Final:解密接口
  • wrapKey/unwrapKey:密钥包装

加密模式

  • CBC:链式加密,需要IV和填充
  • ECB:独立加密,不安全
  • GCM:AEAD认证加密
  • CTR:计数器模式,无填充
  • CFB/OFB:流式加密

密钥类

  • SymmetricKey:密钥基类
  • AESKey:AES密钥,支持KCV
  • DESKey/DES3Key:DES密钥

Botan实现

  • getCipher()返回Botan cipher字符串
  • Botan::Cipher_Mode::create()创建cipher
  • C++原生API

OpenSSL实现

  • getCipher()返回EVP_CIPHER指针
  • EVP_EncryptInit/Update/Final API
  • 需要手动管理EVP_CIPHER_CTX

密钥包装

  • AES_KEYWRAP:标准密钥包装
  • AES_KEYWRAP_PAD:填充密钥包装

下一节,我们将分析非对称算法实现——RSA、ECDSA如何在Botan/OpenSSL中实现。

【下集预告】

非对称算法如何实现?

RSA签名/验证如何工作?

ECDSA密钥生成如何实现?

公钥/私钥类如何设计?

下一节,非对称算法实现。