With key wrapping we take a secret symmetric key and encrypted it. This typically happens when we want to take a back-up of a symmetric key. For this we can either encrypted it with symmetric key encryption or public key encryption. For public key encryption, we create a key pair, and then encrypt the key with our public key - and which will wrap the key. To reveal the key, we can decrypt with the associated private key.
FIPS RSA Key Wrapping using Bouncy Castle and C# |
Method
And, so, we are using a symmetric key to encrypt data, and it runs in a secure enclave. But what happens if they enclave breaks? You will obviously lose your encryption key, and will not be able to decrypt your data. For this, we use key wrapping and where we can wrap a key and export it from a secure environment into one which is insecure..
With key wrapping, we take a secret symmetric key and encrypt it. This typically happens when we want to take a back-up of a symmetric key. For this, we can either encrypt it with symmetric key encryption or public key encryption. For public key encryption, we create a key pair and then encrypt the key with our public key - and which will wrap the key. To reveal the key, we can decrypt it with the associated private key.
Let's see if we can use the FIPS library in Bouncy Castle to wrap a key with RSA encryption. For this we will create an RSA key pair with:
// Generate key pair FipsRsa.KeyGenerationParameters keyGenParameters = new FipsRsa.KeyGenerationParameters(new Org.BouncyCastle.Math.BigInteger("65537"), 2048); FipsRsa.KeyPairGenerator kpGen =CryptoServicesRegistrar.CreateGenerator(keyGenParameters, new SecureRandom()); var pair = kpGen.GenerateKeyPair();
and then we will take a hex definition of a key (keystr) and convert it into a byte array:
var inputData=System.Convert.FromHexString(keystr);
To wrap, we use the public key (key.PublicKey) :
var provider = CryptoServicesRegistrar.CreateService(pair.PublicKey, new SecureRandom()); IKeyWrapper<FipsRsa.OaepWrapParameters> wrapper = provider.CreateKeyWrapper(FipsRsa.WrapOaep); byte[] wrappedInput = wrapper.Wrap(inputData).Collect();
and then to unwrap, we use the private key (key.PrivateKey):
var provider2 = CryptoServicesRegistrar.CreateService(pair.PrivateKey, new SecureRandom()); IKeyUnwrapper<FipsRsa.OaepWrapParameters> unwrapper = provider2.CreateKeyUnwrapper(FipsRsa.WrapOaep); byte[] res = unwrapper.Unwrap(wrappedInput, 0, wrappedInput.Length).Collect();
Code
First we create a folder named "bc_wrap01", 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 Wrapping { using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Fips; using Org.BouncyCastle.Security; class Program { static void Main(string[] args) { var keystr="01020304"; if (args.Length >0) keystr=args[0]; try { var inputData=System.Convert.FromHexString(keystr); FipsRsa.KeyGenerationParameters keyGenParameters = new FipsRsa.KeyGenerationParameters(new Org.BouncyCastle.Math.BigInteger("65537"), 2048); FipsRsa.KeyPairGenerator kpGen =CryptoServicesRegistrar.CreateGenerator(keyGenParameters, new SecureRandom()); var pair = kpGen.GenerateKeyPair(); var provider = CryptoServicesRegistrar.CreateService(pair.PublicKey, new SecureRandom()); IKeyWrapper<FipsRsa.OaepWrapParameters> wrapper = provider.CreateKeyWrapper(FipsRsa.WrapOaep); byte[] wrappedInput = wrapper.Wrap(inputData).Collect(); var provider2 = CryptoServicesRegistrar.CreateService(pair.PrivateKey, new SecureRandom()); IKeyUnwrapper<FipsRsa.OaepWrapParameters> unwrapper = provider2.CreateKeyUnwrapper(FipsRsa.WrapOaep); byte[] res = unwrapper.Unwrap(wrappedInput, 0, wrappedInput.Length).Collect(); Console.WriteLine("Key: {0}",Convert.ToHexString(inputData)); Console.WriteLine("Wrapped: {0}",Convert.ToHexString(wrappedInput)); Console.WriteLine("Unwrapped: {0}",Convert.ToHexString(res)); Console.WriteLine("\n\nPublic key==="); Console.WriteLine("Public key modulus: {0}",pair.PublicKey.Modulus); Console.WriteLine("Public key exponent: {0}",pair.PublicKey.PublicExponent); Console.WriteLine("\n\nPrivate key==="); Console.WriteLine("Private key modulus: {0}",pair.PrivateKey.Modulus); Console.WriteLine("Private key private exponent: {0}",pair.PrivateKey.PrivateExponent); Console.WriteLine("Private key p: {0}",pair.PrivateKey.P); Console.WriteLine("Private key q: {0}",pair.PrivateKey.Q); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run with Dilithium5 gives:
Key: 0102030405060708 Wrapped: 3FE2AC058F6E0F58DAE6727D1417CB2D8F254F50BFC07FEC8D7E41E9398241CC6885B0B401183673268439F329756F5901B37655B3A7A84891DBD9CE78DCB4B280FB6BC697074928711B93801BEBAD5926C95B86F2F11DC14904A68CD04187FEA243853788310BEBE21718D39E5669FB423298052057CD5E49F10C6DD357DA5EF8B963B7DF8C89BFF1DE88DB1F701F5298CA38A815CA76D14F0234C5428B380B35FC7F79DE4C72535880E3A9D351FB79060F4ACF454CA1737DE293D960B88B01D207FE3CC37CB3A6D5EAD90FF36E7661D9706BD8209600646EA475700DCD3432F8F7F3EB91EE166EEE5C04937F5F4B7FD95DFCA2608D239C9E2E63FF84A13386 Unwrapped: 0102030405060708 Public key=== Public key modulus: 22503650939989650560672963362414746771647270124046189482217506719636659622360483832730191179853436633314024390254516906191244742851173203871684130500795253977914886195447128900018425725788748478513966722398769488855613797492245137154062352014301795888237794114575727868535557746896387345381736319064837099505516471494013101844778630607343924082884634663624509734790083887133204127377818078573384888427197639791646099716884812558038717329177733930043359943129999614736472380827806078652193560375969213627065696173581427703281825184713374309075102998915048134043000764869302183034706275259552828088104674317821034104413 Public key exponent: 65537 Private key=== Private key modulus: 22503650939989650560672963362414746771647270124046189482217506719636659622360483832730191179853436633314024390254516906191244742851173203871684130500795253977914886195447128900018425725788748478513966722398769488855613797492245137154062352014301795888237794114575727868535557746896387345381736319064837099505516471494013101844778630607343924082884634663624509734790083887133204127377818078573384888427197639791646099716884812558038717329177733930043359943129999614736472380827806078652193560375969213627065696173581427703281825184713374309075102998915048134043000764869302183034706275259552828088104674317821034104413 Private key private exponent: 1923405110706196921061531719098619162326352802231483442706278344905087948405515208035738070005478207753002237240195255352400284222360600904637665089952311139620218121424494446395978023147316395355234212666382460164864438205178923902047397116256641434120634202554220358814134408337887204405996551432651555806314745200248058491899397670450638058084198387190866311268676902037449374737110366307856249682929951981986969530415324401781237825675908889424662563976823186960390277350289182734524905933336479827169024274857523189140287272651790907560926559244574208582252158235904222762875685697274157428889856644532600189499 Private key p: 175325944459152449849066741265899665881078553976429490827462752253148437573387531725399819818747686651031453866371966057471290171717498802038100335103913474757543628625084172646890438344054202261180849763690039918041934759669446593896922641769801972565770506060536666815609252475864888358306675893022777193039 Private key q: 128353228094160162829086292513181711895261956059254850476005383951140279263325114960459399507284147009492621015231383442540651582824505254538489911453907044411116986299677691264151866090993315671307261137850417108334238905311638023341985781904389264600490154496267962490527208708483716679337490540707742117267