summaryrefslogtreecommitdiffstats
path: root/integrity_algo.cpp
blob: bac87d70e07961779ffd23b80c9f94d298e4ccac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "integrity_algo.hpp"

#include "message_parsers.hpp"

#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>

namespace cipher
{

namespace integrity
{

AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik) :
    Interface(SHA1_96_AUTHCODE_LENGTH)
{
    k1 = generateKn(sik, rmcp::const_1);
}

std::vector<uint8_t> AlgoSHA1::generateHMAC(const uint8_t* input,
                                            const size_t len) const
{
    std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
    unsigned int mdLen = 0;

    if (HMAC(EVP_sha1(), k1.data(), k1.size(), input, len, output.data(),
             &mdLen) == NULL)
    {
        throw std::runtime_error("Generating integrity data failed");
    }

    // HMAC generates Message Digest to the size of SHA_DIGEST_LENGTH, the
    // AuthCode field length is based on the integrity algorithm. So we are
    // interested only in the AuthCode field length of the generated Message
    // digest.
    output.resize(authCodeLength);

    return output;
}

bool AlgoSHA1::verifyIntegrityData(
    const std::vector<uint8_t>& packet, const size_t length,
    std::vector<uint8_t>::const_iterator integrityData) const
{

    auto output = generateHMAC(
        packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length);

    // Verify if the generated integrity data for the packet and the received
    // integrity data matches.
    return (std::equal(output.begin(), output.end(), integrityData));
}

std::vector<uint8_t>
    AlgoSHA1::generateIntegrityData(const std::vector<uint8_t>& packet) const
{
    return generateHMAC(
        packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
        packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
}

std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik,
                                          const rmcp::Const_n& const_n) const
{
    unsigned int mdLen = 0;
    std::vector<uint8_t> Kn(sik.size());

    // Generated Kn for the integrity algorithm with the additional key keyed
    // with SIK.
    if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), const_n.size(),
             Kn.data(), &mdLen) == NULL)
    {
        throw std::runtime_error("Generating KeyN for integrity "
                                 "algorithm failed");
    }
    return Kn;
}

AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik) :
    Interface(SHA256_128_AUTHCODE_LENGTH)
{
    k1 = generateKn(sik, rmcp::const_1);
}

std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input,
                                              const size_t len) const
{
    std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
    unsigned int mdLen = 0;

    if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len, output.data(),
             &mdLen) == NULL)
    {
        throw std::runtime_error("Generating HMAC_SHA256_128 failed");
    }

    // HMAC generates Message Digest to the size of SHA256_DIGEST_LENGTH, the
    // AuthCode field length is based on the integrity algorithm. So we are
    // interested only in the AuthCode field length of the generated Message
    // digest.
    output.resize(authCodeLength);

    return output;
}

bool AlgoSHA256::verifyIntegrityData(
    const std::vector<uint8_t>& packet, const size_t length,
    std::vector<uint8_t>::const_iterator integrityData) const
{

    auto output = generateHMAC(
        packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length);

    // Verify if the generated integrity data for the packet and the received
    // integrity data matches.
    return (std::equal(output.begin(), output.end(), integrityData));
}

std::vector<uint8_t>
    AlgoSHA256::generateIntegrityData(const std::vector<uint8_t>& packet) const
{
    return generateHMAC(
        packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
        packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
}

std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik,
                                            const rmcp::Const_n& const_n) const
{
    unsigned int mdLen = 0;
    std::vector<uint8_t> Kn(sik.size());

    // Generated Kn for the integrity algorithm with the additional key keyed
    // with SIK.
    if (HMAC(EVP_sha256(), sik.data(), sik.size(), const_n.data(),
             const_n.size(), Kn.data(), &mdLen) == NULL)
    {
        throw std::runtime_error("Generating KeyN for integrity "
                                 "algorithm HMAC_SHA256 failed");
    }
    return Kn;
}

} // namespace integrity

} // namespace cipher
OpenPOWER on IntegriCloud