Protecting Your Most Precious of Secrets: FIPS Key Wrapping with RSA
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();The full code is [here]:
namespace Wrap
{
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Fips;
sing 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);
// 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();
// Wrap
var provider = CryptoServicesRegistrar.CreateService(pair.PublicKey, new SecureRandom());
IKeyWrapper<FipsRsa.OaepWrapParameters> wrapper = provider.CreateKeyWrapper(FipsRsa.WrapOaep);
byte[] wrappedInput = wrapper.Wrap(inputData).Collect();
// Unwrap
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 for a key of “0102030405060708” is [here]:
Key: 0102030405060708
Wrapped: A5479932DAA4DD3355F57A7664FEDB02C9E56460A22EAF3B34D173FBC9D72C8458566B2228A59E4C3E1F1CC32B0261EB2EEEF974EC6ECFB2C91A8D0EC1BD00A0972E52F696C15FA63FBC1AFA2142B7674BE222D4103C8B3CB31E24BCFDF93D5DC5BB61667D72BC2E2ACE7777EA0D31C3C717E10E6004EC5C09ED5571422FE58C310FCE5E87ABA0AB71FFD3A5A16CED9F4D60559133C39B851B38A7AB9FAA2466333116D90E09B04B9211F4B24E82A008594A67980E0CB04BD6931DBE730E879189CAFC8E9A8A7A65B6CCE730C46A7C2DAF2CF816FC62D7AE712EB480246C877E733F66CB868FC09074A94E9A2C7E5DC6CD636B5B84044B3D2241930E8CBB5827
Unwrapped: 0102030405060708
Public key modulus: 23978940730260094952461731127828071580637806902289067724659010033947703210730605167745583956173707807584243243237814638070555879076934887692460188585053707204190238630990483459430271176912173433764025385707871745994437184415051127225577451408547124100546811406681622859568227555939708939540551617154945241508428402522405212383256886974027802363630272089415316954507545389453922865581430520339474002544618325676106438225886237575437296636318170324891774347603787637993325192388488046321700539956540191850921884920843742964256775852456061454689752760168164997592801139091902771724420418816614473627849199166795068305959
Public key exponent: 65537
Private key modulus: 23978940730260094952461731127828071580637806902289067724659010033947703210730605167745583956173707807584243243237814638070555879076934887692460188585053707204190238630990483459430271176912173433764025385707871745994437184415051127225577451408547124100546811406681622859568227555939708939540551617154945241508428402522405212383256886974027802363630272089415316954507545389453922865581430520339474002544618325676106438225886237575437296636318170324891774347603787637993325192388488046321700539956540191850921884920843742964256775852456061454689752760168164997592801139091902771724420418816614473627849199166795068305959
Private key private exponent: 4224496844096968984255049019666797602423731914702070219096280419487620447550171159296130618703657938971385209674287926074776663256210845984667368622351192507737316252398128111182719853039168019076848758768071275451298834723227799791667565710409159632954109655637975762341498014264917213420437447116453266985866573531309179990958980632326824386756283161077944748857459637915580141492602025009378443244276052176981054433322884470169890865174658629245009656330728705430565835776189990285425976662402763423315534674013249746137935662790412975361333473408309248557188145854351821162847912630508841474716491891070549200193
Private key p: 158322356933946576153310555251147267536964996147172508770200236597562588245476849738809775923613260595017137143261232422215565820854866946754391495848024741337838579644160898581030728983126669446660473387465520432500646532909121807496225144822687312576491989272589636782783283466771865428205966086867279584689
Private key q: 151456441115668278307567956902145323458062893756169302322194252971259313105860225854463374819505010384847540784973707775642990331230529899458169457771095724664927702362882197685589070238623126901591205753817651891478813406477885847933549107917765644249598642729701554866324156823456158890055953583557566745431Conclusions
You should try and avoid using a password to protect your sensitive key, and where public key encryption is a more secure method … but watch not to lose your RSA private key, too.
