.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=&gt;hextoraw(EncryptedText),key=&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代码执行加密的位置,特别是密钥进入吗? – Ben
我更新了第一篇文章,添加了具有所有这些功能的DB功能。 – Victor
你可以尝试两边的raws/bytes来消除字符集转换错误的风险吗? –