crypto.cc 4.16 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#include "crypto.h"

Jelte Jansen's avatar
Jelte Jansen committed
17
18
19
20
21
#include <iostream>
#include <iomanip>

#include <botan/botan.h>
#include <botan/hmac.h>
22
#include <botan/hash.h>
Jelte Jansen's avatar
Jelte Jansen committed
23
24
25
26
#include <botan/types.h>

#include <dns/buffer.h>
#include <dns/name.h>
Jelte Jansen's avatar
Jelte Jansen committed
27
28
29
#include <dns/tsigkey.h>
#include <dns/util/base64.h>

Jelte Jansen's avatar
Jelte Jansen committed
30
31
32
33
34
#include <string>

using namespace std;
using namespace isc::dns;

Jelte Jansen's avatar
Jelte Jansen committed
35
namespace {
36
Botan::HashFunction* getHash(const Name& hash_name) {
37
    if (hash_name == TSIGKey::HMACMD5_NAME()) {
38
        return Botan::get_hash("MD5");
39
    } else if (hash_name == TSIGKey::HMACSHA1_NAME()) {
40
        return Botan::get_hash("SHA-1");
41
    } else if (hash_name == TSIGKey::HMACSHA256_NAME()) {
42
        return Botan::get_hash("SHA-256");
43
44
45
46
    } else {
        isc_throw(isc::crypto::UnsupportedAlgorithm,
                  "Unknown Hash type " + hash_name.toText());
    }
Jelte Jansen's avatar
Jelte Jansen committed
47
48
}

49
50
51
// Library needs to have been inited during the entire program
// should we make this a singleton? (for hsm we'll need more
// initialization, and dynamic loading)
52
Botan::LibraryInitializer init;
53

Jelte Jansen's avatar
Jelte Jansen committed
54
} // local namespace
Jelte Jansen's avatar
Jelte Jansen committed
55

56
57
58
namespace isc {
namespace crypto {

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class HMACImpl {
public:
    explicit HMACImpl(const TSIGKey& key) {
        Botan::HashFunction* hash = getHash(key.getAlgorithmName());
        hmac_ = new Botan::HMAC::HMAC(hash);

        // Take the 'secret' from the key
        // If the key length is larger than the block size, we hash the
        // key itself first.
        try {
            if (key.getSecretLength() > hash->HASH_BLOCK_SIZE) {
                Botan::SecureVector<Botan::byte> hashed_key =
                    hash->process(static_cast<const Botan::byte*>(key.getSecret()),
                                  key.getSecretLength());
                hmac_->set_key(hashed_key.begin(), hashed_key.size());
            } else {
                hmac_->set_key(static_cast<const Botan::byte*>(key.getSecret()),
                             key.getSecretLength());
            }
        } catch (Botan::Invalid_Key_Length ikl) {
            isc_throw(BadKey, ikl.what());
80
        }
81
    }
Jelte Jansen's avatar
Jelte Jansen committed
82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    ~HMACImpl() { delete hmac_; }

    void update(const void* data, size_t len) {
        // update the data from whatever we get (probably as a buffer)
        hmac_->update(static_cast<const Botan::byte*>(data), len);
    }

    void sign(isc::dns::OutputBuffer& result) {
        // And generate the mac
        Botan::SecureVector<Botan::byte> b_result(hmac_->final());
    
        // write mac to result
        result.writeData(b_result.begin(), b_result.size());
    }
    
    bool verify(const void* sig, size_t len) {
99
        return (hmac_->verify_mac(static_cast<const Botan::byte*>(sig), len));
100
101
102
103
104
105
106
107
108
    }

private:
    Botan::HMAC* hmac_;
};

HMAC::HMAC(const TSIGKey& key) {
    impl_ = new HMACImpl(key);
}
Jelte Jansen's avatar
Jelte Jansen committed
109

110
111
112
HMAC::~HMAC() {
    delete impl_;
}
Jelte Jansen's avatar
Jelte Jansen committed
113

114
115
116
117
118
119
120
121
void
HMAC::update(const void* data, size_t len) {
    impl_->update(data, len);
}

void
HMAC::sign(isc::dns::OutputBuffer& result) {
    impl_->sign(result);
Jelte Jansen's avatar
Jelte Jansen committed
122
123
}

124
bool
125
HMAC::verify(const void* sig, size_t len) {
126
    return (impl_->verify(sig, len));
127
128
129
}

void
130
signHMAC(const void* data, size_t data_len, TSIGKey key,
131
         isc::dns::OutputBuffer& result)
132
{
133
    HMAC hmac(key);
134
    hmac.update(data, data_len);
135
136
    hmac.sign(result);
}
Jelte Jansen's avatar
Jelte Jansen committed
137

138

139
bool
140
verifyHMAC(const void* data, size_t data_len, TSIGKey key,
141
           const void* sig, size_t sig_len)
142
143
{
    HMAC hmac(key);
144
    hmac.update(data, data_len);
145
    return (hmac.verify(sig, sig_len));
Jelte Jansen's avatar
Jelte Jansen committed
146
}
Jelte Jansen's avatar
Jelte Jansen committed
147
148
149
150

} // namespace crypto
} // namespace isc