lacteApp
C++17 service for Lacte hardware
Loading...
Searching...
No Matches
Des.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cstdint>
6#include <string>
7
34namespace lacte::vnc::des {
35namespace detail {
36
37inline constexpr int K_IP[64] = {
38 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
39 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
40 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
41 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7};
42
43inline constexpr int K_FP[64] = {
44 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
45 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
46 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
47 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25};
48
49inline constexpr int K_E[48] = {32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
50 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
51 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
52 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1};
53
54inline constexpr int K_P[32] = {16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23,
55 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27,
56 3, 9, 19, 13, 30, 6, 22, 11, 4, 25};
57
58inline constexpr int K_PC1[56] = {
59 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43,
60 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54,
61 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4};
62
63inline constexpr int K_PC2[48] = {
64 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4,
65 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40,
66 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32};
67
68inline constexpr int K_SHIFTS[16] = {1, 1, 2, 2, 2, 2, 2, 2,
69 1, 2, 2, 2, 2, 2, 2, 1};
70
71inline constexpr int K_SBOX[8][4][16] = {
72 {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
73 {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
74 {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
75 {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
76 {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
77 {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
78 {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
79 {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
80 {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
81 {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
82 {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
83 {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
84 {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
85 {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
86 {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
87 {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
88 {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
89 {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
90 {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
91 {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
92 {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
93 {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
94 {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
95 {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
96 {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
97 {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
98 {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
99 {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
100 {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
101 {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
102 {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
103 {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
104
108inline auto permute(const std::uint64_t src, const int src_bits,
109 const int* table, const int table_len) -> std::uint64_t {
110 std::uint64_t out = 0;
111 for (int i = 0; i < table_len; ++i) {
112 const int shift = src_bits - table[i];
113 out = (out << 1) | ((src >> shift) & 1ULL);
114 }
115 return out;
116}
117
118inline auto rotate_left_28(const std::uint32_t value, const int amount)
119 -> std::uint32_t {
120 constexpr std::uint32_t k_mask = (1u << 28) - 1;
121 const std::uint32_t v = value & k_mask;
122 return ((v << amount) | (v >> (28 - amount))) & k_mask;
123}
124
127inline auto compute_round_keys(const std::uint64_t key64,
128 std::array<std::uint64_t, 16>& round_keys)
129 -> void {
130 const std::uint64_t permuted = permute(key64, 64, K_PC1, 56);
131 auto c = static_cast<std::uint32_t>(permuted >> 28);
132 auto d = static_cast<std::uint32_t>(permuted & ((1u << 28) - 1));
133 for (int round = 0; round < 16; ++round) {
134 c = rotate_left_28(c, K_SHIFTS[round]);
135 d = rotate_left_28(d, K_SHIFTS[round]);
136 const std::uint64_t cd = (static_cast<std::uint64_t>(c) << 28) | d;
137 round_keys[static_cast<std::size_t>(round)] = permute(cd, 56, K_PC2, 48);
138 }
139}
140
144inline auto feistel(const std::uint32_t r, const std::uint64_t round_key48)
145 -> std::uint32_t {
146 const std::uint64_t expanded = permute(r, 32, K_E, 48);
147 const std::uint64_t x = expanded ^ round_key48;
148 std::uint32_t sbox_out = 0;
149 for (int box = 0; box < 8; ++box) {
150 const int shift = 48 - (box * 6 + 6);
151 const auto six = static_cast<std::uint32_t>((x >> shift) & 0x3FULL);
152 const std::uint32_t row = ((six & 0x20U) >> 4U) | (six & 0x01U);
153 const std::uint32_t col = (six >> 1U) & 0x0FU;
154 const std::uint32_t value =
155 static_cast<std::uint32_t>(K_SBOX[box][row][col]);
156 sbox_out = (sbox_out << 4U) | value;
157 }
158 return static_cast<std::uint32_t>(permute(sbox_out, 32, K_P, 32));
159}
160
161} // namespace detail
162
169[[nodiscard]] inline auto encrypt_block(const std::uint64_t plaintext,
170 const std::uint64_t key64)
171 -> std::uint64_t {
172 std::array<std::uint64_t, 16> round_keys{};
173 detail::compute_round_keys(key64, round_keys);
174
175 const std::uint64_t ip = detail::permute(plaintext, 64, detail::K_IP, 64);
176 auto l = static_cast<std::uint32_t>(ip >> 32);
177 auto r = static_cast<std::uint32_t>(ip & 0xFFFFFFFFULL);
178 for (int round = 0; round < 16; ++round) {
179 const std::uint32_t new_r =
180 l ^ detail::feistel(r, round_keys[static_cast<std::size_t>(round)]);
181 l = r;
182 r = new_r;
183 }
184 // Pre-output is R16 || L16 (the swap that alternates every round is NOT
185 // re-applied after the last one) - see this file's own doc comment.
186 const std::uint64_t preoutput = (static_cast<std::uint64_t>(r) << 32) | l;
187 return detail::permute(preoutput, 64, detail::K_FP, 64);
188}
189
190inline auto bytes_to_u64(const std::array<std::uint8_t, 8>& bytes)
191 -> std::uint64_t {
192 std::uint64_t value = 0;
193 for (const auto b : bytes) {
194 value = (value << 8) | b;
195 }
196 return value;
197}
198
199inline auto u64_to_bytes(const std::uint64_t value)
200 -> std::array<std::uint8_t, 8> {
201 std::array<std::uint8_t, 8> out{};
202 std::uint64_t remaining = value;
203 for (int i = 7; i >= 0; --i) {
204 out[static_cast<std::size_t>(i)] = static_cast<std::uint8_t>(remaining);
205 remaining >>= 8;
206 }
207 return out;
208}
209
210namespace detail {
211inline auto reverse_bits(std::uint8_t b) -> std::uint8_t {
212 b = static_cast<std::uint8_t>(((b & 0xF0U) >> 4U) | ((b & 0x0FU) << 4U));
213 b = static_cast<std::uint8_t>(((b & 0xCCU) >> 2U) | ((b & 0x33U) << 2U));
214 b = static_cast<std::uint8_t>(((b & 0xAAU) >> 1U) | ((b & 0x55U) << 1U));
215 return b;
216}
217} // namespace detail
218
228[[nodiscard]] inline auto vnc_encrypt_challenge(
229 const std::array<std::uint8_t, 16>& challenge, const std::string& password)
230 -> std::array<std::uint8_t, 16> {
231 std::array<std::uint8_t, 8> key_bytes{};
232 for (std::size_t i = 0; i < key_bytes.size(); ++i) {
233 key_bytes[i] =
234 i < password.size() ? static_cast<std::uint8_t>(password[i]) : 0;
235 }
236 for (auto& b : key_bytes) {
238 }
239 const std::uint64_t key64 = bytes_to_u64(key_bytes);
240
241 std::array<std::uint8_t, 16> out{};
242 for (int half = 0; half < 2; ++half) {
243 std::array<std::uint8_t, 8> block{};
244 std::copy(challenge.begin() + half * 8, challenge.begin() + half * 8 + 8,
245 block.begin());
246 const std::uint64_t ciphertext = encrypt_block(bytes_to_u64(block), key64);
247 const auto ciphertext_bytes = u64_to_bytes(ciphertext);
248 std::copy(ciphertext_bytes.begin(), ciphertext_bytes.end(),
249 out.begin() + half * 8);
250 }
251 return out;
252}
253} // namespace lacte::vnc::des
constexpr int K_PC2[48]
Definition Des.hpp:63
constexpr int K_SBOX[8][4][16]
Definition Des.hpp:71
auto permute(const std::uint64_t src, const int src_bits, const int *table, const int table_len) -> std::uint64_t
Permutes src (an src_bits-wide value, bit 1 = MSB) through table (each entry a 1-indexed bit position...
Definition Des.hpp:108
auto feistel(const std::uint32_t r, const std::uint64_t round_key48) -> std::uint32_t
The Feistel round function f(R, K): E(R) xor K, split into eight 6-bit groups, each substituted throu...
Definition Des.hpp:144
auto compute_round_keys(const std::uint64_t key64, std::array< std::uint64_t, 16 > &round_keys) -> void
PC1(key) -> C0/D0, then 16 left-rotations (per K_SHIFTS) each followed by PC2 -> one 48-bit round key...
Definition Des.hpp:127
constexpr int K_P[32]
Definition Des.hpp:54
auto rotate_left_28(const std::uint32_t value, const int amount) -> std::uint32_t
Definition Des.hpp:118
constexpr int K_PC1[56]
Definition Des.hpp:58
constexpr int K_IP[64]
Definition Des.hpp:37
constexpr int K_E[48]
Definition Des.hpp:49
constexpr int K_FP[64]
Definition Des.hpp:43
auto reverse_bits(std::uint8_t b) -> std::uint8_t
Definition Des.hpp:211
constexpr int K_SHIFTS[16]
Definition Des.hpp:68
auto u64_to_bytes(const std::uint64_t value) -> std::array< std::uint8_t, 8 >
Definition Des.hpp:199
auto encrypt_block(const std::uint64_t plaintext, const std::uint64_t key64) -> std::uint64_t
Encrypts one 64-bit block with one 64-bit DES key (parity bits included but unchecked - PC1 drops the...
Definition Des.hpp:169
auto vnc_encrypt_challenge(const std::array< std::uint8_t, 16 > &challenge, const std::string &password) -> std::array< std::uint8_t, 16 >
RFB's classic "VNC Authentication" (security type 2) challenge response: the connection password beco...
Definition Des.hpp:228
auto bytes_to_u64(const std::array< std::uint8_t, 8 > &bytes) -> std::uint64_t
Definition Des.hpp:190