c# - Java加密和C#解密问题

标签 c# java encryption-symmetric

我在 C# 中有一个加密和解密字符串文本的 DLL(一些基本的东西),但现在我需要在 Java 中实现相同的加密方法,以便某些应用程序可以加密数据并将其发送到库。

我无法修改 C# 代码,因为它已经在生产中,但 Java 没有,所以请务必在 Java 端提出任何建议。

基本上,我试图在 Java 中实现相同的 C# 加密方法。这是我的 C# 代码:

注意:密码、salt 等值显然只是引用。

    const string PassPhrase = "IhDyHz6bgQyS0Ff1/1s="; 
    const string SaltValue = "0A0Qvv09OXd3GsYHVrA=";   
    const string HashAlgorithm = "SHA1";                
    const int PasswordIterations = 3;                 
    const string InitVector = "GjrlRZ6INgNckBqv";      
    const int KeySize = 256;


public static string Encrypt(string plainText)
    {

        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();


        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;
    }


public static string Decrypt(string cipherText)
    {

        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();


        symmetricKey.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;
    }

这是我的 java 代码,它加密数据,但与 C# 加密代码的方式不同,所以当我尝试使用 C# 库解密它时,它抛出异常:“要解密的数据的长度是无效”

    static final String PassPhrase = "IhDyHz6bgQyS0Ff1/1s=";   
    static final String SaltValue = "0A0Qvv09OXd3GsYHVrA=";    
    static final String HashAlgorithm = "SHA1";               
    static final int PasswordIterations = 3;                   
    static final String InitVector = "GjrlRZ6INgNckBqv";       
    static final int KeySize = 256;

public static String encrypt(String plainText)
{
    char[] password = PassPhrase.toCharArray();
    byte[] salt = SaltValue.getBytes();
    byte[] iv = InitVector.getBytes();
    byte[] ciphertext = new byte[0];

    SecretKeyFactory factory;
    try {
        factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

        KeySpec spec = new PBEKeySpec(password, salt, PasswordIterations, 256);
        SecretKey tmp;

        tmp = factory.generateSecret(spec);

        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = cipher.getParameters();
        //iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        ciphertext = cipher.doFinal(plainText.getBytes("UTF-8"));

    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 
    //catch (InvalidParameterSpecException e) {
    //  // TODO Auto-generated catch block
    //  e.printStackTrace();
    //} 
    catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return Base64.encode(new String(ciphertext));
}

编辑 1:我按照 Jon Skeet 的建议修复了 Java 代码中最终字节数组到 String 的转换。

最佳答案

这是 Java 代码中的错误:

return Base64.encode(ciphertext.toString());

您在字节数组上调用 toString(),它总是给出一个字符串,例如 [B@3e25a5

编辑:哦,刚刚注意到您可以更改 Java 端。万岁。

基本上,您需要使用 Base64 API,它允许:

return Base64.encode(ciphertext);

老实说,允许您“编码”字符串的 Base64 API 总是让我感到失望……base64 从根本上将二进制数据编码为文本,并将文本数据解码为二进制。好吧……

无论如何,使用this API (encodeBytes 方法)如果您需要一个允许您传入字节数组的方法。

我没有详细检查实际的加密部分,但至少 C# 代码看起来在编码方面做得对。它可以用 using 语句来完成 :)

关于c# - Java加密和C#解密问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7730741/

相关文章:

c# - 从另一个项目加载文件

java - Logback - 根据大小滚动文件

security - 防止对服务器的 MITM 攻击

java - 在 java 中创建样式 xml 以供查看(按钮)

ssl - 对称加密 key 与非对称 key - ssl

java - Derby/JavaDB _真的_可以使用 Triple DES 而不是(普通的)DES 进行加密吗?

c# - 当我在 Debug模式下进入和设置函数时,程序运行不同

c# - 如何在 Hololens 应用程序中调用默认浏览器

c# - 解压缩 deflate64

java - 解析器-如何读取文件?