This is an enhancement to CAST5.
CAST6 with Bouncy Castle and C# |
Outline
CAST5 (or CAST-128) was created by Carlisle Adams and Stafford Tavares in 1996. It defines a symmetric key method that has a 64-bit block size, and key sizes from 40 bits up to 128 bits (in jumps of 8 bits). Typically any key less than 80 bits would be seen as being insecure. It uses a 12- or 16-round Feistel cipher. The 16-round version is used for keys for 80 bits and above. It has been standardized in RFC2612 [here]:
Phil Zimmerman could not believe there was no real security or trust built into email. So, in 1991, he created PGP (Pretty Good Privacy). With this, Bob creates a random symmetric key, which is used to encrypt a message. Bob then encrypts this symmetric key with Alice’s public key. When she receives the email she discovers the symmetric key with her private key and then decrypts the message:
But, Phil’s code then appeared outside the US, and in 1993 he was involved in a criminal investigation “munitions export without a license. While this was underway, his team released PGP 3, which improved the overall security of the software. With this, the team avoided RSA for the public key method, as it was protected under patent or royalty free. For signatures, they went for DSA and ElGamal, and for the symmetric key method, they chose CAST5 (which is royalty-free). A 256-bit version is also available as CAST-256.
PGP has advanced to the GNU Privacy Guard (GPG) and is based on OpenPGP. It ow supports the public key methods of RSA, ELG, DSA, ECDH, ECDSA, and EDDSA. Also symmetric key ciphers of IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128, CAMELLIA192, and CAMELLIA256, along with SHA1, RIPEMD160, SHA256, SHA384, SHA512, and SHA224. The compression methods supports are ZIP, ZLIB, and BZIP2: here]
Coding
First we create a folder named "bc_cast6", 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 CAST6 { 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="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 Cast6Engine(); byte[] nonce = new byte[16]; Array.Copy(Convert.FromHexString(iv), nonce, 16); 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(); ICipherParameters keyParamIV = new ParametersWithIV(keyParam,nonce); if (mode=="ECB") { cipherMode.Init(true,keyParam); } else { cipherMode.Init(true,keyParamIV); } 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:
=== CAST6 == Message: Hello 123 Block size: 128 bits Mode: ECB IV: 00112233445566778899AABBCCDDEEFF00 Key size: 128 bits Key: 22F3ACAD3BD60F3CAB9B47578879DC30 [IvOsrTvWDzyrm0dXiHncMA==] Cipher (hex): CED27894261FCC436EFC589A8F6B97CF Cipher (Base64): ztJ4lCYfzENu/Fiaj2uXzw== Plain: Hello 123