RC4 is a stream cipher that was created by Ron Rivest, and created in 1987. It is generally a fast cipher, and where we create a key stream based on a password. RC4 was used in WEP (Wired Equivalent Privacy), and where a small IV value caused serious security problems. The key length can vary from one to 256 bytes, and is used to create an initial 256-byte state vector (S). The output is basically X-OR'ed one bit at a time with the keystream, and the plaintext is recovered by X-OR'ing the cipherstream with the keystream. As we are using a stream cipher, there is no need for padding, and where the ciphertext stream size will be the same as the plaintext length.
RC4 with Bouncy Castle and C# |
Coding
First we create a folder named "bc_rc4", 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 RC4 { using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; class Program { static void Main(string[] args) { var msg="Hello"; var size=512; if (args.Length >0) msg=args[0]; try { var plainTextData=System.Text.Encoding.UTF8.GetBytes(msg); var cipher = new RC4Engine(); CipherKeyGenerator keyGen = new CipherKeyGenerator(); keyGen.Init(new KeyGenerationParameters(new SecureRandom(), size)); KeyParameter keyParam = keyGen.GenerateKeyParameter(); cipher.Init(true,keyParam); int outputSize = plainTextData.Length; byte[] cipherTextData = new byte[outputSize]; cipher.ProcessBytes(plainTextData, 0, plainTextData.Length, cipherTextData, 0); var rtn = cipherTextData; // Decrypt cipher.Init(false,keyParam); 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("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)); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run is:
=== RC4 == Message: Hello 123 IV: 00112233445566778899AABBCCDDEEFF Key size: 128 bits Key: BD03B43CCAB7009822551578AC6E5C53 [vQO0PMq3AJgiVRV4rG5cUw==] Cipher (hex): 7527E4782509FCBDC2 Cipher (Base64): dSfkeCUJ/L3C Plain: Hello 123