.Net使用AES和128位初始化向量加密XML流

时间:2016-06-16 16:57:14

标签: .net vb.net encryption aes rsa

我正在开发一个项目,我通过XML流发布到Web服务。在这种情况下,提供者请求使用128位初始化向量在密码块链接(CBC)模式下使用高级加密标准(AES)加密路由xml。我在VB.Net编码,从我可以告诉我已经满足他们的所有加密要求,但我提交帖子时,我一直收到“无效的路由输入加密”错误响应。我没有做过多加密,所以我希望有一些加密经验的人可以帮助我。它是否失败,因为我没有正确地为IV添加前缀? AES中是否有标准方法将IV合并到密码数据?或者我是如何进行加密的?我已经被困在这里一段时间,尝试了几种不同的加密方式,但没有取得成功。下面列出的是我的代码和加密要求摘要。

  1. 使用高级加密标准(AES)在密码块链接(CBC)模式下使用128位初始化向量[AES]算法生成对称密钥。不要使用零字节初始化向量。

  2. 使用AES对称密钥加密有效的路由输入xml文档。使用128位初始化向量对生成的密文进行前缀。 (建议不要使用全0字节的初始化向量。)

  3. Base64编码初始化向量和加密的路由输入xml文档。

  4. 使用base64编码的初始化向量和加密的Routing Input xml文档构建ENCRYPTED_RI xml元素。

  5. 为明文路由输入xml文档生成SHA1哈希。

  6. 连接明文路由输入xml文档和AES对称密钥的SHA1哈希值。 (SHA1哈希+ AES对称密钥)

  7. 使用公钥和RSA 1.5版算法[RFC 2437]加密连接结果。

  8. Base64对加密的连接结果进行编码。

  9. 使用base64编码的加密连接结果构建ENCRYPTED_KEY xml元素。

  10. 这是我的代码:

    Sub CreateEncryptionXML()
        '############
        '## CREATE AES KEY AND IV
        '############
        Dim SymKey() As Byte
        Dim IV() As Byte
        Dim aes As New AesCryptoServiceProvider
    
        Using myAes As Aes = System.Security.Cryptography.Aes.Create()
            myAes.KeySize = 128
            myAes.BlockSize = 128
            myAes.Mode = CipherMode.CBC
            myAes.Key = Encoding.UTF8.GetBytes("MyEncryptionKey1")
            myAes.IV = Encoding.UTF8.GetBytes("MyInitialVector1")
    
            SymKey = myAes.Key
            IV = myAes.IV
        End Using
    
        '############
        '## ENCRYPT ROUTING INPUT XML DOC
        '############
        Dim riXml As New XmlDocument
        riXml.Load("C:\routingdoc.xml")        
        aes.Key = SymKey
        aes.IV = IV
        aes.Mode = CipherMode.CBC
    
        ' Convert the plaintext string to a byte array.
        Dim plaintextBytes() As Byte = System.Text.Encoding.UTF8.GetBytes(riXml.OuterXml.ToString())
    
        ' Create the stream.
        Dim ms As New System.IO.MemoryStream
    
        ' Create the encoder to write to the stream.
        Dim encStream As New CryptoStream(ms, aes.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write)
    
        ' Use the crypto stream to write the byte array to the stream.
        encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
        encStream.FlushFinalBlock()
    
    
        '############
        '## PREFIX CIPHER TEXT WITH IV
        '############
        Dim encRiXml() As Byte = ms.ToArray
        Dim arraySize As Integer = IV.Length + encRiXml.Length
        Dim Merged(arraySize) As Byte
        IV.CopyTo(Merged, 0)
        encRiXml.CopyTo(Merged, IV.Length)
    
        Dim Base64IVEncRiXML As String = Convert.ToBase64String(Merged)
    
        '******** I BELIVE EVERYTHING PAST HERE IS CORRECT BUT INCLUDED IT TO SHOW WHOLE PROCESS **********
    
        '############
        '## CREATE SHA1 HASH FOR PLAINTEXT ROUTING INPUT
        '############
        Dim hash() As Byte = New SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(riXml.OuterXml.ToString()))
    
        '############
        '## CONCATENATE THE SHA1 HASH OF PLAINTEXT ROUTING INPUT XML WITH AES KEY
        '############
        Dim arraySize2 As Integer = hash.Length + SymKey.Length
        Dim Merged2(arraySize2) As Byte
        hash.CopyTo(Merged2, 0)
        SymKey.CopyTo(Merged2, hash.Length)
    
        '############
        '## ENCRYPT CONCATENATED RESULT USING RSA
        '############
        Dim EncryptionKey As String = File.ReadAllText("C:\cert-1.txt").Replace("-----BEGIN CERTIFICATE-----" & vbCr & vbLf, "").Replace("-----END CERTIFICATE-----", "")
    
        TextBox1.Text = EncryptionKey
    
        Dim binaryCertData() As Byte = Convert.FromBase64String(EncryptionKey)
        Dim cert As X509Certificate2 = New X509Certificate2(binaryCertData)
        Dim xmlKey As String = cert.PublicKey.Key.ToXmlString(False)
        Dim objRSA As RSACryptoServiceProvider = New RSACryptoServiceProvider()
        objRSA.FromXmlString(xmlKey)
    
        Dim encrypted() As Byte = objRSA.Encrypt(Merged2, False)
    
        Dim RSAEncryptedSHA1HashAESKey As String = Convert.ToBase64String(encrypted)
    
        postStaticTest(RSAEncryptedSHA1HashAESKey, Base64IVEncRiXML)
    End Sub
    
    'PROVIDED SAMPLE OF XML OUTPUT FROM DOCUMENTATION
    '<?xml version="1.0" encoding="UTF-8"?>
    '<SECURE_REQUEST_GROUP>
    '<ENCRYPTED_KEY Algorithm=”http://www.w3.org/2001/04/xmlenc#rsa-1_5” >
    'bXcCaS97p8TtGzlgZ9ogRcEAaw1D1OQCpk1AQFfWYE5J2CheNtRBpuME+uB3wSkwjIWftkYxQ5JRTQ3Qhz7LrCM+TOORl2lFFTpVC9zGUP1xndfT6EQONViV0XGJieWCzXNyjO3XpEl7IdntkVKucrDN9gA7wlimUdw4Ya5sn08=
    '</ ENCRYPTED_KEY>
    '< ENCRYPTED_RI Algorithm=”http://www.w3.org/2001/04/xmlenc#aes128-cbc”>
    '9BWPkFDt0Ua/2gN9+BDT9XbYHBuadEREIV1EUmvon/jSr0HkndD/9lBo95H3UYD12TL3wmXVSqi7Ak/QqxzmVRDMgw2Wy0Ezdc3eaA9tOE1c49ZcaZpGM23R1BOazTGdky5v2+oBvSj4a+Ry/aJynvzKvxpTYd15IKOOzPsF/n89Oj6XdjA1TTdn2FCEwo6IkPi0D5QK2i1i/pilEyrrSYQ0oWkYc6ON/OQyL/oHlkBXk0zzQd1HBPOde4/3C6ceajUTvqiIlP6dRBHe6DZ3Ps34g7326jg3koh59RYao/0StgpF3wTJaZ/W36nqlpT3aeoLa/5oKh4A7DjHbYCHTw1uYkPXVGLFl6zTpFRw8hGkPfBRZmS5lXnQl6xidqftb+fx61yBj80/FHAlvmUzBsSQZggeXzBjqlVoWudCuGdC5QH1xKBWrm8haS2UIEdK/DH8fC13oFMpS++C7HTc/u9N8iH6qF0GimxYHvhKwdk3iw/hxrw5Bv1/tQjI1snJm9U1HnokDwG5BWZJp8jBuPgJIapc/DQgIEbM+3NMJXoB/ed9PquPFPPlfoo4E13a3PZPYIDImnLkOjvdPMrZ8A==
    '</ ENCRYPTED_RI>
    '</SECURE_REQUEST_GROUP>
    

