java和.net中的加密结果不一样

我的.net项目中有一个加密密码的方法

public string Encrypt(string plainText) { string PassPhrase = "#$^&*!@!$"; string SaltValue = "R@j@}{BAe"; int PasswordIterations = Convert.ToInt32(textBox5.Text); //amend to match java encryption iteration string InitVector = "@1B2c3D4e5F6g7H8"; int KeySize = 256; //amend to match java encryption key size byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector); byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue); byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); PasswordDeriveBytes password= new PasswordDeriveBytes( PassPhrase, saltValueBytes, "MD5", PasswordIterations); byte[] keyBytes = password.GetBytes(KeySize / 8); RijndaelManaged symmetricKey = new RijndaelManaged(); symmetricKey.Mode = CipherMode.CBC; ICryptoTransform encryptor = symmetricKey.CreateEncryptor( keyBytes, initVectorBytes); MemoryStream memoryStream = new MemoryStream(); CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write); cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); cryptoStream.FlushFinalBlock(); byte[] cipherTextBytes = memoryStream.ToArray(); memoryStream.Close(); cryptoStream.Close(); string cipherText = Convert.ToBase64String(cipherTextBytes); return cipherText; } 

我的任务是将此方法转换为java但在java中我得不到与.Net版本相同的结果

我的java代码是

 package com.andc.billing.pdc.security; import java.io.UnsupportedEncodingException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidParameterSpecException; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import javax.management.openmbean.InvalidKeyException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class PasswordCrypto { private static final String password = "#$^&*!@!$"; private static String initializationVector = "@1B2c3D4e5F6g7H8"; private static String salt = "R@j@}{BAe"; private static int pswdIterations = 2; private static int keySize = 128; private static final Log log = LogFactory.getLog(PasswordCrypto.class); public static String encrypt(String plainText) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, java.security.InvalidKeyException, NoSuchProviderException { byte[] saltBytes = salt.getBytes("ASCII");//"UTF-8"); byte[] ivBytes = initializationVector.getBytes("ASCII");//"UTF-8"); // Derive the key, given password and salt. SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");//PBEWithMD5AndDES"); PBEKeySpec spec = new PBEKeySpec( password.toCharArray(), saltBytes, pswdIterations, keySize ); SecretKey secretKey = factory.generateSecret(spec); SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Cipher.getInstance("AES/CBC/PKCSPadding" cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(ivBytes)); byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("ASCII"));//UTF-8")); String str=new org.apache.commons.codec.binary.Base64().encodeAsString(encryptedTextBytes); log.info(str); return str; } } 

.net加密的.net结果是:

 7mPh3/E/olBGbFpoA18oqw== 

java

 7RPk77AIKAhOttNLW4e5yQ== 

你能帮我解决一下这个问题吗?

我注意到的第一件事是你使用的算法是不同的,在.Net中它是PBKDF1的扩展,在java中它是PBKDF2 ,PBKDF2取代了PBKDF1。

在.net中,您使用的是PasswordDeriveBytes类 ,它“使用PBKDF1算法的扩展从密码派生密钥”。

我还注意到密码迭代在Java中被硬编码为2并且来自.Net中的文本框…确保它们是相同的。

纠正这一点,让我们知道结果。

更新:对于.net中的PBKDF2,请使用Rfc2898DeriveBytes类。

对于一些非常好的相关信息, 请阅读此页面

编辑: 此链接应该是有用的 ,如果您可以使用Chilkat库

这是1和2之间的复杂差异,1只能做多达20个字节,MS已经构建了一个允许更多的扩展,以下代码应该更准确地重新定义.net输出。 从这里开始 。

 import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.encoders.Hex; public class PKCS5Test { /** * @param args */ public static void main(String[] args) throws Exception { byte[] password = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; byte[] salt = PKCS5S1ParametersGenerator.PKCS5PasswordToBytes("MyTesting".toCharArray()); PKCS5S1ParametersGenerator generator = new PasswordDeriveBytes(new SHA1Digest()); generator.init(password, salt, 100); byte[] key = ((KeyParameter)generator.generateDerivedParameters(512)).getKey(); System.out.println( "64 " + new String(Hex.encode(key)).toUpperCase() ); } static class PasswordDeriveBytes extends PKCS5S1ParametersGenerator { private final Digest d; private byte[] output = null; public PasswordDeriveBytes(Digest d) { super(d); this.d = d; } public CipherParameters generateDerivedParameters(int keySize) { keySize = keySize / 8; byte[] result = new byte[keySize]; int done = 0; int count = 0; byte[] b = null; while (done < result.length) { if (b == null) { b = generateInitialKey(); } else if (++count < 1000) { b = generateExtendedKey(++count); } else { throw new RuntimeException("Exceeded limit"); } int use = Math.min(b.length, result.length - done); System.arraycopy(b, 0, result, done, use); done += use; } return new KeyParameter(result); } private byte[] generateOutput() { byte[] digestBytes = new byte[d.getDigestSize()]; d.update(password, 0, password.length); d.update(salt, 0, salt.length); d.doFinal(digestBytes, 0); for (int i = 1; i < (iterationCount - 1); i++) { d.update(digestBytes, 0, digestBytes.length); d.doFinal(digestBytes, 0); } return digestBytes; } private byte[] generateInitialKey() { output = generateOutput(); d.update(output, 0, output.length); byte[] digestBytes = new byte[d.getDigestSize()]; d.doFinal(digestBytes, 0); return digestBytes; } private byte[] generateExtendedKey(int count) { byte[] prefix = Integer.toString(count).getBytes(); d.update(prefix, 0, prefix.length); d.update(output, 0, output.length); byte[] digestBytes = new byte[d.getDigestSize()]; d.doFinal(digestBytes, 0); //System.err.println( "X: " + new String(Hex.encode(digestBytes)).toUpperCase() ); return digestBytes; } } } 

非常感谢您提供的解决方案 – 它运行良好,但有一个小的修正(根据下面提到的初始post):

请用:

 b = generateExtendedKey(count); 

代替:

 b = generateExtendedKey(++count); 

它甚至可以用于256键大小:

这是一个使用256位密钥解密C#Rijndael编码数据的小代码:

 public static String decrypt(final String cipherText, final String passPhrase, final String saltValue, final int passwordIterations, final String initVector, final int keySize) throws Exception { final byte[] initVectorBytes = initVector.getBytes("ASCII"); final byte[] saltValueBytes = saltValue.getBytes("ASCII"); final byte[] cipherTextBytes = Base64.decode(cipherText); final PKCS5S1ParametersGenerator generator = new PasswordDeriveBytes(new SHA1Digest()); generator.init(passPhrase.getBytes("ASCII"), saltValueBytes, passwordIterations); final byte[] key = ((KeyParameter) generator.generateDerivedParameters(keySize)).getKey(); final SecretKey secretKey = new SecretKeySpec(key, ALGORITHM); final Cipher cipher = Cipher.getInstance(TRANSFORMATION); final IvParameterSpec iv = new IvParameterSpec(initVectorBytes); cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); final byte[] decryptedVal = cipher.doFinal(cipherTextBytes); return new String(decryptedVal); } 

Addon:如果你关心密钥大小限制,你可以使用这个工作正常的解决方案 (在Ubuntu 12下测试,Java 1.7 64位(java版本“1.7.0_25”Java(TM)SE运行时环境(版本1.7.0_25) -b15)Java HotSpot(TM)64位服务器VM(内置23.25-b01,混合模式))