HC-256 is a stream cipher that was created in 2004 by Hongjun Wu. It has a 128-bit key and a 256-bit nonce value. It focuses on bulk encryption in software at high speeds and also provides strong security levels. It has a performance level of around 1.93 bits/cycle.
HC256 with Bouncy Castle and C# |
Method
The HC-256 method was created in 2004, and uses a 256-bit key (K) and a 256-bit nonce (IV) value. Internally it has two secret tables: P and Q, and where each table has 1,024 32-bit words. Basically, these represent state values, and each change of state will update one of the entries of the table, and which uses a non-linear update function. Thus, after 2,048 state changes, every element of the tables will have been updated. We then derive the final has by taking a SHA-256, but where we use the P and Q tables as S-boxes. Overall, it is a fast-stream cipher with just four CPU cycles per byte.
The basic functions that HC-256 uses are simple and involve either EX-OR, mod, add or bit shift operations:
Figure [1]
As we have a stream cipher, we basically take the key and the IV, and expand into a key stream (s). The cipher is then:
\(c = p ^ s\)
and where we EX-OR each bit of the plaintext (p) with the bits in the keystream (s), and generate a cipher stream (c ). In order to recover the plaintext, we just EX-OR again with the key stream:
\(p = c ^ s\)
Key and IV setup
The initialization phase provides an expansion of the 256-bit key into the P and Q tables. With this, we take the key and the IV, and split them up into eight 32-bit values (K_0 … K_7, and IV_0 … IV_7). Next, we compute W_i and then use these values to fill the P and Q tables:
Figure [1]
Keystream expansion
In this stage, we generate the key stream (s). Each step will update one of the entries in either the P table or the Q table:
Figure [1]
This will then create the S-box values for the SHA-256 operation. Once generated, the plaintext and cipher stream is just EX-ORed with the expanded key stream.
Coding
First we create a folder named "bc_hc256", and then go into that folder. We can create a Dotnet console project for .NET 8.0 with:
dotnet new console --framework net8.0
This produces a Csproject file of:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>
We then add the latest Bouncy Castle library:
dotnet add package BouncyCastle.Cryptography --version 2.2.1
The following is the coding:
namespace HC256 { using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Paddings; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; class Program { static void Main(string[] args) { var msg="Hello"; var iv="00112233445566778899AABBCCDDEEFF"; var size=256; if (args.Length >0) msg=args[0]; if (args.Length >1) iv=args[1]; try { var plainTextData=System.Text.Encoding.UTF8.GetBytes(msg); var cipher = new HC256Engine(); byte[] nonce = new byte[16]; Array.Copy(Convert.FromHexString(iv), nonce, 16); CipherKeyGenerator keyGen = new CipherKeyGenerator(); keyGen.Init(new KeyGenerationParameters(new SecureRandom(), size)); KeyParameter keyParam = keyGen.GenerateKeyParameter(); ParametersWithIV keyParamIV = new ParametersWithIV(keyParam,nonce); cipher.Init(true,keyParamIV); int outputSize = plainTextData.Length; byte[] cipherTextData = new byte[outputSize]; cipher.ProcessBytes(plainTextData, 0, plainTextData.Length, cipherTextData, 0); var rtn = cipherTextData; // Decrypt cipher.Init(false,keyParamIV); outputSize = cipherTextData.Length; plainTextData = new byte[outputSize]; cipher.ProcessBytes(cipherTextData, 0, cipherTextData.Length,plainTextData, 0); var pln=plainTextData; Console.WriteLine("=== {0} ==",cipher.AlgorithmName); Console.WriteLine("Message:\t\t{0}",msg); Console.WriteLine("IV:\t\t\t{0}",iv); Console.WriteLine("Key size:\t\t{0} bits",size); Console.WriteLine("Key:\t\t\t{0} [{1}]",Convert.ToHexString(keyParam.GetKey()),Convert.ToBase64String(keyParam.GetKey())); Console.WriteLine("\nCipher (hex):\t\t{0}",Convert.ToHexString(rtn)); Console.WriteLine("Cipher (Base64):\t{0}",Convert.ToBase64String(rtn)); Console.WriteLine("\nPlain:\t\t\t{0}",System.Text.Encoding.ASCII.GetString(pln).TrimEnd('\0')); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run is:
=== HC-256 == Message: Hello 123 IV: 00112233445566778899AABBCCDDEEFF00 Key size: 256 bits Key: FD1A85C4E0251E5469BE704A7597E11594BEC56C0F5A89F8F9F2FF40FB77C33D [/RqFxOAlHlRpvnBKdZfhFZS+xWwPWon4+fL/QPt3wz0=] Cipher (hex): 788E4A144F8BA87FD2 Cipher (Base64): eI5KFE+LqH/S Plain: Hello 123
References
[1] Wu, H. (2004). A new stream cipher HC-256. In Fast Software Encryption: 11th International Workshop, FSE 2004, Delhi, India, February 5-7, 2004. Revised Papers 11 (pp. 226-244). Springer Berlin Heidelberg.