消息认证码 hmac

概念介绍

hmac (hash message authentication code) 是用来确认消息的完整性及认证消息的发送者的技术

  1. 完整性,是通过判断hash值来确定的
  2. 认证,是通过对称密码的密钥来完成的

因为是对称密码,所以发送发和接收方事先需要共享密钥

公式:

hmac = hash(msg, key)

发送方发送 msg + hmac
接收方利用公式 hash(msg, key)计算出hmac,然后与接收到的hmac进行对比,如果相同则可确定消息没有被篡改,且是发送者发送的

macOS 上代码封装
头文件 Hmac.h

#ifndef Hmac_h
#define Hmac_h

#include <stdint.h>
#include <vector>

class Hmac final {
public:
    enum struct Algorithm {
        Md5,
        Sha1,
    };

public:
    typedef std::vector<uint8_t> Data;

public:
    static Data md5(const Data &msg, const Data &key);
    static Data sha1(const Data &msg, const Data &key);

public:
    ~Hmac();
    Hmac(Algorithm alg, const Data &key);
    Hmac(Hmac &&hmac) noexcept;
    Hmac &operator=(Hmac &&hmac) noexcept;

    void update(const Data &data);
    Data final();

private:
    struct HmacImpl *_impl = nullptr;
};

#endif /* Hmac_h */

实现文件 Hmac.cpp

#include "Hmac.h"
#include <CommonCrypto/CommonHMAC.h>
#include <assert.h>

struct HmacImpl final {
public:
    HmacImpl(Hmac::Algorithm alg, const void *key, size_t keyLength)
    {
        CCHmacAlgorithm hmacAlg;
        switch (alg) {
        case Hmac::Algorithm::Md5:
            hmacAlg = kCCHmacAlgMD5;
            _hmac.resize(CC_MD5_DIGEST_LENGTH);
            break;
        case Hmac::Algorithm::Sha1:
            hmacAlg = kCCHmacAlgSHA1;
            _hmac.resize(CC_SHA1_DIGEST_LENGTH);
            break;
        }
        CCHmacInit(&_ctx, hmacAlg, key, keyLength);
    }

    void update(const Hmac::Data &data)
    {
        CCHmacUpdate(&_ctx, data.data(), data.size());
    }

    Hmac::Data final()
    {
        CCHmacFinal(&_ctx, _hmac.data());
        return _hmac;
    }

private:
    CCHmacContext _ctx;
    Hmac::Data _hmac;
};

#pragma mark -

Hmac::~Hmac()
{
    delete _impl;
}

Hmac::Hmac(Algorithm alg, const Data &key)
    : _impl(new HmacImpl(alg, key.data(), key.size()))
{
}

Hmac::Hmac(Hmac &&hmac) noexcept : _impl(hmac._impl)
{
    hmac._impl = nullptr;
}

Hmac &Hmac::operator=(Hmac &&hmac) noexcept
{
    assert(&hmac != this);
    delete _impl;
    _impl = hmac._impl;
    hmac._impl = nullptr;
    return *this;
}

void Hmac::update(const Data &data)
{
    _impl->update(data);
}

Hmac::Data Hmac::final()
{
    return _impl->final();
}

#pragma mark -

Hmac::Data Hmac::md5(const Data &msg, const Data &key)
{
    Hmac md5(Algorithm::Md5, key);
    md5.update(msg);
    return md5.final();
}

Hmac::Data Hmac::sha1(const Data &msg, const Data &key)
{
    Hmac sha1(Algorithm::Sha1, key);
    sha1.update(msg);
    return sha1.final();
}

示例:

#include <string>
#include "Hmac.h"

int main()
{
    Hmac::Data key = { 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 }; // 一般是对称密码的密钥
    std::string msg = "hello, world";
    Hmac::Data data(msg.cbegin(), msg.cend());
    auto sha1_mac = Hmac::sha1(data, key);
    auto md5_mac = Hmac::md5(data, key);
    // ...
}
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页