我需要加密/解密整个XML文件。我在this MSDN post中使用RSA,但问题是我必须在一个程序中加密,一个Windows窗体程序并在Windows服务中解密。 Windows服务如何知道我为解密而生成的RSA密钥?
加密/解密代码是:
public class EncryptDecrpt
{
public static void Encrypt(XmlDocument doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg,
string KeyName)
{
try
{
//Check the arguments
if (doc == null)
throw new ArgumentNullException("doc");
if (ElementToEncrypt == null)
throw new ArgumentNullException("ElementToEncrypt");
if (EncryptionElementID == null)
throw new ArgumentNullException("EncryptionElementID");
if (Alg == null)
throw new ArgumentNullException("Alg");
if (KeyName == null)
throw new ArgumentNullException("KeyName");
// Find the specified element in the XmlDocument object
// and create a new XmlElement object
XmlElement elementToEncrypt = doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
if (elementToEncrypt == null)
throw new XmlException("The specified element was not found");
RijndaelManaged sessionKey = null;
// Create a 256 bit Rijandel key
sessionKey = new RijndaelManaged();
sessionKey.KeySize = 256;
EncryptedXml eXml = new EncryptedXml();
byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
// Construct an EncryptedData object and populate
// it with the desired encryption information
EncryptedData edElement = new EncryptedData();
edElement.Type = EncryptedXml.XmlEncElementUrl;
edElement.Id = EncryptionElementID;
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
// Encrypt the session key and add it to an EncryptedKey element
EncryptedKey ek = new EncryptedKey();
byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
DataReference dRef = new DataReference();
// Specify the EncryptedData URI
dRef.Uri = "#" + EncryptionElementID;
ek.AddReference(dRef);
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
KeyInfoName kin = new KeyInfoName();
kin.Value = KeyName;
ek.KeyInfo.AddClause(kin);
edElement.CipherData.CipherValue = encryptedElement;
// Replace the element from the original XmlDocument
// object with the EncrytedData element
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
}
catch (Exception e)
{
// rethrow the exception
throw e;
}
}
public static void Decrypt(XmlDocument Doc, RSA Alg, string KeyName)
{
// Check the arguments.
if (Doc == null)
throw new ArgumentNullException("Doc");
if (Alg == null)
throw new ArgumentNullException("Alg");
if (KeyName == null)
throw new ArgumentNullException("KeyName");
// Create a new EncryptedXml object.
EncryptedXml exml = new EncryptedXml(Doc);
// Add a key-name mapping.
// This method can only decrypt documents
// that present the specified key name.
exml.AddKeyNameMapping(KeyName, Alg);
// Decrypt the element.
exml.DecryptDocument();
}
}
Windows窗体程序中的代码是:
private void SaveForm()
{
try
{
string fileName = System.IO.Path.Combine(Application.StartupPath, "alphaService.xml");
XDocument doc = new XDocument();
XElement xml = new XElement("Info",
new XElement("DatabaseServerName", txtServerName.Text),
new XElement("DatabaseUserName", txtDatabaseUserName.Text),
new XElement("DatabasePassword", txtDatabasePassword.Text),
new XElement("ServiceAccount", txtAccount.Text),
new XElement("ServicePassword", txtServicePassword.Text),
new XElement("RegistrationCode", txtRegistrationCode.Text));
doc.Add(xml);
doc.Save(fileName);
// Encrypt
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(fileName);
// Create a new CspParameters object to specify
// a key container
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
EncryptDecrpt.Encrypt(xmlDoc, "info", "EncryptedElement1", rsaKey, "rsaKey");
xmlDoc.Save(fileName);
MessageBox.Show(xmlDoc.OuterXml);
EncryptDecrpt.Decrypt(xmlDoc, rsaKey, "rsaKey");
Windows服务如何知道RSA密钥或如何执行此操作?
答案 0 :(得分:2)
您需要在两个应用程序之间共享公钥。每次只做new RSACryptoServiceProvider()
会生成新密钥。我在项目的app.config中分享了我的密钥:
<applicationSettings>
<YpurApp.Properties.Settings>
<setting name="PublicKeyXml" serializeAs="String">
<value><RSAKeyValue><Modulus>YOURMODULUS</Modulus><Exponent>YOUREXP</Exponent></RSAKeyValue></value>
</setting>
一旦读入程序,XML实际上就像这样:
<RSAKeyValue><Modulus>YOURMODULUS</Modulus><Exponent>YOUREXP</Exponent></RSAKeyValue>
然后你可以使用这样的代码在公共应用程序中加密:
private static byte[] Encrypt(byte[] bytes)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(Properties.Settings.Default.PublicKeyXml);
return rsa.Encrypt(bytes, true);
}
}
私有应用程序还应具有匹配的PrivateKey,无论是硬编码还是app.config。您不希望与任何可能使用它来破坏加密的“公共”共享私钥。使用私钥解密数据,如下所示:
private static byte[] Decrypt(byte[] bytes)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(Properties.Settings.Default.PrivateKeyXml);
return rsa.Decrypt(bytes, true);
}
}
要生成密钥,请执行以下操作:
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
string keyXML = rsaKey.ToXmlString(true);
这将包含公钥和私钥。公钥是<RSAKeyValue><Modulus></Modulus><Exponent></Exponent>
部分。私钥就是整个事物,包括<P></P><Q></Q><DP></DP><DQ></DQ><InverseQ></InverseQ><D></D>
。将该字符串复制/粘贴到您的app.config中,然后将其拆分为两个选项PublicKey
和PrivateKey
,如上所述。请勿在加密应用程序的app.config中包含私钥。
答案 1 :(得分:2)
PKI和密钥管理本身就是书籍。但它归结为:您在执行解密的服务器上创建密钥对。解密需要私钥,并且您不想移动私钥(除了备份目的)。你应该只做一次,比如5年。
然后将公钥 securily 分发给客户端。您可以通过在代码中加入密钥来完成此操作 - 只要您可以信任公钥即可。然后使用公钥来执行加密。同样,对于每个密钥对,通常执行一次分发。