• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 19741624072

27 Nov 2025 03:45PM UTC coverage: 73.086% (+0.02%) from 73.065%
19741624072

Pull #16570

github

web-flow
Merge 08a2cdb1d into f94a3f63f
Pull Request #16570: rec: rewrite all unwrap calls in web.rs

38523 of 63408 branches covered (60.75%)

Branch coverage included in aggregate %.

128044 of 164496 relevant lines covered (77.84%)

6531485.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/pdns/ipcipher.cc
1
#include "ipcipher.hh"
2
#include "ext/ipcrypt/ipcrypt.h"
3
#include <cassert>
4
#include <openssl/aes.h>
5
#include <openssl/evp.h>
6

7
#ifdef HAVE_IPCIPHER
8
/*
9
int 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
*/
13
std::string makeIPCipherKey(const std::string& password)
14
{
2✔
15
  static const char salt[] = "ipcipheripcipher";
2✔
16
  unsigned char out[16];
2✔
17

18
  PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(), (const unsigned char*)salt, sizeof(salt) - 1, 50000, sizeof(out), out);
2✔
19

20
  return std::string((const char*)out, (const char*)out + sizeof(out));
2✔
21
}
2✔
22

23
static ComboAddress encryptCA4(const ComboAddress& ca, const std::string& key)
24
{
100,000,008✔
25
  if (key.size() != 16) {
100,000,008!
26
    throw std::runtime_error("Need 128 bits of key for ipcrypt");
×
27
  }
×
28

29
  ComboAddress ret = ca;
100,000,008✔
30

31
  // always returns 0, has no failure mode
32
  ipcrypt_encrypt((unsigned char*)&ret.sin4.sin_addr.s_addr,
100,000,008✔
33
                  (const unsigned char*)&ca.sin4.sin_addr.s_addr,
100,000,008✔
34
                  (const unsigned char*)key.c_str());
100,000,008✔
35

36
  return ret;
100,000,008✔
37
}
100,000,008✔
38

39
static ComboAddress decryptCA4(const ComboAddress& ca, const std::string& key)
40
{
4✔
41
  if (key.size() != 16) {
4!
42
    throw std::runtime_error("Need 128 bits of key for ipcrypt");
×
43
  }
×
44

45
  ComboAddress ret = ca;
4✔
46

47
  // always returns 0, has no failure mode
48
  ipcrypt_decrypt((unsigned char*)&ret.sin4.sin_addr.s_addr,
4✔
49
                  (const unsigned char*)&ca.sin4.sin_addr.s_addr,
4✔
50
                  (const unsigned char*)key.c_str());
4✔
51

52
  return ret;
4✔
53
}
4✔
54

55
static ComboAddress encryptCA6(const ComboAddress& address, const std::string& key)
56
{
1✔
57
  if (key.size() != 16) {
1!
58
    throw std::runtime_error("Need 128 bits of key for ipcrypt");
×
59
  }
×
60

61
  ComboAddress ret = address;
1✔
62

63
#if OPENSSL_VERSION_MAJOR >= 3
1✔
64
  auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>(EVP_CIPHER_CTX_new(), &EVP_CIPHER_CTX_free);
1✔
65
  if (ctx == nullptr) {
1!
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);
1✔
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) {
1!
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);
1✔
78
  static_assert(inSize == 16, "We disable padding and so we must assume a data size of 16 bytes");
1✔
79
  const auto blockSize = EVP_CIPHER_get_block_size(aes128cbc.get());
1✔
80
  if (blockSize != 16) {
1!
81
    throw pdns::OpenSSL::error("encryptCA6: unexpected block size");
×
82
  }
×
83
  EVP_CIPHER_CTX_set_padding(ctx.get(), 0);
1✔
84

85
  int updateLen = 0;
1✔
86
  // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
87
  const auto* input = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
1✔
88
  // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
89
  auto* output = reinterpret_cast<unsigned char*>(&ret.sin6.sin6_addr.s6_addr);
1✔
90
  if (EVP_EncryptUpdate(ctx.get(), output, &updateLen, input, static_cast<int>(inSize)) == 0) {
1!
91
    throw pdns::OpenSSL::error("encryptCA6: Could not encrypt address");
×
92
  }
×
93

94
  int finalLen = 0;
1✔
95
  if (EVP_EncryptFinal_ex(ctx.get(), output + updateLen, &finalLen) == 0) {
1!
96
    throw pdns::OpenSSL::error("encryptCA6: Could not finalize address encryption");
×
97
  }
×
98

99
  if ((updateLen + finalLen) != inSize) {
1!
100
    throw pdns::OpenSSL::error("encryptCA6: unexpected final size");
×
101
  }
×
102
#else
103
  AES_KEY wctx;
