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密钥生成如何实现?
公钥/私钥类如何设计?
下一节,非对称算法实现。