XMLエレメントを暗号化・復号化する

XMLファイルに書かれたパスワードの暗号化というお題をいただきまして、あれやこれや検索してみた中で MSDNに「XML 暗号化と XML デジタル署名」というのがありました。

ここでは、DESの後継とされるRijndael(ラインダール)アルゴリズムを使用したXMLの暗号化・復号化を行います。

以下のソースは、ほぼMSDNのものです。
(System.Securityの参照設定が必要です。)

MSDNで紹介されているソースは、RijndaelManagedを生成した時に、共通Key、IVが自動的に生成され、 そのまま使用しています。以下のソースでは、共通Key、IVを指定するように変更してあります。

共通Keyは、決まったサイズが必要となり指定できるサイズは、LegalKeySizesプロパティで確認できます。
(128bit,192bit,256bit)

IVも同様に、決まったサイズが必要となり指定できるサイズは、BlockSize プロパティで確認できます。
(8bit)

Imports System
Imports System.Xml
Imports System.Text
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml

Module basXmlCrypt

    Sub Main()
        Dim key As RijndaelManaged = Nothing

        Try
            ' Rijndaelオブジェクトの生成(この時、KeyとIVも生成される。)
            key = New RijndaelManaged()

            ' 共通Key及びIVの指定
            key.Key = Encoding.Unicode.GetBytes("0123456789012345")
            key.IV = Encoding.Unicode.GetBytes("01234567")

            Dim xmlDoc As New XmlDocument()
            xmlDoc.PreserveWhitespace = True

            ' XMLを読み込みます。
            xmlDoc.Load("test.xml")

            ' 指定したエレメントを暗号化します。
            Encrypt(xmlDoc, "Password", key)

            Console.WriteLine("The element was encrypted")

            Console.WriteLine(xmlDoc.InnerXml)

            Decrypt(xmlDoc, key)

            Console.WriteLine("The element was decrypted")

            Console.WriteLine(xmlDoc.InnerXml)


        Catch e As Exception
            Console.WriteLine(e.Message)
        Finally
            ' Clear the key.
            If Not (key Is Nothing) Then
                key.Clear()
            End If
        End Try

    End Sub


    Sub Encrypt(ByVal Doc As XmlDocument, ByVal ElementName As String, ByVal Key As SymmetricAlgorithm)
        ' 引数確認
        If Doc Is Nothing Then
            Throw New ArgumentNullException("Doc")
        End If
        If ElementName Is Nothing Then
            Throw New ArgumentNullException("ElementToEncrypt")
        End If
        If Key Is Nothing Then
            Throw New ArgumentNullException("Alg")
        End If

        ' 指定されたエレメントの取得
        Dim elementToEncrypt As XmlElement = Doc.GetElementsByTagName(ElementName)(0)

        ' エレメントが存在しなかった時の例外
        If elementToEncrypt Is Nothing Then
            Throw New XmlException("The specified element was not found")
        End If

        ' XML暗号化インスタンスの生成
        Dim eXml As New EncryptedXml()

        ' 暗号化を行います。
        Dim encryptedElement As Byte() = eXml.EncryptData(elementToEncrypt, Key, False)

        ' XMLの暗号化要素を作成します。
        Dim edElement As New EncryptedData()
        edElement.Type = EncryptedXml.XmlEncElementUrl

        Dim encryptionMethod As String = Nothing

        If TypeOf Key Is TripleDES Then
            encryptionMethod = EncryptedXml.XmlEncTripleDESUrl
        ElseIf TypeOf Key Is DES Then
            encryptionMethod = EncryptedXml.XmlEncDESUrl
        End If
        If TypeOf Key Is Rijndael Then
            Select Case Key.KeySize
                Case 128
                    encryptionMethod = EncryptedXml.XmlEncAES128Url
                Case 192
                    encryptionMethod = EncryptedXml.XmlEncAES192Url
                Case 256
                    encryptionMethod = EncryptedXml.XmlEncAES256Url
            End Select
        Else
            Throw New CryptographicException("The specified algorithm is not supported for XML Encryption.")
        End If

        edElement.EncryptionMethod = New EncryptionMethod(encryptionMethod)
        ' 暗号化されたデータを追加します。
        edElement.CipherData.CipherValue = encryptedElement
        ' エレメントを暗号化されたエレメントへ置き換えます。
        EncryptedXml.ReplaceElement(elementToEncrypt, edElement, False)

    End Sub

    Sub Decrypt(ByVal Doc As XmlDocument, ByVal Alg As SymmetricAlgorithm)
        ' 引数確認
        If Doc Is Nothing Then
            Throw New ArgumentNullException("Doc")
        End If
        If Alg Is Nothing Then
            Throw New ArgumentNullException("Alg")
        End If
        ' 暗号化されたエレメントを取得します。
        Dim encryptedElement As XmlElement = Doc.GetElementsByTagName("EncryptedData")(0)

        ' エレメントが存在しなかった時の例外
        If encryptedElement Is Nothing Then
            Throw New XmlException("The EncryptedData element was not found.")
        End If

        Dim edElement As New EncryptedData()
        edElement.LoadXml(encryptedElement)

        Dim exml As New EncryptedXml()

        ' 復号化を行います。
        Dim rgbOutput As Byte() = exml.DecryptData(edElement, Alg)
        ' 復号化されたエレメントへ置き換えます。
        exml.ReplaceData(encryptedElement, rgbOutput)
    End Sub

End Module