2015-10-29 118 views
3

我很難複製oracle如何使用AES 256 + CBC + PKCS5/7將它複製到C#中進行加密。感謝您的幫助。將Oracle AES 256加密複製到C#

我在Oracle包下面的函數(簡體):

--Character set used by GEN_ENCRYPT_PASSWORD and GEN_DECRYPT_PASSWORD 
G_CHARACTER_SET VARCHAR2(10) := 'AL32UTF8';  
FUNCTION GEN_ENCRYPT_PASSWORD(p_in_val  IN VARCHAR2 
            ,p_key   IN VARCHAR2           
            ,p_iv   IN VARCHAR2 := NULL) 
      RETURN RAW 
     IS 
      l_enc_val RAW(4000); 
      l_enc_algo PLS_INTEGER; 
      l_in   RAW(4000); 
      l_iv   RAW(4000); 
      l_key  RAW(4000); 
      --l_ret  VARCHAR2(4000 CHAR); 
      v_mod  NUMBER; 
     BEGIN 
      l_in   := UTL_I18N.STRING_TO_RAW(data => p_in_val, dst_charset => G_CHARACTER_SET); 
      l_iv   := UTL_I18N.STRING_TO_RAW(p_iv, G_CHARACTER_SET); 
      l_key  := UTL_I18N.STRING_TO_RAW(data => p_key, dst_charset => G_CHARACTER_SET); 
      l_enc_algo := DBMS_CRYPTO.encrypt_aes256; 
      --chain_cbc: Cipher Block Chaining. Plaintext is XORed with the previous ciphertext block before it is encrypted. 
      --pad_pkcs5: Provides padding which complies with the PKCS #5: Password-Based Cryptography Standard. 
      v_mod  := (l_enc_algo + DBMS_CRYPTO.chain_cbc + DBMS_CRYPTO.pad_pkcs5); 

      l_enc_val := DBMS_CRYPTO.encrypt(src => l_in, KEY => l_key, typ => v_mod); 
      --l_ret  := RAWTOHEX(l_enc_val); 
      RETURN l_enc_val; 
     END GEN_ENCRYPT_PASSWORD; 

     FUNCTION GEN_DECRYPT_PASSWORD(p_in_val  IN RAW 
            ,p_key   IN VARCHAR2           
            ,p_iv   IN VARCHAR2 := NULL) 
      RETURN VARCHAR2 
     IS 
      l_enc_val RAW(4000); 
      l_enc_algo PLS_INTEGER; 
      l_in   RAW(4000); 
      l_iv   RAW(4000); 
      l_key  RAW(4000); 
      l_ret  VARCHAR2(4000 CHAR); 
      v_mod  NUMBER; 
     BEGIN 
      l_in   := p_in_val;   --UTL_I18N.STRING_TO_RAW(data => p_in_val, dst_charset => G_CHARACTER_SET); 

      l_iv   := UTL_I18N.STRING_TO_RAW(p_iv, G_CHARACTER_SET); 
      l_key  := UTL_I18N.STRING_TO_RAW(data => p_key, dst_charset => G_CHARACTER_SET); 

      l_enc_algo := DBMS_CRYPTO.encrypt_aes256; 

      --chain_cbc: Cipher Block Chaining. Plaintext is XORed with the previous ciphertext block before it is encrypted. 
      --pad_pkcs5: Provides padding which complies with the PKCS #5: Password-Based Cryptography Standard. 
      v_mod  := (l_enc_algo + DBMS_CRYPTO.chain_cbc + DBMS_CRYPTO.pad_pkcs5); 

      l_enc_val := DBMS_CRYPTO.decrypt(src => l_in, KEY => l_key, typ => v_mod); 
      l_ret  := UTL_I18N.raw_to_char(data => l_enc_val, src_charset => G_CHARACTER_SET); 

      RETURN l_ret; 
     END GEN_DECRYPT_PASSWORD; 

然後我跑的查詢:

SELECT pkg_Encyption_Test.GEN_ENCRYPT_PASSWORD('Test', '123456789', '26744a68b53dd87a') Encrypted FROM DUAL; 
--Result: 7D2894678D46C769B3001BD75F603E3C 

和解密結果:

