方法 : 非対称キーで XML 要素を暗号化する
System.Security.Cryptography.Xml 名前空間のクラスを使用して、XML ドキュメント内の要素を暗号化できます。 XML 暗号化は暗号化された XML データを変換または格納する標準の方法で、データを簡単に読み取られるおそれがありません。 XML 暗号化標準の詳細については、http://www.w3.org/TR/xmldsig-core/ の World Wide Web Consortium (W3C) specification for XML Encryption を参照してください。
XML 暗号化を使用して、任意の XML 要素やドキュメントを、暗号化された XML データを含む <EncryptedData> 要素に置き換えることができます。 <EncryptedData> 要素には、暗号化の間に使用されたキーとプロセスに関する情報などのサブ要素も含まれます。 XML 暗号化では、ドキュメントに複数の暗号化された要素を含めたり、要素を複数回暗号化したりできます。 この手順のコード例では、暗号化の間に後で使用できるその他の複数のサブ要素と共に、<EncryptedData> 要素の作成方法を示します。
この例では、2 つのキーを使用して XML 要素を暗号化します。 RSA 公開キーと秘密キーのペアを生成して、キーのペアを安全なキー コンテナーに保存します。 次に、Rijndael とも呼ばれる AES (Advanced Encryption Standard) アルゴリズムを使用して、個別のセッション キーを作成します。 この例では、AES セッション キーを使用して XML ドキュメントを暗号化し、次に RSA 公開キーを使用して AES セッション キーを暗号化します。 最後に、暗号化された AES セッション キーと暗号化された XML データを、新しい <EncryptedData> 要素内の XML ドキュメントに保存します。
XML 要素を復号化するには、キー コンテナーから RSA 秘密キーを取得し、それを使用してセッション キーを復号化し、次にセッション キーを使用してドキュメントを復号化します。 この手順を使用して暗号化された XML 要素を復号化する方法の詳細については、「方法 : 非対称キーで XML 要素を復号化する」を参照してください。
この例は、複数のアプリケーションが暗号化されたデータを共有する必要がある状況や、1 つのアプリケーションが実行するたびに暗号化されたデータを保存する必要のある状況に適しています。
非対称キーで XML 要素を暗号化するには
CspParameters オブジェクトを作成し、キー コンテナーの名前を指定します。
Dim cspParams As New CspParameters() cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
CspParameters cspParams = new CspParameters(); cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
RSACryptoServiceProvider クラスを使用して共通キーを生成します。 CspParameters オブジェクトを RSACryptoServiceProvider クラスのコンストラクターに渡すと、キーがキー コンテナーに自動的に保存されます。 このキーは、AES セッション キーを暗号化するために使用され、後からそれを復号化するために取得できます。
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
ディスクから XML ファイルをロードして、XmlDocument オブジェクトを作成します。 XmlDocument オブジェクトには、暗号化する XML 要素が含まれます。
' Create an XmlDocument object. Dim xmlDoc As New XmlDocument() ' Load an XML file into the XmlDocument object. Try xmlDoc.PreserveWhitespace = True xmlDoc.Load("test.xml") Catch e As Exception Console.WriteLine(e.Message) End Try
// Create an XmlDocument object. XmlDocument xmlDoc = new XmlDocument(); // Load an XML file into the XmlDocument object. try { xmlDoc.PreserveWhitespace = true; xmlDoc.Load("test.xml"); } catch (Exception e) { Console.WriteLine(e.Message); }
指定された要素を XmlDocument オブジェクト内で検索し、暗号化する要素を表す新しい XmlElement オブジェクトを作成します。 この例では、"creditcard" 要素が暗号化されます。
Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(EncryptionElement)(0) ' ' Throw an XmlException if the element was not found. If elementToEncrypt Is Nothing Then Throw New XmlException("The specified element was not found") End If
XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement; // Throw an XmlException if the element was not found. if (elementToEncrypt == null) { throw new XmlException("The specified element was not found"); }
RijndaelManaged クラスを使用して、新しいセッション キーを生成します。 このキーは XML 要素を暗号化します。その後、このキー自体が暗号化され、XML ドキュメントに配置されます。
' Create a 256 bit Rijndael key. sessionKey = New RijndaelManaged() sessionKey.KeySize = 256
// Create a 256 bit Rijndael key. sessionKey = new RijndaelManaged(); sessionKey.KeySize = 256;
EncryptedXml クラスの新しいインスタンスを作成し、そのインスタンスを使用して、セッション キーを使用する指定された要素を暗号化します。 EncryptData メソッドは、暗号化された要素を暗号化されたバイトの配列として返します。
Dim eXml As New EncryptedXml() Dim encryptedElement As Byte() = eXml.EncryptData(elementToEncrypt, sessionKey, False)
EncryptedXml eXml = new EncryptedXml(); byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
EncryptedData オブジェクトを構築し、暗号化された XML 要素の URL 識別子を設定します。 この URL 識別子により、復号化する側は XML に暗号化要素が含まれていることを知ることができます。 XmlEncElementUrl フィールドを使用して、URL 識別子を指定できます。 プレーンテキスト XML 要素は、この EncryptedData オブジェクトによってカプセル化された <EncryptedData> 要素に置き換えられます。
Dim edElement As New EncryptedData() edElement.Type = EncryptedXml.XmlEncElementUrl edElement.Id = EncryptionElementID
EncryptedData edElement = new EncryptedData(); edElement.Type = EncryptedXml.XmlEncElementUrl; edElement.Id = EncryptionElementID;
セッション キーの生成に使用された暗号アルゴリズムの URL 識別子で初期化した EncryptionMethod オブジェクトを作成します。 EncryptionMethod プロパティに EncryptionMethod オブジェクトを渡します。
edElement.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncAES256Url)
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
暗号化されたセッション キーを含む EncryptedKey オブジェクトを作成します。 セッション キーを暗号化して、それを EncryptedKey オブジェクトに追加し、セッション キーの名前およびキー識別子 URL を入力します。
Dim ek As New EncryptedKey() Dim encryptedKey As Byte() = EncryptedXml.EncryptKey(sessionKey.Key, Alg, False) ek.CipherData = New CipherData(encryptedKey) ek.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncRSA15Url)
EncryptedKey ek = new EncryptedKey(); byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false); ek.CipherData = new CipherData(encryptedKey); ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
暗号化されたデータを特定のセッション キーに割り当てる、新しい DataReference オブジェクトを作成します。 このオプションの手順により、XML ドキュメントの複数の部分が 1 つのキーによって暗号化されたことを簡単に指定できます。
Dim dRef As New DataReference() ' Specify the EncryptedData URI. dRef.Uri = "#" + EncryptionElementID ' Add the DataReference to the EncryptedKey. ek.AddReference(dRef)
DataReference dRef = new DataReference(); // Specify the EncryptedData URI. dRef.Uri = "#" + EncryptionElementID; // Add the DataReference to the EncryptedKey. ek.AddReference(dRef);
EncryptedData オブジェクトに、暗号化されたキーを追加します。
edElement.KeyInfo.AddClause(New KeyInfoEncryptedKey(ek))
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
新しい KeyInfo オブジェクトを作成し、RAS キーの名前を指定します。 これを EncryptedData オブジェクトに追加します。 これにより、復号化する側では、セッション キーを復号化するときに使用する正しい非対称キーを識別できます。
' Create a new KeyInfoName element. Dim kin As New KeyInfoName() ' Specify a name for the key. kin.Value = KeyName ' Add the KeyInfoName element to the ' EncryptedKey object. ek.KeyInfo.AddClause(kin)
// Create a new KeyInfoName element. KeyInfoName kin = new KeyInfoName(); // Specify a name for the key. kin.Value = KeyName; // Add the KeyInfoName element to the // EncryptedKey object. ek.KeyInfo.AddClause(kin);
EncryptedData オブジェクトに、暗号化された要素データを追加します。
edElement.CipherData.CipherValue = encryptedElement
edElement.CipherData.CipherValue = encryptedElement;
元の XmlDocument オブジェクトの要素を EncryptedData 要素に置き換えます。
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
XmlDocument オブジェクトを保存します。
xmlDoc.Save("test.xml")
xmlDoc.Save("test.xml");
使用例
Imports System
Imports System.Xml
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml
Class Program
Shared Sub Main(ByVal args() As String)
' Create an XmlDocument object.
Dim xmlDoc As New XmlDocument()
' Load an XML file into the XmlDocument object.
Try
xmlDoc.PreserveWhitespace = True
xmlDoc.Load("test.xml")
Catch e As Exception
Console.WriteLine(e.Message)
End Try
' Create a new CspParameters object to specify
' a key container.
Dim cspParams As New CspParameters()
cspParams.KeyContainerName = "XML_ENC_RSA_KEY"
' Create a new RSA key and save it in the container. This key will encrypt
' a symmetric key, which will then be encryped in the XML document.
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
Try
' Encrypt the "creditcard" element.
Encrypt(xmlDoc, "creditcard", "EncryptedElement1", rsaKey, "rsaKey")
' Save the XML document.
xmlDoc.Save("test.xml")
' Display the encrypted XML to the console.
Console.WriteLine("Encrypted XML:")
Console.WriteLine()
Console.WriteLine(xmlDoc.OuterXml)
Decrypt(xmlDoc, rsaKey, "rsaKey")
xmlDoc.Save("test.xml")
' Display the encrypted XML to the console.
Console.WriteLine()
Console.WriteLine("Decrypted XML:")
Console.WriteLine()
Console.WriteLine(xmlDoc.OuterXml)
Catch e As Exception
Console.WriteLine(e.Message)
Finally
' Clear the RSA key.
rsaKey.Clear()
End Try
Console.ReadLine()
End Sub 'Main
Public Shared Sub Encrypt(ByVal Doc As XmlDocument, ByVal EncryptionElement As String, ByVal EncryptionElementID As String, ByVal Alg As RSA, ByVal KeyName As String)
' Check the arguments.
If Doc Is Nothing Then
Throw New ArgumentNullException("Doc")
End If
If EncryptionElement Is Nothing Then
Throw New ArgumentNullException("EncryptionElement")
End If
If EncryptionElementID Is Nothing Then
Throw New ArgumentNullException("EncryptionElementID")
End If
If Alg Is Nothing Then
Throw New ArgumentNullException("Alg")
End If
If KeyName Is Nothing Then
Throw New ArgumentNullException("KeyName")
End If
'//////////////////////////////////////////////
' Find the specified element in the XmlDocument
' object and create a new XmlElemnt object.
'//////////////////////////////////////////////
Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(EncryptionElement)(0) '
' Throw an XmlException if the element was not found.
If elementToEncrypt Is Nothing Then
Throw New XmlException("The specified element was not found")
End If
Dim sessionKey As RijndaelManaged = Nothing
Try
'////////////////////////////////////////////////
' Create a new instance of the EncryptedXml class
' and use it to encrypt the XmlElement with the
' a new random symmetric key.
'////////////////////////////////////////////////
' Create a 256 bit Rijndael key.
sessionKey = New RijndaelManaged()
sessionKey.KeySize = 256
Dim eXml As New EncryptedXml()
Dim encryptedElement As Byte() = eXml.EncryptData(elementToEncrypt, sessionKey, False)
'//////////////////////////////////////////////
' Construct an EncryptedData object and populate
' it with the desired encryption information.
'//////////////////////////////////////////////
Dim edElement As New EncryptedData()
edElement.Type = EncryptedXml.XmlEncElementUrl
edElement.Id = EncryptionElementID
' Create an EncryptionMethod element so that the
' receiver knows which algorithm to use for decryption.
edElement.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncAES256Url)
' Encrypt the session key and add it to an EncryptedKey element.
Dim ek As New EncryptedKey()
Dim encryptedKey As Byte() = EncryptedXml.EncryptKey(sessionKey.Key, Alg, False)
ek.CipherData = New CipherData(encryptedKey)
ek.EncryptionMethod = New EncryptionMethod(EncryptedXml.XmlEncRSA15Url)
' Create a new DataReference element
' for the KeyInfo element. This optional
' element specifies which EncryptedData
' uses this key. An XML document can have
' multiple EncryptedData elements that use
' different keys.
Dim dRef As New DataReference()
' Specify the EncryptedData URI.
dRef.Uri = "#" + EncryptionElementID
' Add the DataReference to the EncryptedKey.
ek.AddReference(dRef)
' Add the encrypted key to the
' EncryptedData object.
edElement.KeyInfo.AddClause(New KeyInfoEncryptedKey(ek))
' Set the KeyInfo element to specify the
' name of the RSA key.
' Create a new KeyInfoName element.
Dim kin As New KeyInfoName()
' Specify a name for the key.
kin.Value = KeyName
' Add the KeyInfoName element to the
' EncryptedKey object.
ek.KeyInfo.AddClause(kin)
' Add the encrypted element data to the
' EncryptedData object.
edElement.CipherData.CipherValue = encryptedElement
'//////////////////////////////////////////////////
' Replace the element from the original XmlDocument
' object with the EncryptedData element.
'//////////////////////////////////////////////////
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)
Catch e As Exception
' re-throw the exception.
Throw e
Finally
If Not (sessionKey Is Nothing) Then
sessionKey.Clear()
End If
End Try
End Sub 'Encrypt
Public Shared Sub Decrypt(ByVal Doc As XmlDocument, ByVal Alg As RSA, ByVal KeyName As String)
' Check the arguments.
If Doc Is Nothing Then
Throw New ArgumentNullException("Doc")
End If
If Alg Is Nothing Then
Throw New ArgumentNullException("Alg")
End If
If KeyName Is Nothing Then
Throw New ArgumentNullException("KeyName")
End If
' Create a new EncryptedXml object.
Dim exml As 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()
End Sub 'Decrypt
End Class 'Program
using System;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
class Program
{
static void Main(string[] args)
{
// Create an XmlDocument object.
XmlDocument xmlDoc = new XmlDocument();
// Load an XML file into the XmlDocument object.
try
{
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load("test.xml");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
// Create a new CspParameters object to specify
// a key container.
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
// Create a new RSA key and save it in the container. This key will encrypt
// a symmetric key, which will then be encryped in the XML document.
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
try
{
// Encrypt the "creditcard" element.
Encrypt(xmlDoc, "creditcard", "EncryptedElement1", rsaKey, "rsaKey");
// Save the XML document.
xmlDoc.Save("test.xml");
// Display the encrypted XML to the console.
Console.WriteLine("Encrypted XML:");
Console.WriteLine();
Console.WriteLine(xmlDoc.OuterXml);
Decrypt(xmlDoc, rsaKey, "rsaKey");
xmlDoc.Save("test.xml");
// Display the encrypted XML to the console.
Console.WriteLine();
Console.WriteLine("Decrypted XML:");
Console.WriteLine();
Console.WriteLine(xmlDoc.OuterXml);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
// Clear the RSA key.
rsaKey.Clear();
}
Console.ReadLine();
}
public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string KeyName)
{
// 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 XmlElemnt object.
////////////////////////////////////////////////
XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
// Throw an XmlException if the element was not found.
if (elementToEncrypt == null)
{
throw new XmlException("The specified element was not found");
}
RijndaelManaged sessionKey = null;
try
{
//////////////////////////////////////////////////
// Create a new instance of the EncryptedXml class
// and use it to encrypt the XmlElement with the
// a new random symmetric key.
//////////////////////////////////////////////////
// Create a 256 bit Rijndael 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;
// Create an EncryptionMethod element so that the
// receiver knows which algorithm to use for decryption.
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);
// Create a new DataReference element
// for the KeyInfo element. This optional
// element specifies which EncryptedData
// uses this key. An XML document can have
// multiple EncryptedData elements that use
// different keys.
DataReference dRef = new DataReference();
// Specify the EncryptedData URI.
dRef.Uri = "#" + EncryptionElementID;
// Add the DataReference to the EncryptedKey.
ek.AddReference(dRef);
// Add the encrypted key to the
// EncryptedData object.
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
// Set the KeyInfo element to specify the
// name of the RSA key.
// Create a new KeyInfoName element.
KeyInfoName kin = new KeyInfoName();
// Specify a name for the key.
kin.Value = KeyName;
// Add the KeyInfoName element to the
// EncryptedKey object.
ek.KeyInfo.AddClause(kin);
// Add the encrypted element data to the
// EncryptedData object.
edElement.CipherData.CipherValue = encryptedElement;
////////////////////////////////////////////////////
// Replace the element from the original XmlDocument
// object with the EncryptedData element.
////////////////////////////////////////////////////
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
}
catch (Exception e)
{
// re-throw the exception.
throw e;
}
finally
{
if (sessionKey != null)
{
sessionKey.Clear();
}
}
}
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();
}
}
この例では、"test.xml" という名前のファイルが、コンパイル済みプログラムと同じディレクトリに存在していることを前提としています。 また、"test.xml" に "creditcard" 要素が含まれていることも前提としています。 test.xml という名前のファイルに次の XML を配置し、その XML をこの例と共に使用できます。
<root>
<creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry>
</creditcard>
</root>
コードのコンパイル
この例をコンパイルするには、System.Security.dll への参照を含める必要があります。
System.Xml、System.Security.Cryptography、および System.Security.Cryptography.Xml 名前空間を含めます。
セキュリティ
共通暗号化キーをプレーンテキストに格納したり、マシン間で共通キーをプレーンテキストとして転送したりしないでください。 また、非対称キーのペアの秘密キーをプレーンテキストで格納または転送しないでください。 対称および非対称暗号キーの詳細については、「暗号化と復号化のためのキーの生成」を参照してください。
キーをソース コードに直接埋め込まないでください。 埋め込まれたキーは、Ildasm.exe (MSIL 逆アセンブラー) を使用したり、メモ帳などのテキスト エディターでアセンブリを開くことによって、アセンブリから簡単に読み込むことができます。
暗号化キーの使用が終了したら、各バイトをゼロに設定するか、暗号マネージ クラスの Clear メソッドを呼び出して、メモリからこのキーを消去してください。 暗号化キーはデバッガーによってメモリから読み込むことができ、メモリの場所がディスクにページングされる場合はハード ディスクから読み込むこともできます。
参照
処理手順
参照
System.Security.Cryptography.Xml