对称密码

概念介绍

对称密码就是加密和解密使用同一个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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值