SELECT pkg_Encyption_Test.GEN_DECRYPT_PASSWORD('7D2894678D46C769B3001BD75F603E3C', '123456789', '26744a68b53dd87a') Decrypt from dual; 
--Result: Test 

所以以上所有的作品,問題是我怎樣才能轉換爲由C#使用來解密結果? 示例控制檯應用程序:

using System; 
using System.IO; 
using System.Security.Cryptography; 
using System.Text; 

namespace SSO_EncryptionTest 
{ 
    class Program 
    { 
     /* ORACLE 
     * TEXT ENC: 7D2894678D46C769B3001BD75F603E3C 
     * TEXT: Test 
     * KEY: 123456789
     * .NET 
     * ENC: EAAAADI2NzQ0YTY4YjUzZGQ4N2GfHsbuE8t1/hhwz3v9isJ1   
     */ 
     static void Main(string[] args) 
     { 
      //Use the values from Oracle 
      string inputText = "Test"; 
      string encryptedTextValue = "7D2894678D46C769B3001BD75F603E3C"; 
      string encryptPrivateKey = "123456789"; 
      string encryptSharedIV = "26744a68b53dd87a"; 

      Console.WriteLine("******************** Initial values from Oracle ******************"); 
      Console.WriteLine("inputText: '{0}'", inputText); 
      Console.WriteLine("encryptedTextValue: '{0}'", encryptedTextValue); 
      Console.WriteLine("encryptPrivateKey: '{0}'", encryptPrivateKey); 
      Console.WriteLine("encryptSharedIV: '{0}'", encryptSharedIV); 
      Console.WriteLine(); 

      //This is just here to convert the Encrypted byte array to a string for viewing purposes. 
      UTF8Encoding UTF = new UTF8Encoding(); 
      byte[] inputTextByte = UTF.GetBytes(inputText); 
      byte[] encryptedTextValueByte = UTF.GetBytes(encryptedTextValue); 
      byte[] encryptPrivateKeyByte = UTF.GetBytes(encryptPrivateKey); 
      byte[] encryptSharedIvByte = UTF.GetBytes(encryptSharedIV); 

      string Encrypted_Text; 
      //string Decrypted; 
      try 
      { 
       Console.WriteLine("********************Encryption Example******************"); 

       Console.WriteLine("Plain text is: '{0}'", inputText); 
       Encrypted_Text = EncryptOracleAES(inputTextByte, encryptPrivateKeyByte, encryptSharedIvByte); 
       Console.WriteLine("Encrypted text is: '{0}'", Encrypted_Text);    

       Console.WriteLine(); 

       /*Console.WriteLine("********************Decryption Example******************"); 
       Console.WriteLine("Input Encrypted text is '{0}'", XXXXXXXXXXXX); 
       Decrypted = ""; 
       Console.WriteLine("Decrypted text is: '{0}'", Decrypted);*/ 

      } 
      catch (Exception e) 
      { 
       Console.WriteLine("Exception: {0}", e.Message); 
      } 

      Console.WriteLine("Press enter to exit"); 

      Console.ReadLine(); 
     } 

     public static string EncryptOracleAES(byte[] plainText, byte[] privateKey, byte[] sharedIVKey) 
     { 
      //select UTL_I18N.STRING_TO_RAW('Test', 'AL32UTF8') from dual; 
      //54657374   

      string outStr = null;      // Encrypted string to return 
      AesManaged aesAlg = null; 
      try 
      {     
       aesAlg = new AesManaged(); 
       aesAlg.Key = privateKey; 
       aesAlg.KeySize = 256; 
       aesAlg.BlockSize = 128; 
       aesAlg.Padding = PaddingMode.PKCS7; //Same as PKCS5/7 
       aesAlg.Mode = CipherMode.CBC; 
       aesAlg.IV = sharedIVKey; 
       ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, sharedIVKey); 

       using (MemoryStream msEncrypt = new MemoryStream()) 
       { 
        // prepend the IV 
        msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int)); 
        msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length); 

        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) 
        { 
         using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) 
         { 
          //Write all data to the stream. 
          swEncrypt.Write(plainText); 
         } 
        } 
        outStr = Convert.ToBase64String(msEncrypt.ToArray()); 
       } 
      } 
      finally 
      { 

       if (aesAlg != null) 
        aesAlg.Clear(); 
      } 

      // Return the encrypted bytes from the memory stream. 
      return outStr; 

     } 
    } 
} 

