using System;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
namespace Neo.Afx.Security
{
///
/// A utility class for working with asymmetric encryption and decryption.
///
public static class RsaProvider
{
#region GetKeyAlgorithm
///
/// Gets the RSA KeyAlgorithm for the given RSA key blob.
///
/// A byte array that represents an RSA key blob.
/// The RSA KeyAlgorithm for the given RSA key blob.
public static RSACryptoServiceProvider GetKeyAlgorithm(byte[] keyBlob)
{
var rsa = new RSACryptoServiceProvider();
rsa.ImportCspBlob(keyBlob);
return rsa;
}
///
/// Gets the RSA KeyAlgorithm for the given RSA key xml.
///
/// An xml string that represents an RSA key.
/// The RSA KeyAlgorithm for the given RSA key xml.
public static RSACryptoServiceProvider GetKeyAlgorithm(string keyXml)
{
var rsa = new RSACryptoServiceProvider();
var xml = XElement.Parse(keyXml);
var parameters = new RSAParameters();
string value;
if((value = GetValue(xml, "Modulus")) != null)
{
parameters.Modulus = Convert.FromBase64String(value);
}
if((value = GetValue(xml, "Exponent")) != null)
{
parameters.Exponent = Convert.FromBase64String(value);
}
if((value = GetValue(xml, "P")) != null)
{
parameters.P = Convert.FromBase64String(value);
}
if((value = GetValue(xml, "Q")) != null)
{
parameters.Q = Convert.FromBase64String(value);
}
if((value = GetValue(xml, "DP")) != null)
{
parameters.DP = Convert.FromBase64String(value);
}
if((value = GetValue(xml, "DQ")) != null)
{
parameters.DQ = Convert.FromBase64String(value);
}
if((value = GetValue(xml, "InverseQ")) != null)
{
parameters.InverseQ = Convert.FromBase64String(value);
}
if((value = GetValue(xml, "D")) != null)
{
parameters.D = Convert.FromBase64String(value);
}
rsa.ImportParameters(parameters);
return rsa;
}
static string GetValue(XElement parent, string name)
{
var element = parent.Element(name);
return element == null ? null : element.Value;
}
#endregion
#region CreateKeys
///
/// Creates a public and private key pair for the RSA algorithm.
///
/// When the method returns, this contains the public key blob.
/// When the method returns, this contains the private key blob.
/// The as xml.
public static string CreateKeys(out byte[] publicKey, out byte[] privateKey)
{
var rsa = new RSACryptoServiceProvider();
publicKey = rsa.ExportCspBlob(false);
privateKey = rsa.ExportCspBlob(true);
return ExportParameters(rsa, true);
}
///
/// Creates a public and private key pair for the RSA algorithm.
///
/// When the method returns, this contains the base64-encoded public key blob.
/// When the method returns, this contains the base64-encoded private key blob.
/// The as xml.
public static string CreateKeys(out string publicKey, out string privateKey)
{
byte[] publicBuffer;
byte[] privateBuffer;
var xml = CreateKeys(out publicBuffer, out privateBuffer);
publicKey = Convert.ToBase64String(publicBuffer);
privateKey = Convert.ToBase64String(privateBuffer);
return xml;
}
#endregion
#region ExportParameters
///
/// Exports the parameters.
///
/// The RSA cryptographic provider.
/// to include private parameters; otherwise, .
/// The as xml.
public static string ExportParameters(RSACryptoServiceProvider rsa, bool includePrivateParameters)
{
var parameters = rsa.ExportParameters(includePrivateParameters);
var xml = new StringBuilder();
xml.AppendLine("");
xml.AppendLine("");
xml.AppendFormat(" {0}{1}", Convert.ToBase64String(parameters.Modulus), Environment.NewLine);
xml.AppendFormat(" {0}{1}", Convert.ToBase64String(parameters.Exponent), Environment.NewLine);
if(includePrivateParameters)
{
xml.AppendFormat(" {0}
{1}", Convert.ToBase64String(parameters.P), Environment.NewLine);
xml.AppendFormat(" {0}
{1}", Convert.ToBase64String(parameters.Q), Environment.NewLine);
xml.AppendFormat(" {0}{1}", Convert.ToBase64String(parameters.DP), Environment.NewLine);
xml.AppendFormat(" {0}{1}", Convert.ToBase64String(parameters.DQ), Environment.NewLine);
xml.AppendFormat(" {0}{1}", Convert.ToBase64String(parameters.InverseQ), Environment.NewLine);
xml.AppendFormat(" {0}{1}", Convert.ToBase64String(parameters.D), Environment.NewLine);
}
xml.AppendLine("");
return xml.ToString();
}
#endregion
#region Encrypt
///
/// Encrypts the data with the public key.
///
/// The public key to be used.
/// The data to be encrypted.
/// The encrypted data.
public static byte[] Encrypt(byte[] publicKey, byte[] data)
{
var rsa = GetKeyAlgorithm(publicKey);
//OAEP padding is only available on Microsoft Windows XP or later.
var encryptedData = rsa.Encrypt(data, true);
rsa.Clear();
return encryptedData;
}
///
/// Encrypts the plain text with the public key.
///
/// The public key to be used.
/// The plain text to be encrypted.
/// Returns the cipher of the plain text.
public static string Encrypt(string publicKey, string plainText)
{
var key = Convert.FromBase64String(publicKey);
var data = Encoding.UTF8.GetBytes(plainText);
var encryptedData = Encrypt(key, data);
return Convert.ToBase64String(encryptedData);
}
///
/// Encrypts the data with the public key.
///
/// The public key xml to be used.
/// The plain text to be encrypted.
/// The encrypted data.
public static string EncryptXml(string publicKeyXml, string plainText)
{
var rsa = GetKeyAlgorithm(publicKeyXml);
var data = Encoding.UTF8.GetBytes(plainText);
//OAEP padding is only available on Microsoft Windows XP or later.
var encryptedData = rsa.Encrypt(data, false);
rsa.Clear();
return Convert.ToBase64String(encryptedData);
}
#endregion
#region Decrypt
///
/// Decrypts the given encrypted data.
///
/// The private key to be used.
/// The data to be decrypted.
/// The decrypted data.
public static byte[] Decrypt(byte[] privateKey, byte[] encryptedData)
{
var rsa = GetKeyAlgorithm(privateKey);
//OAEP padding is only available on Microsoft Windows XP or later.
var decryptedData = rsa.Decrypt(encryptedData, true);
rsa.Clear();
return decryptedData;
}
///
/// Decrypts the cipher.
///
/// The private key to be used.
/// The cipher to be decrypted.
/// The plain text of the cipher.
public static string Decrypt(string privateKey, string cipher)
{
var key = Convert.FromBase64String(privateKey);
var encryptedData = Convert.FromBase64String(cipher);
var decryptedData = Decrypt(key, encryptedData);
return decryptedData == null ? null : Encoding.UTF8.GetString(decryptedData);
}
///
/// Decrypts the cipher.
///
/// The private key xml to be used.
/// The cipher to be decrypted.
/// The plain text of the cipher.
public static string DecryptXml(string privateKeyXml, string cipher)
{
var rsa = GetKeyAlgorithm(privateKeyXml);
var encryptedData = Convert.FromBase64String(cipher);
//OAEP padding is only available on Microsoft Windows XP or later.
var decryptedData = rsa.Decrypt(encryptedData, false);
rsa.Clear();
return decryptedData == null ? null : Encoding.UTF8.GetString(decryptedData);
}
#endregion
}
}