2012-10-02 65 views
0

出于某种原因,我使用相同的加密密钥从Oracle DMBS_CRYPTO和.NET实现DESCryptoServiceProvider获得不同的编码结果。Oracle和.NET中的不同DES加密

对于我使用DBMS_CRYPTO.ENCRYPT功能具有以下加密类型的DB:

encryption_type PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES 
           + DBMS_CRYPTO.CHAIN_CBC 
           +DBMS_CRYPTO.PAD_PKCS5; 

的DB功能

FUNCTION encrypt (p_plainText VARCHAR2) RETURN RAW DETERMINISTIC 
IS 
    encrypted_raw  RAW (2000); 
BEGIN 
    encrypted_raw := DBMS_CRYPTO.ENCRYPT 
    (
     src => UTL_RAW.CAST_TO_RAW (p_plainText), 
     typ => encryption_type, 
     key => encryption_key 
    ); 
    RETURN encrypted_raw; 
END encrypt; 

而这里的C#件:

  DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider(); 
     MemoryStream memoryStream = new MemoryStream(); 
     CryptoStream cryptoStream = new CryptoStream(memoryStream, 
      cryptoProvider.CreateEncryptor(bytes, bytes), CryptoStreamMode.Write); 
     StreamWriter writer = new StreamWriter(cryptoStream); 
     writer.Write(originalString); 
     writer.Flush(); 
     cryptoStream.FlushFinalBlock(); 
     writer.Flush(); 
     return Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length); 

有什么事情是不同的加密结果的原因?

+0

可以显示oracle代码执行加密的位置,特别是密钥进入吗? – Ben

+0

我更新了第一篇文章,添加了具有所有这些功能的DB功能。 – Victor

+1

你可以尝试两边的raws/bytes来消除字符集转换错误的风险吗? –

回答

0

该问题可能是与钥匙的你有used.Check使用不同的密钥/填充不同的填充

1

the MSDN documentation,你的C#代码使用PKCS7的默认填充,而它看起来像你的Oracle代码使用PKCS5。那可能是一个开始的好地方。当你在这个时候,你也应该明确地设置你的块链接模式。

编辑:对不起,PKCS5和PKCS7应该填充相同的字节长度相同的明文。这可能不是。 Vincent Malgrat的建议是尝试用纯字节来消除编码问题听起来像是一个很好的开始。 C#代码会将您的字符串视为unicode。在Oracle中,我认为它会使用数据库的编码设置。

1

.NET和Oracle加密之间有基本的区别。

例如,Oracle的默认初始值(IV)十六进制是“ABCDEF”。 NET的默认初始值(IV)十六进制是“C992C3154997E0FB”。另外,在.NET中有几种填充模式的选项:ANSIX923,零,ISO10126,PKCS7和无。

在下面的示例代码中,您应该可以不使用用于自定义填充的两行代码,并指定ANSIX923作为填充模式。我们必须容纳来自DBA的人员,他们决定使用代字符“〜”来填充字符串,因此我将代码包含在可以帮助其他人处理类似情况的示例中。

下面是一组简单的,对于我们的解决方案工作方法:

private static string EncryptForOracle(string message, string key) 
    { 

     string iv = "ABCDEF"; 

     int lengthOfPaddedString; 
     message = PadMessageWithCustomChar(message, out lengthOfPaddedString); 

     byte[] textBytes = new byte[lengthOfPaddedString]; 
     textBytes = ASCIIEncoding.ASCII.GetBytes(message); 

     byte[] keyBytes = new byte[key.Length]; 
     keyBytes = ASCIIEncoding.ASCII.GetBytes(key); 

     byte[] ivBytes = new byte[iv.Length]; 
     ivBytes = StringUtilities.HexStringToByteArray(iv); 
     byte[] encrptedBytes = Encrypt(textBytes, keyBytes, ivBytes); 

     return StringUtilities.ByteArrayToHexString(encrptedBytes); 
    } 

    /// <summary> 
    // On the Oracle side, our DBAs wrapped the call to the toolkit encrytion function to pad with a ~, I don't recommend 
    // doing down this path, it is prone to error. 
    // we are working with blocks of size 8 bytes, this method pads the last block with ~ characters. 
    /// </summary> 
    /// <param name="message"></param> 
    /// <param name="lengthOfPaddedString"></param> 
    /// <returns></returns> 
    private static string PadMessageWithCustomChar(string message, out int lengthOfPaddedString) 
    { 
     int lengthOfData = message.Length; 
     int units; 
     if ((lengthOfData % 8) != 0) 
     { 
      units = (lengthOfData/8) + 1; 
     } 
     else 
     { 
      units = lengthOfData/8; 
     } 

     lengthOfPaddedString = units * 8; 

     message = message.PadRight(lengthOfPaddedString, '~'); 
     return message; 
    } 


    public static byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV) 
    { 
     MemoryStream ms = new MemoryStream(); 
     // Create a symmetric algorithm. 
     TripleDES alg = TripleDES.Create(); 
     alg.Padding = PaddingMode.None; 
     // You should be able to specify ANSIX923 in a normal implementation 
     // We have to use none because of the DBA's wrapper 
     //alg.Padding = PaddingMode.ANSIX923; 

     alg.Key = Key; 
     alg.IV = IV; 

     CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); 
     cs.Write(clearData, 0, clearData.Length); 
     cs.Close(); 

     byte[] encryptedData = ms.ToArray(); 
     return encryptedData; 
    } 

