]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/ipcipher.cc
Merge pull request #14020 from omoerbeek/rec-compiling-rust-dcos
[thirdparty/pdns.git] / pdns / ipcipher.cc
CommitLineData
5d5d8c2e 1#include "ipcipher.hh"
7d280342 2#include "ext/ipcrypt/ipcrypt.h"
9b81c913 3#include <cassert>
7d280342 4#include <openssl/aes.h>
caff6e16 5#include <openssl/evp.h>
6
e41aadeb 7#ifdef HAVE_IPCIPHER
caff6e16 8/*
9int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
10 const unsigned char *salt, int saltlen, int iter,
11 int keylen, unsigned char *out);
12*/
5d5d8c2e 13std::string makeIPCipherKey(const std::string& password)
caff6e16 14{
44677590 15 static const char salt[] = "ipcipheripcipher";
caff6e16 16 unsigned char out[16];
51d33ccc 17
44677590 18 PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(), (const unsigned char*)salt, sizeof(salt) - 1, 50000, sizeof(out), out);
caff6e16 19
20 return std::string((const char*)out, (const char*)out + sizeof(out));
21}
7d280342 22
44677590 23static ComboAddress encryptCA4(const ComboAddress& ca, const std::string& key)
7d280342 24{
dd2ef389 25 if (key.size() != 16) {
7d280342 26 throw std::runtime_error("Need 128 bits of key for ipcrypt");
dd2ef389 27 }
488bcb39 28
44677590 29 ComboAddress ret = ca;
7d280342 30
31 // always returns 0, has no failure mode
44677590
FM
32 ipcrypt_encrypt((unsigned char*)&ret.sin4.sin_addr.s_addr,
33 (const unsigned char*)&ca.sin4.sin_addr.s_addr,
34 (const unsigned char*)key.c_str());
35
7d280342 36 return ret;
37}
38
44677590 39static ComboAddress decryptCA4(const ComboAddress& ca, const std::string& key)
7d280342 40{
dd2ef389 41 if (key.size() != 16) {
7d280342 42 throw std::runtime_error("Need 128 bits of key for ipcrypt");
dd2ef389 43 }
488bcb39 44
44677590 45 ComboAddress ret = ca;
7d280342 46
47 // always returns 0, has no failure mode
44677590
FM
48 ipcrypt_decrypt((unsigned char*)&ret.sin4.sin_addr.s_addr,
49 (const unsigned char*)&ca.sin4.sin_addr.s_addr,
50 (const unsigned char*)key.c_str());
51
7d280342 52 return ret;
53}
54
dd2ef389 55static ComboAddress encryptCA6(const ComboAddress& address, const std::string& key)
7d280342 56{
dd2ef389 57 if (key.size() != 16) {
7d280342 58 throw std::runtime_error("Need 128 bits of key for ipcrypt");
dd2ef389 59 }
7d280342 60
dd2ef389 61 ComboAddress ret = address;
7d280342 62
9b81c913
FM
63#if OPENSSL_VERSION_MAJOR >= 3
64 auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>(EVP_CIPHER_CTX_new(), &EVP_CIPHER_CTX_free);
65 if (ctx == nullptr) {
66 throw pdns::OpenSSL::error("encryptCA6: Could not initialize cipher context");
67 }
68
69 auto aes128cbc = std::unique_ptr<EVP_CIPHER, decltype(&EVP_CIPHER_free)>(EVP_CIPHER_fetch(nullptr, "AES-128-CBC", nullptr), &EVP_CIPHER_free);
70
71 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
72 if (EVP_EncryptInit(ctx.get(), aes128cbc.get(), reinterpret_cast<const unsigned char*>(key.c_str()), nullptr) == 0) {
73 throw pdns::OpenSSL::error("encryptCA6: Could not initialize encryption algorithm");
74 }
75
76 // Disable padding
77 const auto inSize = sizeof(address.sin6.sin6_addr.s6_addr);
78 static_assert(inSize == 16, "We disable padding and so we must assume a data size of 16 bytes");
79 const auto blockSize = EVP_CIPHER_get_block_size(aes128cbc.get());
80 assert(blockSize == 16);
81 EVP_CIPHER_CTX_set_padding(ctx.get(), 0);
82
83 int updateLen = 0;
84 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
85 const auto* input = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
86 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
87 auto* output = reinterpret_cast<unsigned char*>(&ret.sin6.sin6_addr.s6_addr);
88 if (EVP_EncryptUpdate(ctx.get(), output, &updateLen, input, static_cast<int>(inSize)) == 0) {
89 throw pdns::OpenSSL::error("encryptCA6: Could not encrypt address");
90 }
91
92 int finalLen = 0;
93 if (EVP_EncryptFinal_ex(ctx.get(), output + updateLen, &finalLen) == 0) {
94 throw pdns::OpenSSL::error("encryptCA6: Could not finalize address encryption");
95 }
96
97 assert(updateLen + finalLen == inSize);
98#else
7d280342 99 AES_KEY wctx;
100 AES_set_encrypt_key((const unsigned char*)key.c_str(), 128, &wctx);
dd2ef389 101 AES_encrypt((const unsigned char*)&address.sin6.sin6_addr.s6_addr,
488bcb39 102 (unsigned char*)&ret.sin6.sin6_addr.s6_addr, &wctx);
9b81c913 103#endif
7d280342 104
105 return ret;
106}
107
dd2ef389 108static ComboAddress decryptCA6(const ComboAddress& address, const std::string& key)
7d280342 109{
dd2ef389 110 if (key.size() != 16) {
7d280342 111 throw std::runtime_error("Need 128 bits of key for ipcrypt");
dd2ef389
FM
112 }
113
114 ComboAddress ret = address;
488bcb39 115
3768bfad
FM
116#if OPENSSL_VERSION_MAJOR >= 3
117 auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>(EVP_CIPHER_CTX_new(), &EVP_CIPHER_CTX_free);
118 if (ctx == nullptr) {
119 throw pdns::OpenSSL::error("decryptCA6: Could not initialize cipher context");
120 }
121
122 auto aes128cbc = std::unique_ptr<EVP_CIPHER, decltype(&EVP_CIPHER_free)>(EVP_CIPHER_fetch(nullptr, "AES-128-CBC", nullptr), &EVP_CIPHER_free);
123
124 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
125 if (EVP_DecryptInit(ctx.get(), aes128cbc.get(), reinterpret_cast<const unsigned char*>(key.c_str()), nullptr) == 0) {
126 throw pdns::OpenSSL::error("decryptCA6: Could not initialize decryption algorithm");
127 }
128
129 // Disable padding
130 const auto inSize = sizeof(address.sin6.sin6_addr.s6_addr);
131 static_assert(inSize == 16, "We disable padding and so we must assume a data size of 16 bytes");
132 const auto blockSize = EVP_CIPHER_get_block_size(aes128cbc.get());
133 assert(blockSize == 16);
134 EVP_CIPHER_CTX_set_padding(ctx.get(), 0);
135
136 int updateLen = 0;
137 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
138 const auto* input = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
139 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
140 auto* output = reinterpret_cast<unsigned char*>(&ret.sin6.sin6_addr.s6_addr);
141 if (EVP_DecryptUpdate(ctx.get(), output, &updateLen, input, static_cast<int>(inSize)) == 0) {
142 throw pdns::OpenSSL::error("decryptCA6: Could not decrypt address");
143 }
144
145 int finalLen = 0;
146 if (EVP_DecryptFinal_ex(ctx.get(), output + updateLen, &finalLen) == 0) {
147 throw pdns::OpenSSL::error("decryptCA6: Could not finalize address decryption");
148 }
149
150 assert(updateLen + finalLen == inSize);
151#else
7d280342 152 AES_KEY wctx;
153 AES_set_decrypt_key((const unsigned char*)key.c_str(), 128, &wctx);
dd2ef389 154 AES_decrypt((const unsigned char*)&address.sin6.sin6_addr.s6_addr,
488bcb39 155 (unsigned char*)&ret.sin6.sin6_addr.s6_addr, &wctx);
3768bfad 156#endif
488bcb39 157
7d280342 158 return ret;
159}
160
7d280342 161ComboAddress encryptCA(const ComboAddress& ca, const std::string& key)
162{
dd2ef389 163 if (ca.sin4.sin_family == AF_INET) {
7d280342 164 return encryptCA4(ca, key);
dd2ef389
FM
165 }
166
167 if (ca.sin4.sin_family == AF_INET6) {
7d280342 168 return encryptCA6(ca, key);
dd2ef389
FM
169 }
170
171 throw std::runtime_error("ipcrypt can't encrypt non-IP addresses");
7d280342 172}
173
174ComboAddress decryptCA(const ComboAddress& ca, const std::string& key)
175{
dd2ef389 176 if (ca.sin4.sin_family == AF_INET) {
7d280342 177 return decryptCA4(ca, key);
dd2ef389
FM
178 }
179
180 if (ca.sin4.sin_family == AF_INET6) {
7d280342 181 return decryptCA6(ca, key);
dd2ef389
FM
182 }
183
184 throw std::runtime_error("ipcrypt can't decrypt non-IP addresses");
7d280342 185}
e41aadeb
RG
186
187#endif /* HAVE_IPCIPHER */