104
  AES_set_encrypt_key((const unsigned char*)key.c_str(), 128, &wctx);
105
  AES_encrypt((const unsigned char*)&address.sin6.sin6_addr.s6_addr,
106
              (unsigned char*)&ret.sin6.sin6_addr.s6_addr, &wctx);
107
#endif
108

109
  return ret;
1✔
110
}
1✔
111

112
static ComboAddress decryptCA6(const ComboAddress& address, const std::string& key)
113
{
1✔
114
  if (key.size() != 16) {
1!
115
    throw std::runtime_error("Need 128 bits of key for ipcrypt");
×
116
  }
×
117

118
  ComboAddress ret = address;
1✔
119

120
#if OPENSSL_VERSION_MAJOR >= 3
1✔
121
  auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>(EVP_CIPHER_CTX_new(), &EVP_CIPHER_CTX_free);
1✔
122
  if (ctx == nullptr) {
1!
123
    throw pdns::OpenSSL::error("decryptCA6: Could not initialize cipher context");
×
124
  }
×
125

126
  auto aes128cbc = std::unique_ptr<EVP_CIPHER, decltype(&EVP_CIPHER_free)>(EVP_CIPHER_fetch(nullptr, "AES-128-CBC", nullptr), &EVP_CIPHER_free);
1✔
127

128
  // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
129
  if (EVP_DecryptInit(ctx.get(), aes128cbc.get(), reinterpret_cast<const unsigned char*>(key.c_str()), nullptr) == 0) {
1!
130
    throw pdns::OpenSSL::error("decryptCA6: Could not initialize decryption algorithm");
×
131
  }
×
132

133
  // Disable padding
134
  const auto inSize = sizeof(address.sin6.sin6_addr.s6_addr);
1✔
135
  static_assert(inSize == 16, "We disable padding and so we must assume a data size of 16 bytes");
1✔
136
  const auto blockSize = EVP_CIPHER_get_block_size(aes128cbc.get());
1✔
137
  if (blockSize != 16) {
1!
138
    throw pdns::OpenSSL::error("decryptCA6: unexpected block size");
×
139
  }
×
140
  EVP_CIPHER_CTX_set_padding(ctx.get(), 0);
1✔
141

142
  int updateLen = 0;
1✔
143
  // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
144
  const auto* input = reinterpret_cast<const unsigned char*>(&address.sin6.sin6_addr.s6_addr);
1✔
145
  // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
146
  auto* output = reinterpret_cast<unsigned char*>(&ret.sin6.sin6_addr.s6_addr);
1✔
147
  if (EVP_DecryptUpdate(ctx.get(), output, &updateLen, input, static_cast<int>(inSize)) == 0) {
1!
148
    throw pdns::OpenSSL::error("decryptCA6: Could not decrypt address");
×
149
  }
×
150

151
  int finalLen = 0;
1✔
152
  if (EVP_DecryptFinal_ex(ctx.get(), output + updateLen, &finalLen) == 0) {
1!
153
    throw pdns::OpenSSL::error("decryptCA6: Could not finalize address decryption");
×
154
  }
×
155

156
  if ((updateLen + finalLen) != inSize) {
1!
157
    throw pdns::OpenSSL::error("decryptCA6: unexpected final size");
×
158
  }
×
159
#else
160
  AES_KEY wctx;
161
  AES_set_decrypt_key((const unsigned char*)key.c_str(), 128, &wctx);
162
  AES_decrypt((const unsigned char*)&address.sin6.sin6_addr.s6_addr,
163
              (unsigned char*)&ret.sin6.sin6_addr.s6_addr, &wctx);
164
#endif
165

166
  return ret;
1✔
167
}
1✔
168

169
ComboAddress encryptCA(const ComboAddress& ca, const std::string& key)
170
{
100,000,009✔
171
  if (ca.sin4.sin_family == AF_INET) {
100,000,009✔
172
    return encryptCA4(ca, key);
100,000,008✔
173
  }
100,000,008✔
174

175
  if (ca.sin4.sin_family == AF_INET6) {
1!
176
    return encryptCA6(ca, key);
1✔
177
  }
1✔
178

179
  throw std::runtime_error("ipcrypt can't encrypt non-IP addresses");
×
180
}
1✔
181

182
ComboAddress decryptCA(const ComboAddress& ca, const std::string& key)
183
{
5✔
184
  if (ca.sin4.sin_family == AF_INET) {
5✔
185
    return decryptCA4(ca, key);
4✔
186
  }
4✔
187

188
  if (ca.sin4.sin_family == AF_INET6) {
1!
189
    return decryptCA6(ca, key);
1✔
190
  }
1✔
191

192
  throw std::runtime_error("ipcrypt can't decrypt non-IP addresses");
×
193
}
1✔
194

195
#endif /* HAVE_IPCIPHER */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc