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
47 changes: 21 additions & 26 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
name: Build C++ Project

on: [push]

name: Build and Test
on: [push, pull_request]
jobs:
build:
name: Build on Ubuntu with GCC
runs-on: ubuntu-latest # For Gitea, ensure you have a runner with the 'ubuntu-latest' label

# Environment variables for the C/C++ compiler
env:
CC: gcc
CXX: g++

runs-on: ubuntu-latest
strategy:
matrix: {compiler: [gcc, clang], build_type: [Release, Debug]}
steps:
# Step 1: Check out the repository code
- name: Checkout repository
uses: actions/checkout@v4 # Updated to the latest version for best practice
# Note for Gitea: Ensure your instance can access this action or use a native 'git clone' command.

# Step 2: Configure the project and build it
- name: Configure and Build
run: |
# Configure using CMake. The -B flag creates the 'build' directory.
# The build type is now hardcoded to 'Debug'.
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON .

# Build the project using the generated configuration.
cmake --build build --config Debug
- uses: actions/checkout@v4
- name: Install deps
run: sudo apt-get update && sudo apt-get install -y build-essential cmake
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
- name: Build
run: cmake --build build -j
- name: Run tests
run: ctest --output-on-failure -C ${{ matrix.build_type }} -V
sanitize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"
- run: cmake --build build -j
- run: ctest --output-on-failure -C Debug -V
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@
cmake-build-debug
build
.vscode
.cache
77 changes: 39 additions & 38 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,53 +1,54 @@
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.30)
project(blowfish VERSION 1.0.0 LANGUAGES CXX)

message(STATUS "CMake version: ${CMAKE_VERSION}")
message(STATUS "Project version: ${PROJECT_VERSION}")

if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
elseif (CMAKE_CXX_STANDARD LESS 11)
message(WARNING "CMAKE_CXX_STANDARD has been set to '${CMAKE_CXX_STANDARD}' which is lower than the minimum required standard (c++14).")
endif ()
# ===== compiler settings =====
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

message(STATUS "Using C++ standard c++${CMAKE_CXX_STANDARD}")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
message(STATUS "Using C++ standard c++${CMAKE_CXX_STANDARD}")

message (STATUS "CMake version: ${CMAKE_VERSION}")
message (STATUS "Project version: ${PROJECT_VERSION}")

set(BLOWFISH_SRC ${PROJECT_SOURCE_DIR}/src/blowfish.cc)
set(BLOWFISH2_SRC ${PROJECT_SOURCE_DIR}/src/blowfish2.cc)
source_group(src FILES ${BLOWFISH_SRC} ${BLOWFISH2_SRC})

set(BLOWFISH_TEST ${PROJECT_SOURCE_DIR}/tests/Main.cpp)
set(BLOWFISH2_TEST ${PROJECT_SOURCE_DIR}/tests/Main2.cpp)
source_group(tests FILES ${BLOWFISH_TEST} ${BLOWFISH2_TEST})
set(BF_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)

set(BLOWFISH_INC ${PROJECT_SOURCE_DIR}/include/blowfish/blowfish.h)
set(BLOWFISH2_INC ${PROJECT_SOURCE_DIR}/include/blowfish/blowfish2.h)
source_group(include FILES ${BLOWFISH_INC} ${BLOWFISH2_INC})
# ===== blowfish library =====
add_library(blowfish)
target_compile_features(blowfish PUBLIC cxx_std_17)

