需要帮助将C#加密方法转换为Java

时间:2019-04-29 10:40:03

标签: java c# encryption

我正在尝试将现有的C#加密方法转换为Java,但遇到了如下障碍

例如,当我使用C#加密基本字符串“ 12345”时,我得到此输出 8ZQZEUrctqP1PMmQxVtCcA ==

当我用java加密相同的字符串时,我得到了 jkEZp2cfeGXVE / IxIW6X3g ==

private static string Encrypt(string plainText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations,
                        string initVector, int keySize)
{
    try
    {
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);
        byte[] keyBytes = password.GetBytes(keySize / 8);
        RijndaelManaged symmetricKey = new RijndaelManaged { 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;
    }
    catch (Exception execp)
    {
        MessageBox.Show(string.Format("Exception in Encrypt function\r\nError: {0}", execp.Message));
        return "";
    }
}

private static string Decrypt(string cipherText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations,
                                string initVector, int keySize)
{
    try
    {
        if (cipherText == string.Empty)
            return "";

        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
        PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);
        byte[] keyBytes = password.GetBytes(keySize / 8);
        RijndaelManaged symmetricKey = new RijndaelManaged { Mode = CipherMode.CBC };
        ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
        MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
        CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
        byte[] plainTextBytes = new byte[cipherTextBytes.Length];
        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
        memoryStream.Close();
        cryptoStream.Close();
        string plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
        return plainText;
    }
    catch (Exception execp)
    {
        MessageBox.Show(string.Format("Exception in Decrypt function\r\nError: {0}", execp.Message));
        return "";
    }
}

public static string ProtectPassword(string plainText)
{
    try
    {
        const string passPhrase = "Ydfv324232r!23%47%7^&ex>,1"; // can be any string
        const string saltValue = "s@1tValue"; // can be any string
        const string hashAlgorithm = "SHA1"; // can be "MD5"
        const int passwordIterations = 101; // can be any number
        const string initVector = "@1B2vQ94eZF6g7H1"; // must be 16 bytes
        const int keySize = 256; // can be 192 or 128

        string ret = Encrypt(plainText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);

        return ret;
    }
    catch (Exception execp)
    {
        MessageBox.Show(string.Format("Exception in ProtectPassword function\r\nError: {0}", execp.Message));
        return "";
    }
}

public static string UnprotectPassword(string cipherText)
{
    try
    {
        const string passPhrase = "Ydfv324232r!23%47%7^&ex>,1"; // can be any string
        const string saltValue = "s@1tValue"; // can be any string
        const string hashAlgorithm = "SHA1"; // can be "MD5"
        const int passwordIterations = 101; // can be any number
        const string initVector = "@1B2vQ94eZF6g7H1"; // must be 16 bytes
        const int keySize = 256; // can be 192 or 128

        string ret = Decrypt(cipherText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);

        return ret;
    }
    catch (Exception execp)
    {
        MessageBox.Show(string.Format("Exception in UnprotectPassword function\r\nError: {0}", execp.Message));
        return "";
    }
}

以下是我已转换为java的内容,但仍未获得相同的加密输入和输出-我只是将“ ProtectPassword”重命名为“ Encrypt”,将“ UnprotectPassword”重命名为“ Decrypt”

import java.io.ByteArrayOutputStream;
import java.security.SecureRandom;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
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.xml.bind.DatatypeConverter;

public class Encryption {

