2016-06-16 53 views
2

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

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

  2. 使用AES对称密钥加密有效的路由输入xml文档。在128位初始化向量的前面加上密码文本。 (不建议使用所有0字节的初始化向量。)

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

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

  5. 生成明文Routing Input xml文档的SHA1哈希值。

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

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

  8. Base64对加密级联结果进行编码。

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

这里是我的代码:

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> 
+0

找出他们是否正在使用具有128,192或256位密钥的AES(这些是AES的FIPS兼容标准密钥大小)。指定了128位IV,但这是标准的,所有AES都使用IV尺寸,因为所有类型的AES使用128位块。其余的要求看起来非常简单。 – Kevin

回答

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 
+0

它回答了他用操作代码列出的每个要求(一旦他提供要发布的xml的根名称,未在问题中指定,未指定.cer文件的位置/名称也是如此)。我会说这是合格的答案。显然,结构不好(正如我在顶部指出的那样)并需要重构。我通过这种方式构建了代码,以清楚说明代码如何满足每个需求。你怎么知道这是对问题的澄清/延伸? – Kevin

+0

感谢Kevin,我对您的代码进行了一些编辑以获得可用的安全请求XML。然而,它仍然以“无效的RI XML加密”的错误作为响应我已经列出了我原始问题末尾的文档中提供的示例作为参考。你认为哪些因素会导致加密失败? – Jonathan

+0

@Kevin对不起,我很困惑,虽然它是一个自我回答的OP – Plutonix