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

时间:2014-01-31 12:33:25

标签: c# java encryption aes md5

我的.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==

请你帮我解决这个问题吗?

2 个答案:

答案 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,混合模式))