aboutsummaryrefslogtreecommitdiff
path: root/blowfish.hpp
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2020-11-06 11:30:05 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2020-11-06 11:55:29 +0200
commitca9602e39f6cb360be907ecd08d0eb850d5cf879 (patch)
tree0a5ab961ada74168ca48977c7bd5b3bdad567082 /blowfish.hpp
downloadblowfish-ca9602e39f6cb360be907ecd08d0eb850d5cf879.tar.xz
Initial commit
Diffstat (limited to 'blowfish.hpp')
-rw-r--r--blowfish.hpp103
1 files changed, 103 insertions, 0 deletions
diff --git a/blowfish.hpp b/blowfish.hpp
new file mode 100644
index 0000000..e0468cd
--- /dev/null
+++ b/blowfish.hpp
@@ -0,0 +1,103 @@
+#pragma once
+
+// https://www.schneier.com/academic/archives/1994/09/description_of_a_new.html
+
+#include "blowfish_init.hpp"
+#include <algorithm>
+
+class Blowfish {
+public:
+ struct Block {
+ constexpr Block(uint64_t x) {
+ L = x >> 32;
+ R = x & 0xffffffff;
+ }
+ constexpr Block(uint32_t l, uint32_t r) : L(l), R(r) {}
+
+ constexpr operator uint64_t() const {
+ return (static_cast<uint64_t>(L) << 32) + R;
+ }
+ uint32_t L;
+ uint32_t R;
+ };
+
+ constexpr Blowfish(const uint8_t key[], size_t keylen) {
+ for (size_t i = 0; i < BOXES; ++i) {
+ for (size_t j = 0; j < ENTRIES; ++j) {
+ S[i][j] = S_INIT[i][j];
+ }
+ }
+
+ //
+ size_t k = 0;
+ for (size_t i = 0; i < SUBKEYS; ++i) {
+ uint32_t qk = 0;
+ for (size_t j = 0; j < 4; ++j) {
+ qk = (qk << 8) | key[k];
+ ++k;
+ if (k >= keylen) {
+ k = 0;
+ }
+ }
+ P[i] = P_INIT[i] ^ qk;
+ }
+
+ Block x(0, 0);
+
+ for (size_t i = 0; i < SUBKEYS; i += 2) {
+ x = encrypt(x);
+ P[i] = x.L;
+ P[i + 1] = x.R;
+ }
+ for (size_t i = 0; i < BOXES; ++i) {
+ for (size_t j = 0; j < ENTRIES; j += 2) {
+ x = encrypt(x);
+ S[i][j] = x.L;
+ S[i][j + 1] = x.R;
+ }
+ }
+ }
+
+ constexpr Block encrypt(const Block &x) const {
+ Block y(x);
+ for (size_t i = 0; i < ROUNDS; ++i) {
+ y.L = y.L ^ P[i];
+ y.R = F(y.L) ^ y.R;
+ std::swap(y.L, y.R);
+ }
+ std::swap(y.L, y.R);
+ y.R = y.R ^ P[16];
+ y.L = y.L ^ P[17];
+
+ return y;
+ }
+
+ constexpr Block decrypt(const Block &x) const {
+ Block y(x);
+ for (size_t i = ROUNDS + 1; i > 1; --i) {
+ y.L = y.L ^ P[i];
+ y.R = F(y.L) ^ y.R;
+ std::swap(y.L, y.R);
+ }
+ std::swap(y.L, y.R);
+ y.R = y.R ^ P[1];
+ y.L = y.L ^ P[0];
+ return y;
+ }
+
+private:
+ constexpr uint32_t F(uint32_t x) const {
+ const uint8_t a = (x >> 24) & 0xff;
+ const uint8_t b = (x >> 16) & 0xff;
+ const uint8_t c = (x >> 8) & 0xff;
+ const uint8_t d = x & 0xff;
+
+ uint32_t y = S[0][a] + S[1][b];
+ y = y ^ S[2][c];
+ y = y + S[3][d];
+ return y;
+ }
+
+ uint32_t P[SUBKEYS];
+ uint32_t S[BOXES][ENTRIES];
+};