Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,30 @@ target_include_directories(blowfish2 PUBLIC ${BF_INCLUDE_DIR})

# ===== Tests =====
include(CTest)
if(BUILD_TESTING)
add_executable(bf_test tests/Main.cpp)
if (BUILD_TESTING)

# ---- Blowfish Test ----
add_executable(bf_test
tests/Main.cpp
tests/test_framework.h
tests/test_vectors.cpp
tests/test_roundtrip.cpp
tests/test_avalanche.cpp
tests/test_properties.cpp
)
target_link_libraries(bf_test PRIVATE blowfish)
add_test(NAME bf_test COMMAND bf_test)
add_test(NAME BlowfishTests COMMAND bf_test)

add_executable(bf2_test tests/Main2.cpp)
# ---- Blowfish2 Test ----
add_executable(bf2_test
tests/Main2.cpp
tests/test_framework.h
tests/bf2_test_vectors.cpp
tests/bf2_test_roundtrip.cpp
tests/bf2_test_avalanche.cpp
tests/bf2_test_properties.cpp
)
target_link_libraries(bf2_test PRIVATE blowfish2)
add_test(NAME bf2_test COMMAND bf2_test)
add_test(NAME Blowfish2Tests COMMAND bf2_test)

endif()
6 changes: 3 additions & 3 deletions include/blowfish/blowfish.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
#include <cstdint>
#include <string>

#define MAXKEYBYTES 56 // 448 bits max
static constexpr uint32_t N = 16;
static constexpr uint32_t BF_NUM_ROUNDS = 16;
static constexpr uint32_t BF_MAX_KEYBYTES = 56;

#if !defined(BLOWFISH_BLOWFISH_H_)
#define BLOWFISH_BLOWFISH_H_

