Blowpipe: authenticated Blowfish-encrypted pipe
Blowpipe is a toy that creates an authenticated, Blowfish-encrypted pipe. Each cryptographic primitive it uses is built entirely with the Blowfish cipher:
- The key is derived from a passphrase using bcrypt.
- The stream is encrypted with Blowfish in CTR mode.
- The message authentication code (MAC) is Blowfish-CBC-MAC with fixed-length messages.
This tool is strictly stream oriented, processing standard input to standard output. It could be used to encrypt a file (prompted for a passphrase):
$ blowpipe -E < data.gz > data.gz.enc $ blowpipe -D < data.gz.enc | gunzip > data.txt
Or to securely transfer a file over a network:
# receiver $ nc -lp 2000 | blowpipe -D -k keyfile > data.zip || rm -f data.zip # sender $ blowpipe -E -k keyfile < data.zip | nc -N hostname 2000
On a modern desktop, Blowpipe has a throughput of about 75 MB/s.
On decryption, the tool only produces authenticated output. However, the overall output could still be truncated should something go wrong in the middle of a long stream. If the stream has been truncated, an error message will be produced and the exit status will reflect the error.
Since Blowfish is a 64-bit block cipher, it's only safe to encrypt up to a few tens of GBs at a time before birthday attacks become an issue. However, because of the key salt, it's safe to reuse a password or key file to encrypt an arbitrary amount of data across separate runs. Other than the block size, Blowfish is still a solid cipher.
Despite being a toy, Blowpipe is more secure than a few crypto tools typically packaged by a Linux distribution, such as the "bcrypt" file encryption tool (unauthenticated, ECB mode) and aespipe (unauthenticated).
A proper alternative to Blowpipe is aepipe, which is built upon a stronger, newer cipher (AES).
-D decrypt standard input to standard output -E encrypt standard input to standard output -c cost (encrypt) set the bcrypt cost (decrypt) set the maximum permitted bcrypt cost -k file read key material from given file -w wait for full chunks and don't flush early
Use the PREFIX variable to control the installation path. The default is
to install under
$ make PREFIX=$HOME/.local install
To build with MinGW-w64, set CC and EXEEXT. On Linux you can even run
the test suite (
make check) if you have the Wine binfmt configured.
$ make CC=x86_64-w64-mingw32-gcc EXEEXT=.exe
To quickly build with MSVC:
cl.exe -Ox blowpipe.c blowfish.c
There's also an
amalgamation target, which will combine all sources
and headers into a single C source file,
blowpipe-cli.c, ready to be
compiled trivially anywhere by any C99 compiler.
The overall wire format:
- 16-byte random salt
- 1-byte bcrypt cost: last salt byte + cost, modulo 256
- one or more chunks
The format is stream-oriented and data is processed in separate chunks up to 64kB in size, each with its own MAC. A special zero-length chunk marks the end of the stream, and any data following this chunk is ignored.
The chunk format:
- 8 byte MAC for this chunk (continued from previous chunk)
- 2 byte big endian message length, encrypted and authenticated (
msglen - 2bytes of encrypted data
The MAC is computed on the ciphertext. The last block in a chunk has its plaintext zero padded before encryption and authentication, but these bytes are not actually transmitted. The receiver must also zero-pad and encrypt the padding before authenticating.
Since MACs are chained across chunks, it's not possible for an attacker
to reorder individual chunks. The last chunk in the stream will have a
msglen of 2, making it an empty chunk. Since this chunk and its
msglen are authenticated, an attacker cannot prematurely terminate the
stream without being detected.
C99 Public Domain Blowfish Cipher
This repository includes a standalone Blowfish library (
blowfish.h), ready to use in another project. It is a strictly
conforming C99 program with no platform-specific code.
void blowfish_init(struct blowfish *, const void *, int); void blowfish_encrypt(struct blowfish *, uint32_t *, uint32_t *); void blowfish_decrypt(struct blowfish *, uint32_t *, uint32_t *); void blowfish_bcrypt(void *digest, const void *pwd, int len, const void *salt, int cost);
blowfish.h for complete API documentation.