As long as the object is marked as serializable, one way to convert an object to a byte array is to use the BinaryFormatter class in .Net.
You will need to add this using statement to your code file:
using System.Runtime.Serialization.Formatters.Binary;
A binary formatter can output your class to a stream. As you intend to convert your object to a byte array, you can use a System.IO.MemoryStream as temporary storage.
MemoryStream memStream = new MemoryStream();
You can then create a new binary formatter.
BinaryFormatter formatter = new BinarryFomatter();
and use this to serialize your object.
formatter.Serialize(memStream, someObject);
To get the bytes you can use:
return memStream.ToArray();
To deserialize the byte array you need to write the bytes to a memory stream.
memStream.Write(arrBytes, 0, arrBytes.Length);
Return to the beginning of the stream.
memStream.Seek(0, SeekOrigin.Begin);
Then use the formatter to recreate the object.
Object obj = (Object)formatter.Deserialize(memStream);
If you are already using encryption functions you should be able to encrypt the created byte array quite easily before storing it in the database.
Hopefully that will help you in the right direction. If you are lucky, the BouncyCastle objects will be marked as serializable, if not you will need some extra code. Later, I will get a chance to look at the BouncyCastle librarys to be able to test this and will post more code if necessary.
... I have never used BouncyCastle before. After some testing, it appears that the public and private key objects are not serializable, so you will need to convert these objects into something that is!
It appears that the public and private keys expose properties as various BouncyCastle.Math.BigInteger values. (The keys can also be constructed from these BigIntegers). Further, BigIntegers have a ToByteArray() function and can also be constructed from a byte array. Very useful..
Knowing that you can break each key into BigIntegers and these in turn to a byte array and that the reverse is also possible, you a way to store all these in a serializable object. A simple struct or class would do e.g.
[Serializable]
private struct CipherPrivateKey
{
public byte[] modulus;
public byte[] publicExponent;
public byte[] privateExponent;
public byte[] p;
public byte[] q;
public byte[] dP;
public byte[] dQ;
public byte[] qInv;
}
[Serializable]
private struct CipherPublicKey
{
public bool isPrivate;
public byte[] modulus;
public byte[] exponent;
}
This gives us a pair of easy to use serializable objects.
The AsymmetricCipherKeyPair exposes the Public and Private keys as AsymmetricKeyParameter objects. To get at the more detailed properties you will need to cast these to the following:
keyPair.Public to BouncyCastle.Crypto.Parameters.RsaKeyParameters
keyPair.Private to BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters
The following functions will convert these to the structs to declared earlier:
private static CipherPublicKey getCipherPublicKey(Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters cPublic)
{
CipherPublicKey cpub = new CipherPublicKey();
cpub.modulus = cPublic.Modulus.ToByteArray();
cpub.exponent = cPublic.Exponent.ToByteArray();
return cpub;
}
private static CipherPrivateKey getCipherPrivateKey(Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters cPrivate)
{
CipherPrivateKey cpri = new CipherPrivateKey();
cpri.dP = cPrivate.DP.ToByteArray();
cpri.dQ = cPrivate.DQ.ToByteArray();
cpri.modulus = cPrivate.Modulus.ToByteArray();
cpri.p = cPrivate.P.ToByteArray();
cpri.privateExponent = cPrivate.Exponent.ToByteArray();
cpri.publicExponent = cPrivate.PublicExponent.ToByteArray();
cpri.q = cPrivate.Q.ToByteArray();
cpri.qInv = cPrivate.QInv.ToByteArray();
return cpri;
}
Using the binary formatter mentioned earlier, we can convert the serializable objects we have just created to a byte array.
CipherPublicKey cpub = getCipherPublicKey((Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)keypair.Public);
MemoryStream memStream = new MemoryStream();
BinaryFormatter formatter = new BinarryFomatter();
formatter.Serialize(memStream, cpub);
return memStream.ToArray();
Desierializing is then just the inverse as described earlier. Once you have either the public or private structs deserialized you can use the BouncyCastle contructors to recreate the keys. These functions demonstrate this.
private static Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters recreateASymCipherPublicKey(CipherPublicKey cPublicKey)
{
Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters key;
key = new Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters(
cPublicKey.isPrivate,
createBigInteger(cPublicKey.modulus),
createBigInteger(cPublicKey.exponent));
return key;
}
private static Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters recreateASymCipherPrivateKey(CipherPrivateKey cPrivateKey)
{
Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters key;
key = new Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters(
createBigInteger(cPrivateKey.modulus),
createBigInteger(cPrivateKey.publicExponent),
createBigInteger(cPrivateKey.privateExponent),
createBigInteger(cPrivateKey.p),
createBigInteger(cPrivateKey.q),
createBigInteger(cPrivateKey.dP),
createBigInteger(cPrivateKey.dQ),
createBigInteger(cPrivateKey.qInv));
return key;
}
If you need to recreate the original key pair for any reason:
AsymmetricKeyParameter publ = (AsymmetricKeyParameter)recreateASymCipherPublicKey(cKeyPair.publicKey);
AsymmetricKeyParameter priv = (AsymmetricKeyParameter)recreateASymCipherPrivateKey(cKeyPair.privateKey);
AsymmetricCipherKeyPair keyPair = new AsymmetricCipherKeyPair(publ, priv);
Hopefully that all makes sense! The code samples should help you on your way.