但我的結果並不一致:

******************** Initial values from Oracle ****************** 
inputText: 'Test' 
encryptedTextValue: '7D2894678D46C769B3001BD75F603E3C' 
encryptPrivateKey: '123456789' 
encryptSharedIV: '26744a68b53dd87a' 

********************Encryption Example****************** 
Plain text is: 'Test' 
Encrypted text is: 'EAAAADI2NzQ0YTY4YjUzZGQ4N2FCXNXYzo2xWZym3dNFwCSJ' 

我缺少什麼?

+2

'UTF.GetBytes( 「AB」)'將返回字符代碼字符A和B'{65,66}'不是您需要的'0xAB'(171)的字節值。您需要[將十六進制字符串轉換爲字節數組](http://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array) –

+0

對不起我得到了邏輯,但沒有看到何時需要進行轉換。我使用了LINQ調用:public static byte [] StringToByteArray(string hex) { return Enumerable.Range(0,hex.Length) .Where(x => x%2 == 0) .Select(x = > Convert.ToByte(hex.Substring(x,2),16)) .ToArray(); } – AhsenB

+1

您可以用鏈接答案 –

回答

2

主要問題是我的select語句在我傳入IV值(與解密相同)時,我的選擇語句缺少參數'AES256'......我責怪同事經常爲此煩惱:)。

SELECT pkg_Encyption_Test.GEN_ENCRYPT_PASSWORD('Test', '123456789', '26744a68b53dd87a') Encrypted FROM DUAL; 
--Result: 7D2894678D46C769B3001BD75F603E3C 

本來應該是:

SELECT pkg_Encyption_Test..GEN_ENCRYPT_PASSWORD('Test' 
             ,'123456789' 
             ,'AES256' --Or NULL 
             ,'26744a68b53dd87a26744a68b53dd87a') 
      Encrypted 
    FROM DUAL; 
--Result: E320A0CABF881088A424B4F36F188029 

這需要重構,但總的想法是存在的。

類:

public static string EncryptUsingAes(byte[] inputTextByte, byte[] privateKeyByte, byte[] sharedIVKeyByte) 
     { 
      using (var aesEncryption = AesEncryption.AesEncryptionType(privateKeyByte, sharedIVKeyByte)) 
      { 
       // Convert string to byte array     
       byte[] dest = new byte[inputTextByte.Length]; 

       // encryption 
       using (ICryptoTransform encrypt = aesEncryption.CreateEncryptor(aesEncryption.Key, aesEncryption.IV)) 
       { 
        dest = encrypt.TransformFinalBlock(inputTextByte, 0, inputTextByte.Length); 

        encrypt.Dispose();       
       } 
       return BitConverter.ToString(dest).Replace("-", ""); 
      } 
     } 

public static string DecryptUsingAes(byte[] inputTextByte, byte[] privateKeyByte, byte[] sharedIVKeyByte) 
     { 
      using (var aesDecryption = AesEncryption.AesEncryptionType(privateKeyByte, sharedIVKeyByte)) 
      { 
       // Convert string to byte array     
       byte[] dest = new byte[inputTextByte.Length]; 

       // encryption 
       using (ICryptoTransform decrypt = aesDecryption.CreateDecryptor(aesDecryption.Key, aesDecryption.IV)) 
       { 
        dest = decrypt.TransformFinalBlock(inputTextByte, 0, inputTextByte.Length); 

        decrypt.Dispose(); 

       } 
       // Convert byte array to UTF8 string 
       return Encoding.UTF8.GetString(dest); ; 
      } 
     } 

和主:AesEncryption

public static AesCryptoServiceProvider AesEncryptionType(byte[] privateKeyByte, byte[] sharedIVKeyByte) 
     { 
      var aes = new AesCryptoServiceProvider(); 
      aes.BlockSize = 128; 
      aes.KeySize = 256; 
      aes.IV = sharedIVKeyByte; 
      aes.Key = privateKeyByte; 
      aes.Mode = CipherMode.CBC; 
      aes.Padding = PaddingMode.PKCS7; 
      return aes; 
     } 

變化我去