    public static String Encrypt(String str)
    {
        try 
        {
            String passPhrase = "Ydfv324232r!23%47%7^&ex>,1";
            String saltValue = "s@1tValue";
            int passwordIterations = 101;
            int keySize = 256;
            String initVector = "@1B2vQ94eZF6g7H1";

            SecureRandom random = new SecureRandom();
            byte[] salt = new byte[16];
            random.nextBytes(salt);

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec spec = new PBEKeySpec(passPhrase.toCharArray(), saltValue.getBytes("UTF-8"), passwordIterations, keySize);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(initVector.getBytes("UTF-8")));            
            byte[] encryptedText = cipher.doFinal(str.getBytes("UTF-8"));

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();           
            outputStream.write(encryptedText);

            // properly encode the complete cipher text
            return DatatypeConverter.printBase64Binary(outputStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }   

    public static String Decrypt(String str)
    {
        try 
        {
            String passPhrase = "Ydfv324232r!23%47%7^&ex>,1";
            String saltValue = "s@1tValue";
            int passwordIterations = 101;
            int keySize = 256;
            String initVector = "@1B2vQ94eZF6g7H1";

            byte[] ciphertext = DatatypeConverter.parseBase64Binary(str);           

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec spec = new PBEKeySpec(passPhrase.toCharArray(), saltValue.getBytes(), passwordIterations, keySize);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

            cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(initVector.getBytes("UTF-8")));
            byte[] plaintext = cipher.doFinal(ciphertext);

            return new String(plaintext, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

2 个答案:

答案 0 :(得分:0)

密文不同,因为C#代码中的PasswordDeriveBytes和Java代码中的PBKDF2WithHmacSHA1生成不同的密钥:

除了C#类型的PasswordDeriveBytes,还有C#类型的Rfc2898DeriveBytes,它是具有SHA-1的PBKDF2的实现,因此,与PBKDF2WithHmacSHA1中的对等物Java代码。

如果可能,应在C#代码中使用Rfc2898DeriveBytes而不是PasswordDeriveBytes,请参见例如herehere PBKDF2 部分。然后两个代码返回相同的密文。

据我所知,没有提供者提供C#类型PasswordDeriveBytes的Java实现。但是,互联网上有功能上相同的Java实现,例如here。如果Java代码使用这样的实现而不是PBKDF2WithHmacSHA1,则两个代码都返回相同的密文。但是,正如已经提到的,这应该是第二选择。

答案 1 :(得分:0)

下面承诺的是解决方案-再次感谢您的支持

public static class Encryption
{
    public static string Encrypt(string text)
    {
        var thePassword = "%cFRm*F)N9Rq[6#5";
        byte[] IV = Encoding.UTF8.GetBytes("7!,V5u]Bu>q>7zY'");

        var md5 = new MD5CryptoServiceProvider();
        var password = md5.ComputeHash(Encoding.ASCII.GetBytes(thePassword));
        var cipher = new RijndaelManaged();            
        var encryptor = cipher.CreateEncryptor(password, IV);

        var buffer = Encoding.ASCII.GetBytes(text);
        return Convert.ToBase64String(encryptor.TransformFinalBlock(buffer, 0, buffer.Length));
    }

    public static string Decrypt(string text)
    {
        var thePassword = "%cFRm*F)N9Rq[6#5";
        byte[] IV = Encoding.UTF8.GetBytes("7!,V5u]Bu>q>7zY'");

        var md5 = new MD5CryptoServiceProvider();
        var password = md5.ComputeHash(Encoding.ASCII.GetBytes(thePassword));
        var cipher = new RijndaelManaged();
        var decryptor = cipher.CreateDecryptor(password, IV);

        byte[] input = Convert.FromBase64String(text);
        var newClearData = decryptor.TransformFinalBlock(input, 0, input.Length);
        return Encoding.ASCII.GetString(newClearData);
    }
}

与Java等效

public class Encryption {

    public static String Encrypt(String str)
    {
        try 
        {
            String thePassword = "%cFRm*F)N9Rq[6#5";
            byte[] encryptedData;
            byte[] IV = "7!,V5u]Bu>q>7zY'".getBytes();

            MessageDigest digest = MessageDigest.getInstance("MD5");            
            SecretKeySpec password = new SecretKeySpec(digest.digest(thePassword.getBytes()), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec IVParamSpec = new IvParameterSpec(IV);
            cipher.init(Cipher.ENCRYPT_MODE, password, IVParamSpec);
            encryptedData = cipher.doFinal(str.getBytes());

            return DatatypeConverter.printBase64Binary(encryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }   

    public static String Decrypt(String str)
    {
        try 
        {
            String thePassword = "%cFRm*F)N9Rq[6#5";
            byte[] encryptedData = DatatypeConverter.parseBase64Binary(str); 
            byte[] IV = "7!,V5u]Bu>q>7zY'".getBytes();

            MessageDigest digest = MessageDigest.getInstance("MD5");            
            SecretKeySpec password = new SecretKeySpec(digest.digest(thePassword.getBytes()), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec IVParamSpec = new IvParameterSpec(IV);
            cipher.init(Cipher.DECRYPT_MODE, password, IVParamSpec);

            byte[] decryptedVal = cipher.doFinal(encryptedData);
            return new String(decryptedVal); 
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}