概念介绍
对称密码就是加密和解密使用同一个key
对称密码算法有很多,但是现在只有AES (Advanced Encryption Standard) 是最常用的,其它像 DES, 3DES 等都已淘汰
AES是一种块密码算法,块密码算法只能对固定长度的数据进行加密,例如:AES的块长度是128位,即16字节。AES算法将一个明文块加密生成一个密文块,密文快的长度跟明文块相等,都为16字节。
如果要加密的数据比16字节长,就要进行分块加密,然后将密文块组合成完整的密文。
分块加密并组合有多种方法,称为mode。主要模式有ecb, cbc, cfb, ofb, ctr 等,但是最常用的只有两种:即 cbc 和 ctr,其它都已淘汰
代码
为方便使用,下面对苹果平台提供的对称密码库做个封装
头文件:Aes.h
#ifndef Aes_h
#define Aes_h
#include <stdint.h>
#include <vector>
class Aes final {
public:
enum struct Mode {
Cbc,
Ctr,
};
enum struct Operation {
Encrypt,
Decrypt,
};
enum {
KeySize128 = 16,
KeySize192 = 24,
KeySize256 = 32,
};
public:
typedef std::vector<uint8_t> Data;
public:
static Data encrypt_cbc_128(const Data &data, const uint8_t (&key)[KeySize128], const uint8_t (&iv)[16]);
static Data decrypt_cbc_128(const Data &data, const uint8_t (&key)[KeySize128], const uint8_t (&iv)[16]);
public:
~Aes();
Aes(Operation op, Mode mode, const uint8_t (&key)[KeySize128], const uint8_t (&iv)[16]);
Aes(Operation op, Mode mode, const uint8_t (&key)[KeySize192], const uint8_t (&iv)[16]);
Aes(Operation op, Mode mode, const uint8_t (&key)[KeySize256], const uint8_t (&iv)[16]);
Aes(Aes &&aes) noexcept;
Aes &operator=(Aes &&aes) noexcept;
Data update(const Data &data);
Data final();
void reset();
private:
struct AesImpl *_impl = nullptr;
};
#endif /* Aes_h */
实现文件:Aes.cpp
#include "Aes.h"
#include <CommonCrypto/CommonCryptor.h>
#include <assert.h>
struct AesImpl final {
public:
~AesImpl()
{
CCCryptorRelease(_cryptor);
}
AesImpl(Aes::Operation op, Aes::Mode mode, const void *key, size_t keyLength, const void *iv)
{
CCCryptorCreateWithMode(_operation(op), _mode(mode), kCCAlgorithmAES, ccPKCS7Padding, iv, key, keyLength, nullptr, 0, 0, 0, &_cryptor);
}
Aes::Data update(const Aes::Data &data)
{
size_t len = CCCryptorGetOutputLength(_cryptor, data.size(), false);
Aes::Data buf(len);
size_t size = 0;
CCCryptorUpdate(_cryptor, data.data(), data.size(), buf.data(), buf.size(), &size);
return buf;
}
Aes::Data final()
{
Aes::Data buf(kCCBlockSizeAES128);
size_t size = 0;
CCCryptorFinal(_cryptor, buf.data(), buf.size(), &size);
buf.resize(size);
return buf;
}
void reset()
{
CCCryptorReset(_cryptor, nullptr);
}
private:
constexpr CCOperation _operation(Aes::Operation op) const
{
switch (op) {
case Aes::Operation::Encrypt:
return kCCEncrypt;
case Aes::Operation::Decrypt:
return kCCDecrypt;
}
}
constexpr CCMode _mode(Aes::Mode mode) const
{
switch (mode) {
case Aes::Mode::Cbc:
return kCCModeCBC;
case Aes::Mode::Ctr:
return kCCModeCTR;
}
}
private:
CCCryptorRef _cryptor = nullptr;
};
#pragma mark -
Aes::~Aes()
{
delete _impl;
}
Aes::Aes(Operation op, Mode mode, const uint8_t (&key)[KeySize128], const uint8_t (&iv)[16])
: _impl(new AesImpl(op, mode, key, KeySize128, iv))
{
}
Aes::Aes(Operation op, Mode mode, const uint8_t (&key)[KeySize192], const uint8_t (&iv)[16])
: _impl(new AesImpl(op, mode, key, KeySize192, iv))
{
}
Aes::Aes(Operation op, Mode mode, const uint8_t (&key)[KeySize256], const uint8_t (&iv)[16])
: _impl(new AesImpl(op, mode, key, KeySize256, iv))
{
}
Aes::Aes(Aes &&aes) noexcept : _impl(aes._impl)
{
aes._impl = nullptr;
}
Aes &Aes::operator=(Aes &&aes) noexcept
{
assert(&aes != this);
delete _impl;
_impl = aes._impl;
aes._impl = nullptr;
return *this;
}
Aes::Data Aes::update(const Data &data)
{
return _impl->update(data);
}
Aes::Data Aes::final()
{
return _impl->final();
}
void Aes::reset()
{
return _impl->reset();
}
Aes::Data Aes::encrypt_cbc_128(const Data &data, const uint8_t (&key)[KeySize128], const uint8_t (&iv)[16])
{
Data buf;
Aes aes(Operation::Encrypt, Mode::Cbc, key, iv);
auto u = aes.update(data);;
buf.insert(buf.end(), u.cbegin(), u.cend());
auto f = aes.final();
buf.insert(buf.end(), f.cbegin(), f.cend());
return buf;
}
Aes::Data Aes::decrypt_cbc_128(const Data &data, const uint8_t (&key)[KeySize128], const uint8_t (&iv)[16])
{
Data buf;
Aes aes(Operation::Decrypt, Mode::Cbc, key, iv);
auto u = aes.update(data);;
buf.insert(buf.end(), u.cbegin(), u.cend());
auto f = aes.final();
buf.insert(buf.end(), f.cbegin(), f.cend());
return buf;
}
示例:main.cpp
#include <iostream>
#include <stdio.h>
#include <stdarg.h>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include "Aes.h"
std::string format(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int size = vsnprintf(nullptr, 0, fmt, ap) + 1;
va_end(ap);
char *buf = new char[size];
va_start(ap, fmt);
vsnprintf(buf, size, fmt, ap);
va_end(ap);
std::string fs(buf, size-1);
delete[] buf;
return fs;
}
std::string toHexString(const Aes::Data &data)
{
std::vector<std::string> svec;
std::transform(data.cbegin(), data.cend(), std::back_inserter(svec), [](auto byte) { return format("%02X", byte); });
return std::accumulate(svec.cbegin(), svec.cend(), std::string());
}
int main()
{
const uint8_t key[16] = { 0xa5, 0xc0, 0xda, 0xb7, 0x87, 0x45, 0xc7, 0x37, 0x95, 0x07, 0x2C, 0x96, 0x67, 0xae, 0x28, 0xf1 };
const uint8_t iv[16] = { 0xdb, 0x32, 0x9a, 0x66, 0x09, 0x8b, 0x67, 0xf7, 0xb5, 0xa7, 0x9f, 0x38, 0x57, 0xb9, 0x25, 0x41 };
std::string msg = "hello, world";
Aes::Data data(msg.cbegin(), msg.cend());
auto enc = Aes::encrypt_cbc_128(data, key, iv);
std::cout << toHexString(enc) << std::endl;
auto dec = Aes::decrypt_cbc_128(enc, key, iv);
std::cout << std::string(dec.cbegin(), dec.cend()) << std::endl;
}
运行输出:
$ ./a.out
BC0B8E8AF2458A300E08A350B48EE793
hello, world