2016-06-16 81 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