把这些方法在静态StringUtilities类:

/// <summary> 
    /// Method to convert a string of hexadecimal character pairs 
    /// to a byte array. 
    /// </summary> 
    /// <param name="hexValue">Hexadecimal character pair string.</param> 
    /// <returns>A byte array </returns> 
    /// <exception cref="System.ArgumentNullException">Thrown when argument is null.</exception> 
    /// <exception cref="System.ArgumentException">Thrown when argument contains an odd number of characters.</exception> 
    /// <exception cref="System.FormatException">Thrown when argument contains non-hexadecimal characters.</exception> 
    public static byte[] HexStringToByteArray(string hexValue) 
    { 
     ArgumentValidation.CheckNullReference(hexValue, "hexValue"); 

     if (hexValue.Length % 2 == 1) 
      throw new ArgumentException("ERROR: String must have an even number of characters.", "hexValue"); 

     byte[] values = new byte[hexValue.Length/2]; 

     for (int i = 0; i < values.Length; i++) 
      values[i] = byte.Parse(hexValue.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); 

     return values; 
    } // HexStringToByteArray() 


    /// <summary> 
    /// Method to convert a byte array to a hexadecimal string. 
    /// </summary> 
    /// <param name="values">Byte array.</param> 
    /// <returns>A hexadecimal string.</returns> 
    /// <exception cref="System.ArgumentNullException">Thrown when argument is null.</exception> 
    public static string ByteArrayToHexString(byte[] values) 
    { 
     ArgumentValidation.CheckNullReference(values, "values"); 

     StringBuilder hexValue = new StringBuilder(); 

     foreach (byte value in values) 
     { 
      hexValue.Append(value.ToString("X2")); 
     } 

     return hexValue.ToString(); 
    } // ByteArrayToHexString() 

    public static byte[] GetStringToBytes(string value) 
    { 
     SoapHexBinary shb = SoapHexBinary.Parse(value); 
     return shb.Value; 
    } 

    public static string GetBytesToString(byte[] value) 
    { 
     SoapHexBinary shb = new SoapHexBinary(value); 
     return shb.ToString(); 
    } 

如果您正在使用从该ANSIX923填充模式。 NET方面,你的PL/SQL代码看起来像这样,因为你必须读取最后两个字节来确定填充了多少字节并将它们从字符串中移除,以便返回原始字符串。

create or replace FUNCTION DecryptPassword(EncryptedText IN VARCHAR2,EncKey IN VARCHAR2) RETURN VARCHAR2 
IS 
encdata RAW(2000); 
numpad NUMBER; 
result VARCHAR2(100); 
BEGIN 
    encdata:=dbms_obfuscation_toolkit.DES3Decrypt(input=&amp;gt;hextoraw(EncryptedText),key=&amp;gt;UTL_RAW.CAST_TO_RAW(EncKey)); 

    result :=rawtohex(encdata); 
    numpad:=substr(result,length(result)-1); 
    result:= substr(result,1,length(result)-(numpad*2)); 
    result := hextoraw(result); 
    result := utl_raw.cast_to_varchar2(result); 
    return result; 

END DecryptPassword;