private static void Main(string[] args) 
     { 
      //Use the values from Oracle 
      string inputText = "Test"; 
      string encryptionType = "AES256"; 
      string encryptPrivateKey = "123456789"; 
      string encryptSharedIV = "26744a68b53dd87a";//26744a68b53dd87a26744a68b53dd87a"; 
      string encryptedTextValue = "E320A0CABF881088A424B4F36F188029"; 

      Console.WriteLine("******************** Initial values from Oracle ******************"); 
      Console.WriteLine("inputText: '{0}'", inputText); 
      Console.WriteLine("encryptionType: '{0}'", encryptionType); 
      Console.WriteLine("encryptedTextValue: '{0}'", encryptedTextValue); 
      Console.WriteLine("encryptPrivateKey: '{0}'", encryptPrivateKey); 
      Console.WriteLine("encryptSharedIV: '{0}'", encryptSharedIV); 

      //OracleRaw 
      string oracleRawText = "54657374"; 
      string oracleRawPrivateKey = "3132333435363738393031323334353637383930313233343536373839303132"; 
      string oracleRawSharedIV = "32363734346136386235336464383761"; //26744a68b53dd87a - IV is 16 byte array.    

      Console.WriteLine("******************** Initial values from Oracle OracleRaw ******************"); 
      Console.WriteLine("oracleRawText: '{0}'", oracleRawText); 
      Console.WriteLine("oracleRawPrivateKey: '{0}'", oracleRawPrivateKey); 
      Console.WriteLine("oracleRawSharedIV: '{0}'", oracleRawSharedIV); 
      Console.WriteLine(); 

      //This is just here to convert the Encrypted byte array to a string for viewing purposes. 
      var utf = new UTF8Encoding(); 
      byte[] inputTextByte = utf.GetBytes(inputText); //byte: 4 - "Test" 
      byte[] privateKeyByte = utf.GetBytes(encryptPrivateKey); //byte: 32 - "123456789" 
      byte[] sharedIVByte = utf.GetBytes(encryptSharedIV); //byte: 16 - "26744a68b53dd87a" 

      //string Decrypted; 
      try 
      { 
       string encryptedText = string.Empty; 

       byte[] oracleRawTextByte = StringToByteArray(oracleRawText); 
       byte[] oracleRawPrivateKeyByte = StringToByteArray(oracleRawPrivateKey); 
       byte[] oracleRawSharedIVByte = StringToByteArray(oracleRawSharedIV); 

       encryptedText = EncryptUsingAes(oracleRawTextByte, oracleRawPrivateKeyByte, oracleRawSharedIVByte); 
       Console.WriteLine("********************Encryption Example EncryptUsingAes(OracleRaw) ******************"); 
       Console.WriteLine("Plain text is: '{0}'", inputText); 
       Console.WriteLine("Encrypted text is: '{0}'", encryptedText); 
       Console.WriteLine(); 

       encryptedText = EncryptUsingAes(inputTextByte, privateKeyByte, sharedIVByte); 
       Console.WriteLine("********************Encryption Example EncryptUsingAes******************"); 
       Console.WriteLine("Plain text is: '{0}'", inputText); 
       Console.WriteLine("Encrypted text is: '{0}'", encryptedText); 
       Console.WriteLine(); 

       Console.WriteLine("********************Encryption Example DecryptUsingAes******************"); 
       Console.WriteLine("Encrypted text is: '{0}'", encryptedText); 

       byte[] cypherText = StringToByteArray(encryptedText); 

       encryptedText = DecryptUsingAes(cypherText, privateKeyByte, sharedIVByte); 

       Console.WriteLine("Plain text is: '{0}'", encryptedText); 
       Console.WriteLine();      
      } 
      catch (Exception e) 
      { 
       Console.WriteLine("Exception: {0}", e.Message); 
      } 

      Console.WriteLine("Press enter to exit"); 
      Console.ReadLine(); 
     } 
    } 
+1

?爲什麼使用 - 返回BitConverter.ToString(dest).Replace(「 - 」,「」); – pordi

+1

如果你這樣做---返回BitConverter.ToString(dest).Replace(「 - 」,「」);那麼解密時會出錯。只要使用Convert.ToBase64String()就可以了。儘管如此,感謝這個美妙的解決方案 – pordi