C#DES加解密的密钥和java DES加解密的SecureRandom密钥一致互通问题

在维护旧版本的代码需要将java版的des加密换成c#版的,java 的DES的填充模式默认是ecb模式,c#对应的模式也要改成ecb模式,关于两种语言的DES算法加解密网上的文章多的是,自行搜索即可。我要讲的是在java端用了SecureRandom来指定明文密钥作为种子生成密钥后加密后,c#要使用同样的明文密钥来解密一致性问题。

JAVA DES 生成密钥的方式

/**
* 将二进制转换成16进制字符串
* @param buf
* @return
 */
public static String parseByte2HexStr(byte buf []){
   StringBuffer sb = new StringBuffer();
   for(int i = 0; i < buf.length; i++){
      String hex = Integer.toHexString(buf[i] & 0xFF);
      if(hex.length() == 1){
          hex = '0' + hex;
      }
      sb.append(hex.toUpperCase());
   }
   return sb.toString();
}
String secret = "977050781250000";
byte[] seed = secret.getBytes("UTF-8");
//KeyGenerator keyGen = KeyGenerator.getInstance("AES");
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
//keyGen.init(128, sr);  //AES使用
keyGen.init( sr);
SecretKey key = keyGen.generateKey();
byte[] keyArray =key.getEncoded();
System.out.println("key:"+parseByte2HexStr(keyArray)); //结果为 892C9D649B382C9B

java DES的密钥如果要换成c#版的密钥,只需对明文密钥做两次SHA1后转成十六进制取前16位字符即为C#版的密钥。但c#DES的密钥用两次SHA1后,是没法解密出java的加密串的,这个问题困扰了我很多天,网上基本找不到解决方案。后来我查了java jdk的源代码,得知java的DES密钥除了两次SHA1外,加多了一个奇偶数校验调整,于是看到了光明。

C# DES 生成java对应的密钥方式

/// <summary>
/// 将DES明文密钥转成java对应的通过SecureRandom后转换的des密钥
/// </summary>
/// <param name="key">输入字符串。</param>
/// <param name="charset">字符编码。</param>
/// <returns>转换后的DES密钥。(16个十六进制字符)</returns>
public static string ToJavaDesKey(string key, String charset = "")
{
	Encoding encoding;
	if (charset == "")
	{
		encoding = Encoding.UTF8;
	}
	else
	{
		encoding = Encoding.GetEncoding(charset);
	}
	byte[] keyArray;

	byte[] seed = encoding.GetBytes(key);
	//两次sha1,即可转换成和java aes一样的密钥
	using (var st = new SHA1CryptoServiceProvider())
	{

		using (var nd = new SHA1CryptoServiceProvider())
		{
			keyArray = nd.ComputeHash(st.ComputeHash(seed));

		}
	}
	setParityBit(keyArray, 0); //奇偶校验调整
	return byteToHexStr(keyArray).Substring(0, 16);  //取前16位作为DES的密钥
}
//奇偶校验调整
static void setParityBit(byte[] key, int offset)
{
	if (key == null)
		return;

	for (int i = 0; i < 8; i++)
	{
		int b = key[offset] & 0xfe;
		b |= (BitCount(b) & 1) ^ 1;
		key[offset++] = (byte)b;
	}


}
//统计一个数的二进制位有多少个 ,对应java的Integer.bitCount
static int BitCount(int value)
{
	value = (value & 0x55555555) + ((value >> 1) & 0x55555555);
	value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
	value = (value & 0x0f0f0f0f) + ((value >> 4) & 0x0f0f0f0f);
	value = (value * (0x01010101)) >> 24;
	return value;
}
/// 字节数组转16进制字符串 
/// </summary> 
/// <param name="bytes"></param> 
/// <returns></returns> 
public static string byteToHexStr(byte[] bytes)
{
	StringBuilder strbuf = new StringBuilder(bytes.Length * 2);
	int i;
	for (i = 0; i < bytes.Length; i++)
	{
		strbuf.Append(((int)bytes[i] & 0xff).ToString("X2"));
	}
	return strbuf.ToString();
}
/**
 * @Description 16进制转化为2进制
 * @param hexStr
 * @return
 */

public static byte[] parseHexStr2Byte(String hexStr)
{
	try
	{

		if (hexStr.Length < 1)
		{
			return null;
		}
		byte[] result = new byte[hexStr.Length / 2];
		string tt = "";
		string kk = "";
		for (int i = 0; i < hexStr.Length / 2; i++)
		{
			tt = hexStr.Substring(i * 2, 2);

			result[i] = (byte)Convert.ToByte(tt, 16);

		}
		return result;
	}
	catch (Exception e)
	{

		throw;
	}

}
String key = "977050781250000";
string new_key = ToJavaDesKey(key);  //得到的结果为 892C9D649B382C9B,和java的一致
//des.Key = parseHexStr2Byte(new_key ); //将得到的new_key用于DES,即可解密出java加密的结果,这里不再叙述。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值