Oracle和.NET中的不同DES加密 [英] Different DES Encryption in Oracle and .NET

查看:129
本文介绍了Oracle和.NET中的不同DES加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



对于DB,我使用以下加密类型的 DBMS_CRYPTO.ENCRYPT 函数: p>

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

数据库功能

  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加密;

这里是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);

什么可能是加密结果不同的原因?

解决方案

.NET和Oracle加密之间存在基本差异。



例如,Oracle的默认初始化值)为0123456789ABCDEF。
.NET的默认初始化值(IV)为C992C3154997E0FB。
另外,.NET中有多种填充模式选项:ANSIX923,Zeros,ISO10126,PKCS7和无。



在下面的示例代码中,能够在没有用于自定义填充的两行代码的情况下进行操作,并为填充模式指定ANSIX923。我们不得不容纳一个来自DBA的人造pas,他们决定用波浪号〜字符填充字符串,所以我把代码作为一个例子,可以帮助别人在类似的情况下。



这是一个简单的方法,适用于我们的解决方案:

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

string iv =0123456789ABCDEF;

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);

返回StringUtilities.ByteArrayToHexString(encrptedBytes);
}

///< summary>
//在Oracle方面,我们的DBA将对该工具包加密函数的调用包装到〜,我不建议
//做这个路径,容易出错。
//我们正在使用大小为8字节的块,该方法用〜个字符填充最后一个块。
///< / 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单位;
if((lengthOfData%8)!= 0)
{
units =(lengthOfData / 8)+ 1;
}
else
{
units = lengthOfData / 8;
}

lengthOfPaddedString = units * 8;

message = message.PadRight(lengthOfPaddedString,'〜');
返回消息;
}


public static byte [] Encrypt(byte [] clearData,byte [] Key,byte [] IV)
{
MemoryStream ms =新的MemoryStream();
//创建一个对称算法。
TripleDES alg = TripleDES.Create();
alg.Padding = PaddingMode.None;
//你应该能够在正常的实现中指定ANSIX923
//由于DBA的包装器
//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> 
///将十六进制字符对
///的字符串转换为字节数组的方法。
///< / summary>
///< param name =hexValue>十六进制字符串字符串< / param>
///< returns>一个字节数组< / returns>
///< exception cref =System.ArgumentNullException>当参数为空时抛出。< / exception>
///< exception cref =System.ArgumentException>当参数包含奇数个字符时抛出。< / exception>
///< exception cref =System.FormatException>当参数包含非十六进制字符时抛出。< / exception>
public static byte [] HexStringToByteArray(string hexValue)
{
ArgumentValidation.CheckNullReference(hexValue,hexValue);

if(hexValue.Length%2 == 1)
throw new ArgumentException(ERROR:String必须有偶数个字符,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);

返回值;
} // HexStringToByteArray()


///< summary>
///将字节数组转换为十六进制字符串的方法。
///< / summary>
///< param name =values> Byte array。< / param>
///< returns>十六进制字符串< / returns>
///< exception cref =System.ArgumentNullException>当参数为空时抛出。< / exception>
public static string ByteArrayToHexString(byte [] values)
{
ArgumentValidation.CheckNullReference(values,values);

StringBuilder hexValue = new StringBuilder();

foreach(值中的字节值)
{
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();
}

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

 创建或替换FUNCTION DecryptPassword(EncryptedText IN VARCHAR2,EncKey IN VARCHAR2)RETURN VARCHAR2 
IS
encda​​ta RAW(2000);
numpad NUMBER;
result VARCHAR2(100);
BEGIN
encda​​ta:= dbms_obfuscation_toolkit.DES3Decrypt(input =& amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp; amp;

result:= rawtohex(encda​​ta);
numpad:= substr(result,length(result)-1);
result:= substr(result,1,length(result) - (numpad * 2));
result:= hextoraw(result);
result:= utl_raw.cast_to_varchar2(result);
返回结果;

END DecryptPassword;


For some reason, I am getting different encoding results from Oracle DMBS_CRYPTO and .NET implementation of DESCryptoServiceProvider using the same encryption key.

For the DB I am using DBMS_CRYPTO.ENCRYPT function with the following encryption type:

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

The DB Function

 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;

And here's the C# piece:

            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);

What could be the reason for having different encryption results?

解决方案

There are basic differences between .NET and Oracle encryption.

For instance, Oracle's default Initialization Value (IV) in hex is "0123456789ABCDEF". .NET 's default Initialization Value (IV) in hex is "C992C3154997E0FB". Also, there are several options for padding modes in .NET: ANSIX923, Zeros, ISO10126, PKCS7 and None.

In the sample code below, you should be able to do without the two lines of code used for the custom padding, and specify ANSIX923 for the padding mode. We had to accommodate a faux pas from the DBAs who decided to pad strings with the tilde "~" character, so I included the code to serve as an example that may help others in a similar situation.

Here's a simple set of methods that worked for our solution:

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

        string iv = "0123456789ABCDEF";

        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;
    }

Put these methods in a static StringUtilities class:

    /// <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();
    } 

If you are using the ANSIX923 padding mode from the .NET side, your PL/SQL code will look like this because you have to read the last two bytes to figure out how many bytes were padded and remove them from the string so you return the original string.

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;

这篇关于Oracle和.NET中的不同DES加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