https://github.com/samuel-lucas6/tango12
A stream cipher based on BLAKE2b.
https://github.com/samuel-lucas6/tango12
blake2 blake2b blake2b-hash-algorithm cipher crypto cryptography encryption keystream stream-cipher
Last synced: 12 months ago
JSON representation
A stream cipher based on BLAKE2b.
- Host: GitHub
- URL: https://github.com/samuel-lucas6/tango12
- Owner: samuel-lucas6
- License: mit
- Created: 2021-02-09T22:29:52.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2022-04-11T15:33:25.000Z (about 4 years ago)
- Last Synced: 2025-06-09T23:46:47.851Z (12 months ago)
- Topics: blake2, blake2b, blake2b-hash-algorithm, cipher, crypto, cryptography, encryption, keystream, stream-cipher
- Language: C#
- Homepage: https://samuellucas.com/Tango12
- Size: 133 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
[](https://github.com/samuel-lucas6/Tango12/blob/main/LICENSE)
[](https://github.com/samuel-lucas6/Tango12/actions)
# Tango12
A stream cipher based on BLAKE2b. There are two modes:
1. Tango12d: *deterministic* mode. No nonce is required.
2. Tango12p: *probabilistic* mode. A nonce is required.
## Should I use this?
⚠️**NO, this is a demo of how a keyed hash function can be turned into a stream cipher.**
## How do I play around with this?
1. Install the [Sodium.Core](https://www.nuget.org/packages/Sodium.Core) NuGet package in [Visual Studio](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio).
2. Download the latest [release](https://github.com/samuel-lucas6/Tango12/releases).
3. Move the downloaded DLL file into your Visual Studio project folder.
3. Click on the ```Project``` tab and ```Add Project Reference...``` in Visual Studio.
4. Go to ```Browse```, click the ```Browse``` button, and select the downloaded DLL file.
Note that the [libsodium](https://doc.libsodium.org/) library requires the [Visual C++ Redistributable for Visual Studio 2015-2019](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads) to work on Windows. If you want your program to be portable, then you must keep the relevant (x86 or x64) ```vcruntime140.dll``` file in the same folder as your executable on Windows.
### Tango12d
⚠️**WARNING: Never reuse a key.**
```c#
const string message = "This is a test.";
const int keyLength = 64;
// The message could be a file
byte[] message = Encoding.UTF8.GetBytes(message);
// The key should be random for each message
byte[] key = SodiumCore.GetRandomBytes(keyLength);
// Encrypt the message
byte[] ciphertext = Tango12d.Encrypt(message, key);
// Decrypt the ciphertext
byte[] plaintext = Tango12d.Decrypt(ciphertext, key);
```
### Tango12p
⚠️**WARNING: Never reuse a nonce with the same key.**
```c#
const string message = "This is a test.";
const int nonceLength = 24;
const int keyLength = 32;
// The message could be a file
byte[] message = Encoding.UTF8.GetBytes(message);
// The nonce can be random. Increment the nonce for each message encrypted using the same key
byte[] nonce = SodiumCore.GetRandomBytes(nonceLength);
// The key can be random or derived using a KDF (e.g. Argon2, HKDF, etc)
byte[] key = SodiumCore.GetRandomBytes(keyLength);
// Encrypt the message
byte[] ciphertext = Tango12p.Encrypt(message, nonce, key);
// Decrypt the ciphertext
byte[] plaintext = Tango12p.Decrypt(ciphertext, nonce, key);
```
## How does it work?
### Constants
```c#
internal const int BlockSize = 64;
internal const int CounterLength = 64;
internal const int NonceLength = 24;
internal const int KeyLength = 64;
```
### Tango12d
1. An empty 64 byte counter is created.
```c#
var counter = new byte[Constants.CounterLength];
```
2. The message is read in blocks of 64 bytes.
```c#
var buffer = new byte[Constants.BlockSize];
using var memoryStream = new MemoryStream(message);
while ((bytesRead = memoryStream.Read(buffer, offset: 0, buffer.Length)) > 0)
```
3. For each block, BLAKE2b-512, with the counter as the message and the key as the key, is used to generate a keystream block.
```c#
byte[] keystreamBlock = GenericHash.Hash(counter, key, Constants.BlockSize);
```
4. The message block and keystream block are XORed together to produce the ciphertext block.
```c#
internal static byte[] Xor(byte[] message, byte[] keystream)
{
var ciphertext = new byte[message.Length];
for (int i = 0; i < ciphertext.Length; i++)
{
ciphertext[i] = (byte)(message[i] ^ keystream[i]);
}
return ciphertext;
}
```
5. The counter is incremented.
```c#
counter = Utilities.Increment(counter);
```
6. This continues until the end of the message is reached.
### Tango12p
1. An empty 64 byte counter is created.
```c#
var counter = new byte[Constants.CounterLength];
```
2. The counter and 24 byte nonce are concatenated together.
```c#
var counter = new byte[Constants.CounterLength];
counter = Arrays.Concat(counter, nonce);
```
3. The message is read in blocks of 64 bytes.
```c#
var buffer = new byte[Constants.BlockSize];
using var memoryStream = new MemoryStream(message);
while ((bytesRead = memoryStream.Read(buffer, offset: 0, buffer.Length)) > 0)
```
4. For each block, BLAKE2b-512, with the counter and nonce as the message and the key as the key, is used to generate a keystream block.
```c#
byte[] keystreamBlock = GenericHash.Hash(counter, key, Constants.BlockSize);
```
4. The message block and keystream block are XORed together to produce the ciphertext block.
```c#
internal static byte[] Xor(byte[] message, byte[] keystream)
{
var ciphertext = new byte[message.Length];
for (int i = 0; i < ciphertext.Length; i++)
{
ciphertext[i] = (byte)(message[i] ^ keystream[i]);
}
return ciphertext;
}
```
5. The counter is incremented.
```c#
counter = Utilities.Increment(counter);
```
6. This continues until the end of the message is reached.