Kalyna — The Ukrainian Cipher

The Kalyna (Ukrainian: Калина, Viburnum opulus) cipher uses block sizes of 128, 256 and 512 bits (and where the key size can be up to…

Kalyna — The Ukrainian Cipher

The Kalyna (Ukrainian: Калина, Viburnum opulus) cipher uses block sizes of 128, 256 and 512 bits (and where the key size can be up to double the block size). A 128-bit block size can thus support a 256-bit key, while a 256-bit block size can support a 512-bit key. In 2015, it was defined as a standard in Ukraine as DSTU 7624:2014 [1]:

Before 2015, Ukraine mainly used the Russian-defined GOST 28147–89 symmetric key method. And so, while GOST 28147–89 was efficient in hardware, it was slower than the AES method. The State Service of Special Communication and Information Protection of Ukraine then organised the National Public Cryptographic Competition — of which Kalyna was named the winner.

Overall, Kalyna uses a substitution–permutation network (SPN) and is based on the Rijndael (AES) approach of scheduling part of the key in each round. It has 10 rounds for 128-bit keys, 14 rounds for 256-bit keys and 18 rounds for 512-bit keys.

First we create a folder named “bc_dstu”, 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 using a 128-bit block size (var cipher = new Dstu7624Engine(128)) [here]:

namespace Serpent
{
using Org.BouncyCastle.Crypto;
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="00112233445566778899AABBCCDDEEFF00";
var size=128;
var mode="CBC";
if (args.Length >0) msg=args[0];
if (args.Length >1) iv=args[1];
if (args.Length >2) size=Convert.ToInt32(args[2]);
if (args.Length >3) mode=args[3];



try {
var plainTextData=System.Text.Encoding.UTF8.GetBytes(msg);
var cipher = new Dstu7624Engine(128);

byte[] nonce = new byte[8];
Array.Copy(Convert.FromHexString(iv), nonce, 8);

PaddedBufferedBlockCipher cipherMode = new PaddedBufferedBlockCipher(new CbcBlockCipher(cipher), new Pkcs7Padding());

if (mode=="ECB") cipherMode = new PaddedBufferedBlockCipher(new EcbBlockCipher (cipher), new Pkcs7Padding());
else if (mode=="CFB") cipherMode = new PaddedBufferedBlockCipher(new CfbBlockCipher (cipher,128 ), new Pkcs7Padding());

CipherKeyGenerator keyGen = new CipherKeyGenerator();
keyGen.Init(new KeyGenerationParameters(new SecureRandom(), size));
KeyParameter keyParam = keyGen.GenerateKeyParameter();

cipherMode.Init(true,keyParam);
int outputSize = cipherMode.GetOutputSize(plainTextData.Length);
byte[] cipherTextData = new byte[outputSize];
int result = cipherMode.ProcessBytes(plainTextData, 0, plainTextData.Length, cipherTextData, 0);
cipherMode.DoFinal(cipherTextData, result);
var rtn = cipherTextData;

// Decrypt
cipherMode.Init(false,keyParam);
outputSize = cipherMode.GetOutputSize(cipherTextData.Length);
plainTextData = new byte[outputSize];
result = cipherMode.ProcessBytes(cipherTextData, 0, cipherTextData.Length,plainTextData, 0);

cipherMode.DoFinal(plainTextData, result);
var pln=plainTextData;

Console.WriteLine("=== {0} ==",cipher.AlgorithmName);
Console.WriteLine("Message:\t\t{0}",msg);
Console.WriteLine("Block size:\t\t{0} bits",cipher.GetBlockSize()*8);
Console.WriteLine("Mode:\t\t\t{0}",mode);
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 [here]:

=== DSTU7624 ==
Message: Hello 123
Block size: 128 bits
Mode: ECB
IV: 00112233445566778899AABBCCDDEEFF00
Key size: 256 bits
Key: F03634910C9E9BF814A4726A882F971E939FBEC12D64E7E3139EB766FB20ECFB [8DY0kQyem/gUpHJqiC+XHpOfvsEtZOfjE563Zvsg7Ps=]
Cipher (hex): A626AADD6A0862178C52978762618313
Cipher (Base64): piaq3WoIYheMUpeHYmGDEw==
Plain: Hello 123

Conclusions

In some areas of the world, the NIST define standards are just now trusted. In China, we have SM4 [here] as a replacement for AES, and in Russian we have GOST 28147 [here].

References

[1] Oliynykov, R., Gorbenko, I., Kazymyrov, O., Ruzhentsev, V., Kuznetsov, O., Gorbenko, Y., … & Kaidalov, D. (2015). A new encryption standard of Ukraine: The Kalyna block cipher. Cryptology ePrint Archive [paper].