1 个答案:

答案 0 :(得分:0)

还有一些开放的实施问题(我想我已经通过我使用的值清楚地说明了哪些问题)。这绝对应该重构,我这样做是为了说明每个要求是如何得到满足的。

Imports System.Security.Cryptography
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography.X509Certificates

Public Class SoAnswer
    Dim keySize As Integer = 128
    Public Function EncryptData() As XDocument
        Dim encoder As UTF8Encoding = New UTF8Encoding()
        'Specifed Root Name in Declaration
        Dim outputDocument As XDocument = New XDocument(New XElement("SECURE_REQUEST_GROUP"))
        outputDocument.Declaration = New XDeclaration("1.0", "utf-8", "true")
        'outputDocument.Root.Name = "Whatever they specify the root of the xml should be"
        Dim riXml As XDocument
        Dim file As FileStream = New FileStream("C:\routingdoc.xml", FileMode.Open, FileAccess.Read)
        riXml = XDocument.Load(file)

        Dim symKey As Byte() = Requirement1(keySize)
        Dim encryptedXml As Byte() = Requirement2(encoder.GetBytes(riXml.ToString()), symKey)
        Dim encodedXml = Requirement3(encryptedXml)
        'Moved Requirement 4 below requirement 9 so it will appear below the key in the output XML
        'Requirement4(encodedXml, outputDocument)
        Dim hash As Byte() = Requirement5(riXml)
        Dim hashKey = Requirement6(hash, symKey)
        Dim encryptedHashKey = Requirement7(hashKey)
        Dim encodedHashKey = Requirement8(encryptedHashKey)
        Requirement9(encodedHashKey, outputDocument)
        Requirement4(encodedXml, outputDocument)
        'Now you should have an XDocument with the proper content to POST to the web service

        'Decrypt check
        Dim check As String = encoder.GetString(Decrypt(Convert.FromBase64String(encodedXml), symKey))

       postStaticTestXML(outputDocument.ToString)
    End Function

    Private Function Requirement1(size As Integer) As Byte()
        Using aes As New AesCryptoServiceProvider()
            aes.KeySize = size
            aes.GenerateKey()
            Return aes.Key
        End Using
    End Function

    Private Function Requirement2(data() As Byte, key() As Byte) As Byte()
        Using aes As New AesCryptoServiceProvider()
            Dim iv As Byte() = aes.IV
            Using encryptor As ICryptoTransform = aes.CreateEncryptor(key, iv)
                Using msEncrypt As MemoryStream = New MemoryStream()
                    Using csEncrypt As CryptoStream = New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
                        csEncrypt.Write(data, 0, data.Length)
                        csEncrypt.FlushFinalBlock()
                        Dim encryptedData As Byte() = msEncrypt.ToArray()
                        Dim buffer(iv.Length + encryptedData.Length - 1) As Byte
                        buffer = CombineArrays(iv, encryptedData)
                        Return buffer
                    End Using
                End Using
            End Using
        End Using
    End Function

    Private Function Requirement3(content As Byte()) As String
        Return Convert.ToBase64String(content)
    End Function

    Private Sub Requirement4(content As String, ByRef doc As XDocument)
    'added XAttribute to accommodate the required algorithm attribute
        doc.Root.Add(New XElement("ENCRYPTED_RI", content, New XAttribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#aes128-cbc")))
    End Sub

    Private Function Requirement5(content As XDocument) As Byte()
        Dim encoder As UTF8Encoding = New UTF8Encoding()
        Using hash As New SHA1CryptoServiceProvider()
            Return hash.ComputeHash(encoder.GetBytes(content.ToString()))
        End Using
    End Function

    Private Function Requirement6(hash As Byte(), key As Byte()) As Byte()
        Return CombineArrays(hash, key)
    End Function

    Private Function Requirement7(content As Byte()) As Byte()
        'I'm assuming here that they originally sent you a .cer file with their private key in it
        'Dim cert As X509Certificate2 = X509Certificate2.CreateFromCertFile("path\filename of .cer file")
        'X509Certificate2 Could not be directly specified with CreateFromCertFile. A new instance was created and set to derive its value from the retrieved X509Certificate
        Dim cert As X509Certificate2 = New X509Certificate2(X509Certificate.CreateFromCertFile("C:\cert-1.txt"))
        Using rsa As RSACryptoServiceProvider = cert.PublicKey.Key
            'This assumes PKCS7 padding which is most common
            Return rsa.Encrypt(content, False)
        End Using
    End Function

    Private Function Requirement8(content As Byte()) As String
        Return Convert.ToBase64String(content)
    End Function

    Private Sub Requirement9(content As String, ByRef doc As XDocument)
    'Added XAttribute to accommodate for the required "Algorithm" attribute
        doc.Root.Add(New XElement("ENCRYPTED_KEY", content, New XAttribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-1_5")))
    End Sub

    'Support function
    Private Function CombineArrays(array1 As Byte(), array2 As Byte())
        Dim buffer(array1.Length + array2.Length - 1) as Byte
        System.Buffer.BlockCopy(array1, 0, buffer, 0, array1.Length)
        System.Buffer.BlockCopy(array2, 0, buffer, array1.Length, array2.Length)
        Return buffer
    End Function

    Private Function Decrypt(data() As Byte, key() As Byte) As Byte()
        Dim iv((128 / 8) - 1) As Byte
        Buffer.BlockCopy(data, 0, iv, 0, iv.Length)
        Dim value(data.Length - iv.Length - 1) As Byte
        Buffer.BlockCopy(data, iv.Length, value, 0, value.Length)
        Using aes As AesCryptoServiceProvider = New AesCryptoServiceProvider()
            Using decryptor As ICryptoTransform = aes.CreateDecryptor(key, iv)
                Using msDecrypt As MemoryStream = New MemoryStream(value)
                    Using csDecrypt As CryptoStream = New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
                        Dim decrypted(msDecrypt.Length - 1) As Byte
                        csDecrypt.Read(decrypted, 0, decrypted.Length)
                        Return RemovePadding(decrypted)
                    End Using
                End Using
            End Using
        End Using
    End Function

    Private Function RemovePadding(data As Byte()) As Byte()
        Dim trimCount As Integer = 0
        For i As Integer = data.Length - 1 To data.Length - (128 / 8) + 1 Step -1
            If data(i) = 0 Then trimCount += 1 Else Exit For
        Next

        If trimCount <= 0 Then Return data

        Dim buffer((data.Length - trimCount) - 1) As Byte
        System.Buffer.BlockCopy(data, 0, buffer, 0, buffer.Length)
        Return buffer
    End Function

End Class