set(BLOWFISH_DOC
README.md
LICENSE
target_sources(blowfish
PRIVATE
src/blowfish.cc
PUBLIC FILE_SET HEADERS
BASE_DIRS ${BF_INCLUDE_DIR}
FILES include/blowfish/blowfish.h
)
source_group(doc FILES ${BLOWFISH_DOC})

set(BLOWFISH_SCRIPTS
.gitattributes
.gitignore
build.sh
)
source_group(scripts FILES ${BLOWFISH_SCRIPTS})
target_include_directories(blowfish PUBLIC ${BF_INCLUDE_DIR})

add_library(blowfish ${BLOWFISH_SRC} ${BLOWFISH_INC} ${BLOWFISH_SCRIPTS} ${BLOWFISH_DOC})
add_library(blowfish2 ${BLOWFISH2_SRC} ${BLOWFISH2_INC} ${BLOWFISH_SCRIPTS} ${BLOWFISH_DOC})
# ===== blowfish2 library =====
add_library(blowfish2)
target_compile_features(blowfish2 PUBLIC cxx_std_14)

target_include_directories(blowfish PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_include_directories(blowfish2 PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_sources(blowfish2
PRIVATE
src/blowfish2.cc
PUBLIC FILE_SET HEADERS
BASE_DIRS ${BF_INCLUDE_DIR}
FILES include/blowfish/blowfish2.h
)

add_executable(bf_test ${BLOWFISH_TEST} ${BLOWFISH_SRC} ${BLOWFISH_INC})
add_executable(bf2_test ${BLOWFISH2_TEST} ${BLOWFISH2_SRC} ${BLOWFISH2_INC})
target_include_directories(blowfish2 PUBLIC ${BF_INCLUDE_DIR})

target_include_directories(bf_test PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_include_directories(bf2_test PUBLIC ${PROJECT_SOURCE_DIR}/include)
# ===== Tests =====
include(CTest)
if(BUILD_TESTING)
add_executable(bf_test tests/Main.cpp)
target_link_libraries(bf_test PRIVATE blowfish)
add_test(NAME bf_test COMMAND bf_test)

add_executable(bf2_test tests/Main2.cpp)
target_link_libraries(bf2_test PRIVATE blowfish2)
add_test(NAME bf2_test COMMAND bf2_test)
endif()
53 changes: 46 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,68 @@
# Blowfish and Blowfish2 Encryption Algorithm

<p align=center><a href="https://github.com/avinal/blowfish/actions"><img alt="build" src="https://github.com/avinal/blowfish/workflows/build/badge.svg?branch=main"></a><a href="https://github.com/avinal/blowfish/blob/main/LICENSE"><img src="https://img.shields.io/github/license/avinal/blowfish" alt="license"></a></p>
[![Build Status](https://github.com/avinal/blowfish/actions/workflows/cmake.yml/badge.svg)](https://github.com/avinal/blowfish/actions/workflows/cmake.yml)

Blowfish is a symmetric block cipher that can be used as a drop-in replacement for DES or IDEA. It takes a variable-length key, from 32 bits to 448 bits, making it ideal for both domestic and exportable use. Blowfish was designed in 1993 by Bruce Schneier as a fast, free alternative to existing encryption algorithms. Since then it has been analyzed considerably, and it is slowly gaining acceptance as a strong encryption algorithm. Blowfish is unpatented and license-free, and is available free for all uses.
Blowfish is a symmetric block cipher that can be used as a drop-in replacement for DES or IDEA. It
takes a variable-length key, from 32 bits to 448 bits, making it ideal for both domestic and
exportable use. Blowfish was designed in 1993 by Bruce Schneier as a fast, free alternative to
existing encryption algorithms. Since then it has been analyzed considerably, and it is slowly
gaining acceptance as a strong encryption algorithm. Blowfish is not patented and license-free,
and is available free for all uses.

Blowfish 2 was released in 2005. It has exactly the same design but has twice as many S tables and uses 64-bit integers instead of 32-bit integers. It no longer works on 64-bit blocks but on 128-bit blocks like AES. 128-bit block, 64 rounds, key up to 4224 bits.
Blowfish 2 was released in 2005. It has exactly the same design but has twice as many S tables and
uses 64-bit integers instead of 32-bit integers. It no longer works on 64-bit blocks but on 128-bit
blocks like AES. 128-bit block, 64 rounds, key up to 4224 bits.

## About this project

This is a C++ implementation of the encryption algorithm.

## How to use this in your project?

1. You may fork it and use it like any other source file in your project. You only need [blowfish.hpp](include/blowfish/blowfish.hpp) and [blowfish.cpp](src/blowfish.cpp) files. Just modify the header as per your convienence.
2. If you are using CMake, the work is lot easier. You can add this as a git submodule. It isolates your project from this dependency.
1. You may fork it and use it like any other source file in your project. You only need
[blowfish.hpp](include/blowfish/blowfish.hpp) and [blowfish.cpp](src/blowfish.cpp) files. Just
modify the header as per your convenience.

2. If you are using CMake, the work is lot easier. You can add this as a git submodule. It isolates
your project from this dependency.

```bash
# In your project root type these commands
git submodule add https://github.com/avinal/blowfish
# considering this addition is your only change
git commit -m "blowfish submodule added"
git push origin main
```
```

Add this to your CMakeLists.txt as well.

## Building

This library has no dependencies on any other code. Just a C++ compiler should be enough to build
this. Although this library is supposed to be used under some other project, sometimes you may need
to build this. Here are the prerequisites:

- [CMake](https://cmake.org/download/)
- [G++](https://gcc.gnu.org/) or [Clang](https://clang.llvm.org/)
- [Make](https://www.gnu.org/software/make/) or [Ninja Build](https://ninja-build.org/) or any other CMake compatible generator.

Here is how I install them on Fedora:

```shell
sudo dnf install clang cmake g++ make ninja-build
```

Configure CMake, enabled debug for development purposes:

```shell
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
```

Build using configured generator:

Add this to your CMakeLists.txt as well.
```shell
cmake --build build --config Debug
```

## References

Expand Down
22 changes: 12 additions & 10 deletions include/blowfish/blowfish.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,34 @@
// Original Blowfish Algorithm copyright:
// SPDX-FileCopyrightText: 1997 Paul Kocher

#include <algorithm>
#pragma once
#include <array>
#include <cstdint>
#include <string>

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

#if !defined(BLOWFISH_BLOWFISH_H_)
#define BLOWFISH_BLOWFISH_H_

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

public:
Blowfish() {}
Blowfish(std::string const &key);
Blowfish() = default;
explicit Blowfish(std::string const &key);
Blowfish(Blowfish const &) = delete;

void initialize(std::string const &key);
void initialize(const uint8_t *key, size_t keylen);
void initialize(const std::string &key);

void encrypt(uint32_t &xl, uint32_t &xr);
void decrypt(uint32_t &xl, uint32_t &xr);
void encrypt(uint32_t &xl, uint32_t &xr) noexcept;
void decrypt(uint32_t &xl, uint32_t &xr) noexcept;
~Blowfish();
};

#endif // BLOWFISH_BLOWFISH_H_
25 changes: 14 additions & 11 deletions include/blowfish/blowfish2.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,35 @@
// Original Blowfish 2 Algorithm copyright:
// SPDX-FileCopyrightText: 2005 Alexander Pukall

#include <algorithm>
#pragma once
#include <array>
#include <cstdint>
#include <string>

#define MAXKEYBYTES 56 // 4224 bits max
#define N 64
#define MAXKEYBYTES 56 // 448 bits max

#if !defined(BLOWFISH_BLOWFISH2_H_)
#define BLOWFISH_BLOWFISH2_H_

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

public:
Blowfish2() {}
Blowfish2(std::string const &key);
Blowfish2(Blowfish2 const &) = delete;
Blowfish2() = default;
explicit Blowfish2(const std::string &key) { initialize(key); }

Blowfish2(const Blowfish2 &) = delete;
Blowfish2 &operator=(const Blowfish2 &) = delete;

void initialize(std::string const &key);
void initialize(const uint8_t *key, size_t keylen);

void encrypt(uint64_t &xl, uint64_t &xr);
void decrypt(uint64_t &xl, uint64_t &xr);
void encrypt(uint64_t &xl, uint64_t &xr) noexcept;
void decrypt(uint64_t &xl, uint64_t &xr) noexcept;
};

#endif // BLOWFISH_BLOWFISH2_H_
Loading