HMAC is a message authentication code (MAC) that can be used to verify the integrity and authentication of a message. It involves hashing the message with a secret key and thus differs from standard hashing, which is purely a one-way function. As with any MAC, it can be used with a standard hash function, such as MD5 or SHA-1, which results in methods such as HMAC-MD5 or HMAC-SHA-1. Also, as with any hashing function, the strength depends on the quality of the hashing function, and the resulting number of hash code bits. Along with this, the number of bits in the secret key is a factor in the strength of the hash. The figure below outlines the operation, where the message to be sent is converted with a secret key, and the hashing function, to an HMAC code. This is then sent with the message. On receipt, the receiver recalculates the HMAC code from the same secret key, and the message, and checks it against the received version. If they match, it validates both the sender and the message.
FIPS CMAC using Bouncy Castle and C# |
Code
First we create a folder named "bc_fips_mhac", and then go into that folder.We can create a Dotnet console project for .NET 8.0 with:
dotnet new console --framework net8.0
Next we download the FIPS module (bc-fips-1.0.2.dll) from [here] and add it as a reference to the project:
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> <ItemGroup> <Reference Include="Org.BouncyCastle.Crypto"> <HintPath>bc-fips-1.0.2.dll</HintPath> </Reference> </ItemGroup> </Project>
Next some code:
namespace CMAC { using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Fips; using Org.BouncyCastle.Security; using System.Text.Json; class Program { static void Main(string[] args) { var keystr="0000000000000000000000000000000000000000000000000000000000000000"; var msg="Hello 123"; var size=64; var method="Sha1"; if (args.Length >0) msg=args[0]; if (args.Length >1) size=Convert.ToInt32(args[1]); if (args.Length >2) method=args[2]; var message=System.Text.Encoding.ASCII.GetBytes(msg); var key=System.Convert.FromHexString(keystr); try { var t=FipsShs.Sha1HMac; if (method=="Sha1") t=FipsShs.Sha1HMac; if (method=="Sha224") t=FipsShs.Sha224HMac; if (method=="Sha256") t=FipsShs.Sha256HMac; if (method=="Sha384") t=FipsShs.Sha384HMac; if (method=="Sha512") t=FipsShs.Sha512HMac; var calcFact =CryptoServicesRegistrar.CreateService(new FipsShs.Key(t, key)).CreateMacFactory(t.WithMacSize(size)); IStreamCalculatormacCalculator = calcFact.CreateCalculator(); Stream macStream = macCalculator.Stream; macStream.Write(message, 0, message.Length); macStream.Close(); var mac= macCalculator.GetResult().Collect(); Console.WriteLine("Message: {0}",msg); Console.WriteLine("Hash method: {0}",method); Console.WriteLine("Key: {0}",keystr); Console.WriteLine("HMAC: {0}",Convert.ToHexString(mac)); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run gives:
Message: gdgfg Hash method: Sha256 Key: 0000000000000000000000000000000000000000000000000000000000000000 HMAC: 6D516FF520E3311B594B8976B8F61F0D