And, so, NIST has defined AES as the standard for symmetric key encryption. But, NIST were pin-pointed in possibly pushing a cipher with an NSA backdoor. For companies in China, the ShāngMì (SM) series of ciphers provides one alternative for TLS 1.3 integration and Wireless authentication. SM2 defines authentication, SM3 define a hashing function and SM4 for encryption. SM4 was developed by Lü Shuwang in 2007, and became a national standard (GB/T 32907–2016) in 2016. It has also been defined in RFC 8998. With the SM4 block cipher we have a block size of 128-bits, and with a 128-bit encryption key. Each block of data has 32 rounds of processing. Overall, we can add a salt value of 128 bits in an IV (Initialisation Vector).
SM4 with Bouncy Castle and C# |
Coding
First we create a folder named "bc_blowfish", 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 SM4 { 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 SM4Engine(); 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:
=== SM4 == Message: Hello 123 Block size: 128 bits Mode: ECB IV: 00112233445566778899AABBCCDDEEFF00 Key size: 128 bits Key: 4CFA20685BE4D44CE5907C05FDFECC8D [TPogaFvk1EzlkHwF/f7MjQ==] Cipher (hex): 3A0D96CCE2D782DFF832F5D09C0FA7F2 Cipher (Base64): Og2WzOLXgt/4MvXQnA+n8g== Plain: Hello 123