我的.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
加密“1”的结果是:
7mPh3/E/olBGbFpoA18oqw==
而java
是
7RPk77AIKAhOttNLW4e5yQ==
请你帮我解决这个问题吗?
答案 0 :(得分:4)
我首先注意到的是你使用的算法是不同的,在.Net中它是PBKDF1的扩展,在java中它是PBKDF2,PBKDF2取代了PBKDF1
在.net中,您正在使用the PasswordDeriveBytes class"使用PBKDF1算法的扩展从密码中获取密钥。"
我还注意到密码迭代在Java中硬编码为2,来自.Net中的文本框...确保它们是相同的。
纠正这一点,让我们知道结果。
更新:对于.net中的PBKDF2,请使用Rfc2898DeriveBytes类。
对于一些非常好的相关信息have a read of this page
编辑: This link should be helpful如果您可以使用Chilkat library
1和2之间有一个复杂的区别,1只能做多达20个字节,MS已经建立了一个允许更多的扩展,下面的代码应该更准确地重新定义.net输出。 Taken from here
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;
}
}
}
答案 1 :(得分:0)
非常感谢您提供的解决方案 - 它运行良好,但有一个小的修正(根据下面的mentioned初稿):
请使用:
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);
}
附加组件: 如果您关心密钥大小限制,您可以使用this solution,它可以正常工作(在Ubuntu 12下测试,Java 1.7 64位(java版本&#34; 1.7.0_25&#34; Java(TM)SE运行时环境(版本1.7.0_25-b15) Java HotSpot(TM)64位服务器VM(版本23.25-b01,混合模式))