class Blowfish {
private:
std::array<uint32_t, N + 2> PArray{};
std::array<uint32_t, BF_NUM_ROUNDS + 2> PArray{};
std::array<std::array<uint32_t, 256>, 4> Sboxes{};
uint32_t F(uint32_t x) const noexcept;

Expand Down
6 changes: 3 additions & 3 deletions include/blowfish/blowfish2.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
#include <cstdint>
#include <string>

#define MAXKEYBYTES 56 // 448 bits max
static constexpr uint64_t BF2_NUM_ROUNDS = 64;
static constexpr uint64_t BF2_MAX_KEYBYTES = 56;

#if !defined(BLOWFISH_BLOWFISH2_H_)
#define BLOWFISH_BLOWFISH2_H_

class Blowfish2 {
private:
static constexpr uint64_t N = 64;
std::array<uint64_t, N + 2> PArray{};
std::array<uint64_t, BF2_NUM_ROUNDS + 2> PArray{};
std::array<std::array<uint64_t, 256>, 8> Sboxes{};
uint64_t F(uint64_t x) const noexcept;

Expand Down
20 changes: 10 additions & 10 deletions src/blowfish.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

#include <blowfish/blowfish.h>

static const std::array<uint32_t, 16 + 2> P = {
static const std::array<uint32_t, 16 + 2> BF_PARRAY_INIT = {
0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, 0xA4093822L,
0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, 0x452821E6L, 0x38D01377L,
0xBE5466CFL, 0x34E90C6CL, 0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L,
0xB5470917L, 0x9216D5D9L, 0x8979FB1BL};

static const std::array<std::array<uint32_t, 256>, 4> S = {
static const std::array<std::array<uint32_t, 256>, 4> BF_SBOX_INT = {
{{0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, 0xB8E1AFEDL,
0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, 0x24A19947L, 0xB3916CF7L,
0x0801F2E2L, 0x858EFC16L, 0x636920D8L, 0x71574E69L, 0xA458FEA3L,
Expand Down Expand Up @@ -230,19 +230,19 @@ void Blowfish::initialize(const uint8_t *key, size_t keylen) {
uint32_t datal = 0;
uint32_t datar = 0;

Sboxes = S;
Sboxes = BF_SBOX_INT;

size_t j = 0;
for (uint32_t i = 0; i < N + 2; ++i) {
for (uint32_t i = 0; i < BF_NUM_ROUNDS + 2; ++i) {
data = 0;
for (uint32_t k = 0; k < 4; ++k) {
data = (data << 8) | key[j];
j = (j + 1) % keylen;
}
PArray[i] = P[i] ^ data;
PArray[i] = BF_PARRAY_INIT[i] ^ data;
}

for (uint32_t i = 0; i < N + 2; i += 2) {
for (uint32_t i = 0; i < BF_NUM_ROUNDS + 2; i += 2) {
encrypt(datal, datar);
PArray[i] = datal;
PArray[i + 1] = datar;
Expand Down Expand Up @@ -282,15 +282,15 @@ void Blowfish::encrypt(uint32_t &xl, uint32_t &xr) noexcept {
uint32_t Xl = xl;
uint32_t Xr = xr;

for (uint32_t i = 0; i < N; ++i) {
for (uint32_t i = 0; i < BF_NUM_ROUNDS; ++i) {
Xl ^= PArray[i];
Xr = F(Xl) ^ Xr;
std::swap(Xl, Xr);
}

std::swap(Xl, Xr);
Xr ^= PArray[N];
Xl ^= PArray[N + 1];
Xr ^= PArray[BF_NUM_ROUNDS];
Xl ^= PArray[BF_NUM_ROUNDS + 1];
xl = Xl;
xr = Xr;
}
Expand All @@ -299,7 +299,7 @@ void Blowfish::decrypt(uint32_t &xl, uint32_t &xr) noexcept {
uint32_t Xl = xl;
uint32_t Xr = xr;

for (int i = N + 1; i >= 2; --i) {
for (int i = BF_NUM_ROUNDS + 1; i >= 2; --i) {
Xl ^= PArray[i];
Xr ^= F(Xl);
std::swap(Xl, Xr);
Expand Down
20 changes: 10 additions & 10 deletions src/blowfish2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#include <blowfish/blowfish2.h>

static const std::array<uint64_t, 64 + 2> P = {
static const std::array<uint64_t, 64 + 2> BF2_PARRAY_INIT = {
0x243F6A8885A308D3, 0x13198A2E03707344, 0xA4093822299F31D0,
0x082EFA98EC4E6C89, 0x452821E638D01377, 0xBE5466CF34E90C6C,
0xC0AC29B7C97C50DD, 0x3F84D5B5B5470917, 0x9216D5D98979FB1B,
Expand All @@ -30,7 +30,7 @@ static const std::array<uint64_t, 64 + 2> P = {
0x1BFEDF72429B023D, 0x37D0D724D00A1248, 0xDB0FEAD349F1C09B,
0x075372C980991B7B, 0x25D479D8F6E8DEF7, 0xE3FE501AB6794C3B};

static const std::array<std::array<uint64_t, 256>, 8> S = {
static const std::array<std::array<uint64_t, 256>, 8> BF2_SBOX_INIT = {
{{0x976CE0BD04C006BA, 0xC1A94FB6409F60C4, 0x5E5C9EC2196A2463,
0x68FB6FAF3E6C53B5, 0x1339B2EB3B52EC6F, 0x6DFC511F9B30952C,
0xCC814544AF5EBD09, 0xBEE3D004DE334AFD, 0x660F2807192E4BB3,
Expand Down Expand Up @@ -736,20 +736,20 @@ void Blowfish2::initialize(const uint8_t *key, size_t keylen) {
uint64_t datal = 0;
uint64_t datar = 0;

Sboxes = S; // assumes static const S exists
Sboxes = BF2_SBOX_INIT; // assumes static const S exists

size_t j = 0;

for (uint64_t i = 0; i < N + 2; ++i) {
for (uint64_t i = 0; i < BF2_NUM_ROUNDS + 2; ++i) {
data = 0;
for (uint64_t k = 0; k < 8; ++k) {
data = (data << 8) | key[j];
j = (j + 1) % keylen;
}
PArray[i] = P[i] ^ data;
PArray[i] = BF2_PARRAY_INIT[i] ^ data;
}

for (uint64_t i = 0; i < N + 2; i += 2) {
for (uint64_t i = 0; i < BF2_NUM_ROUNDS + 2; i += 2) {
encrypt(datal, datar);
PArray[i] = datal;
PArray[i + 1] = datar;
Expand Down Expand Up @@ -798,15 +798,15 @@ void Blowfish2::encrypt(uint64_t &xl, uint64_t &xr) noexcept {
uint64_t Xl = xl;
uint64_t Xr = xr;

for (uint64_t i = 0; i < N; ++i) {
for (uint64_t i = 0; i < BF2_NUM_ROUNDS; ++i) {
Xl ^= PArray[i];
Xr = F(Xl) ^ Xr;
std::swap(Xl, Xr);
}

std::swap(Xl, Xr);
Xr ^= PArray[N];
Xl ^= PArray[N + 1];
Xr ^= PArray[BF2_NUM_ROUNDS];
Xl ^= PArray[BF2_NUM_ROUNDS + 1];
xl = Xl;
xr = Xr;
}
Expand All @@ -815,7 +815,7 @@ void Blowfish2::decrypt(uint64_t &xl, uint64_t &xr) noexcept {
uint64_t Xl = xl;
uint64_t Xr = xr;

for (uint64_t i = N + 1; i > 1; --i) {
for (uint64_t i = BF2_NUM_ROUNDS + 1; i > 1; --i) {
Xl ^= PArray[i];
Xr = F(Xl) ^ Xr;
std::swap(Xl, Xr);
Expand Down
60 changes: 4 additions & 56 deletions tests/Main.cpp
Original file line number Diff line number Diff line change
@@ -1,58 +1,6 @@
#include <iostream>
// SPDX-FileCopyrightText: 2025 Avinal Kumar avinal.xlvii@gmail.com
// SPDX-License-Identifier: MIT

#include <blowfish/blowfish.h>
#include "test_framework.h"

std::string from_uint(uint32_t sh) {
std::string re("");
for (int i = 0; i < 4; i++) {
re += (unsigned char)(sh >> i * 8);
}
return re;
}

int main(int argc, char const *argv[]) {
std::string key("test@pass47");
std::string message("My name is Avinal and I am cute");
std::string cipher("");
int len = message.length();
int j = sizeof(uint32_t);
int rem =
((len > j * 2) ? (((len / j * 2) + 1) * j * 2 - len) : (j * 2 - len));
message.append(rem, '\0');
len = message.length();
Blowfish blowfish(key);
std::cout << "My message is: " << message << std::endl;
uint32_t lm, rm;
for (size_t i = 0; i < len; i += 8) {
lm = 0;
rm = 0;
lm = *reinterpret_cast<unsigned int *>(
const_cast<char *>(message.substr(i, j).c_str()));
rm = *reinterpret_cast<unsigned int *>(
const_cast<char *>(message.substr(i + 4, j).c_str()));
blowfish.encrypt(lm, rm);
cipher += from_uint(lm) + from_uint(rm);
}
std::cout << cipher << std::endl;
std::string decipher("");
len = cipher.length();
std::cout << "length: " << len << std::endl;
for (size_t i = 0; i < len; i += 8) {
lm = 0;
rm = 0;
lm = *reinterpret_cast<unsigned int *>(
const_cast<char *>(cipher.substr(i, 4).c_str()));
rm = *reinterpret_cast<unsigned int *>(
const_cast<char *>(cipher.substr(i + 4, 4).c_str()));
blowfish.decrypt(lm, rm);
decipher += from_uint(lm) + from_uint(rm);
}

std::cout << decipher << std::endl;
if (message == decipher) {
std::cout << "Test successful!" << std::endl;
return 0;
} else {
return 1;
}
}
int main() { return tests_summary(); }
107 changes: 4 additions & 103 deletions tests/Main2.cpp
Original file line number Diff line number Diff line change
@@ -1,105 +1,6 @@
#include <cstdint>
#include <iostream>
// SPDX-FileCopyrightText: 2025 Avinal Kumar avinal.xlvii@gmail.com
// SPDX-License-Identifier: MIT

#include <blowfish/blowfish2.h>
#include <ostream>
#include "test_framework.h"

std::string from_uint(uint64_t sh) {
std::string re("");
for (int i = 0; i < 8; i++) {
re += (unsigned char)(sh >> i * 8);
}
return re;
}

uint64_t to_uint(std::string &s, size_t index, size_t size) {
return *reinterpret_cast<uint64_t *>(
const_cast<char *>(s.substr(index, size).c_str()));
}

int main(int argc, char const *argv[]) {
std::string key("test@pass47");
std::string message("My name is Avinal and I am cute and smart");
std::string cipher("");
int len = message.length();
int J = sizeof(uint64_t);
int rem =
((len > J * 2) ? (((len / J * 2) + 1) * J * 2 - len) : (J * 2 - len));
message.append(rem, '\0');
len = message.length();

Blowfish2 blowfish(key);

std::cout << "My message is: " << message << J << std::endl;
uint64_t L = 0, R = 0;
for (size_t i = 0; i < len; i += 16) {
L = to_uint(message, i, J);
R = to_uint(message, i + J, J);
blowfish.encrypt(L, R);
cipher += from_uint(L) + from_uint(R);
}
std::cout << "Cipher: " << cipher << std::endl;

std::string decipher("");
len = cipher.length();
std::cout << "length: " << len << std::endl;
for (size_t i = 0; i < len; i += 16) {
L = to_uint(cipher, i, J);
R = to_uint(cipher, i + J, J);
blowfish.decrypt(L, R);
decipher += from_uint(L) + from_uint(R);
}
if (message == decipher) {
std::cout << "Test OK." << std::endl;
} else {
std::cout << "Test failed." << std::endl;
}
// C Blowfish 2 tests

L = 0x0000000000000001, R = 0x0000000000000002;

blowfish.initialize("TESTKEY");
blowfish.encrypt(L, R);
if (L == 0x7B2B9DE71D1B1C62 && R == 0x91C230351177BEE8)
std::cout << "Test encryption OK." << std::endl;
else
std::cout << "Test encryption failed." << std::endl;

blowfish.decrypt(L, R);
if (L == 1 && R == 2)
std::cout << "Test decryption OK." << std::endl;
else
std::cout << "Test decryption failed." << std::endl;

L = 0x0102030405060708;
R = 0x0910111213141516;

blowfish.initialize("A");
blowfish.encrypt(L, R);
if (L == 0xCA38165603F9915C && R == 0x61F0776A0F55E807)
std::cout << "Test encryption OK." << std::endl;
else
std::cout << "Test encryption failed." << std::endl;

blowfish.decrypt(L, R);
if (L == 0x0102030405060708 && R == 0x0910111213141516)
std::cout << "Test decryption OK." << std::endl;
else
std::cout << "Test decryption failed." << std::endl;

L = 0x0102030405060708;
R = 0x0910111213141516;

blowfish.initialize("B");
blowfish.encrypt(L, R);
if (L == 0xD07690A78B109983 && R == 0x8DDF85826F2366C2)
std::cout << "Test encryption OK." << std::endl;
else
std::cout << "Test encryption failed." << std::endl;

blowfish.decrypt(L, R);
if (L == 0x0102030405060708 && R == 0x0910111213141516)
std::cout << "Test decryption OK." << std::endl;
else
std::cout << "Test decryption failed." << std::endl;
}
int main() { return tests_summary(); }
Loading