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 } }