当前位置: 首页 > 知识库问答 >
问题:

用java加密,用C#解密AES 256位

端木桐
2023-03-14

1.我有java函数,它加密xml文件并返回加密的字符串。

/// Java Class 
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class Crypt {

    public static String key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    public static byte[] key_Array = Base64.decodeBase64(key);

    public static String encrypt(String strToEncrypt)
    {       
        try
        {   
            //Cipher _Cipher = Cipher.getInstance("AES");
            //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            //Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");      

            Key SecretKey = new SecretKeySpec(key_Array, "AES");

            Cipher _Cipher = Cipher.getInstance("AES");     
            _Cipher.init(Cipher.ENCRYPT_MODE, SecretKey);       

            return Base64.encodeBase64String(_Cipher.doFinal(strToEncrypt.getBytes()));     
        }
        catch (Exception e)
        {
            System.out.println("[Exception]:"+e.getMessage());
        }
        return null;
    }

    public static void main(String[] args) {        
        StringBuilder sb = new StringBuilder();
        sb.append("xml file string ...");

        String EncryptedString = encrypt(sb.toString());        
        System.out.println("[EncryptedString]:"+EncryptedString);
    }
}

2.我有c#函数,它可以解密由java函数加密的消息。

/// C# Function
private static string Decrypt(string encryptedText)
{
    RijndaelManaged aesEncryption = new RijndaelManaged();            
    aesEncryption.BlockSize = 256;
    //aesEncryption.KeySize = 256;
    //aesEncryption.Mode = CipherMode.CBC;
    //aesEncryption.Padding = PaddingMode.PKCS7;

    string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    //string ivStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";        

    byte[] keyArr = Convert.FromBase64String(keyStr);
    //byte[] ivArr = Convert.FromBase64String(ivStr);

    aesEncryption.Key = keyArr;
    //aesEncryption.IV = ivArr;

    ICryptoTransform decrypto = aesEncryption.CreateDecryptor();

    byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length);  
    byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); /// CryptographicException: Length of the data to decrypt is invalid.    
    return ASCIIEncoding.UTF8.GetString(decryptedData); 
}

Java加密功能运行良好。但问题是C函数,
当我解密时,会得到下面的错误消息

CryptographicException: Length of the data to decrypt is invalid.

我使用下面的参考搜索解决方案

  1. Java中的AES加密和C#中的解密
  2. C#/Java|AES256加密/解密
  3. C#和Java中的加密/解密

但我仍然面临同样的错误。谁能给我提个建议吗。

我只是改变我的C#加密功能。下面是我的更改列表

  1. 块大小到128
  2. 密钥大小为256
  3. IV尺寸至16
  4. 键大小到32
/// Updated decrypt function
private static string Decrypt(string encryptedText)
{
    RijndaelManaged aesEncryption = new RijndaelManaged();            
    aesEncryption.BlockSize = 128;
    aesEncryption.KeySize = 256;

    //aesEncryption.Mode = CipherMode.CBC;
    aesEncryption.Padding = PaddingMode.None;

    string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    string ivStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";           

    byte[] ivArr = Convert.FromBase64String(ivStr);
    byte[] IVkey16BytesValue = new byte[16];
    Array.Copy(ivArr, IVkey16BytesValue, 16);

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArr32BytesValue = new byte[32];
    Array.Copy(keyArr, KeyArr32BytesValue, 32);

    aesEncryption.IV = IVkey16BytesValue;
    aesEncryption.Key = KeyArr32BytesValue; 

    ICryptoTransform decrypto = aesEncryption.CreateDecryptor();

    byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length);
    byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); 
    return ASCIIEncoding.UTF8.GetString(decryptedData);
}

在这段时间内,没有发生错误。但我得到解密的消息,我无法阅读。

g:�\0�\td��Y\\符O����\rL��W�wHm�>f�\au����%��0��\ ..........

请让我再听听你的建议。

共有3个答案

汤兴生
2023-03-14

在我最近的一个项目中,我的任务是建立一个带有加密部分的url,以传递到另一个网站。他们在服务器上运行java,而我们是用c#开发的。

我知道这与您的任务不完全相符,但希望这能帮助其他试图找到答案的人:)

我从他们的开发人员那里收到了以下内容,用于构建我们的加密

为了在c#中实现这一点,我做了以下操作:

    public String Encrypt(String plainText, String key)
    {
        var plainBytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(Encrypt(plainBytes, GetRijndaelManaged(key)));
    }

    private RijndaelManaged GetRijndaelManaged(String secretKey)
    {
        var keyBytes = new byte[16];
        var secretKeyBytes = Encoding.ASCII.GetBytes(secretKey);
        Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));
        return new RijndaelManaged
        {
            Mode = CipherMode.ECB,
            Padding = PaddingMode.PKCS7,
            KeySize = 128,
            BlockSize = 128,
            Key = keyBytes,
            IV = keyBytes

        };
    }

    private byte[] Encrypt(byte[] plainBytes, RijndaelManaged rijndaelManaged)
    {
        return rijndaelManaged.CreateEncryptor()
            .TransformFinalBlock(plainBytes, 0, plainBytes.Length);
    }
宓和同
2023-03-14

我认为块大小应该是128,键大小应该是256。keyStr应该是32个字符长,IVStr应该是16个字符长。这可能会有所帮助,因为它描述了为什么128位必须用于块大小以及密钥大小可以是什么。csrc.nist.gov/publications/fips/fips197/fips-197.pdf

你在解密方法中有这个。

    aesEncryption.Padding = PaddingMode.None; 

我相信你也需要把它放在加密方法中。

还有,为什么不将此方法用于键和IV。

    aes.Key = ASCIIEncoding.ASCII.GetBytes(keyStr); 
    aes.IV = ASCIIEncoding.ASCII.GetBytes(ivStr);
寿卜鹰
2023-03-14

当我从@deathismyfriend和其他人那里得到非常有用的建议后,我发现了我在C#Decrypt函数中缺少的内容。所以我改变我的函数如下。

/// C# Error Fixed Version - CipherMode.ECB
public static string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

private static string Encrypt(string PlainText)
{
    RijndaelManaged aes = new RijndaelManaged();
    aes.BlockSize = 128;
    aes.KeySize = 256;

    /// In Java, Same with below code
    /// Cipher _Cipher = Cipher.getInstance("AES");  // Java Code
    aes.Mode = CipherMode.ECB; 

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArrBytes32Value = new byte[32];
    Array.Copy(keyArr, KeyArrBytes32Value, 32);

    aes.Key = KeyArrBytes32Value;

    ICryptoTransform encrypto = aes.CreateEncryptor();

    byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(PlainText);
    byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
    return Convert.ToBase64String(CipherText);
}

private static string Decrypt(string CipherText)
{  
    RijndaelManaged aes = new RijndaelManaged();
    aes.BlockSize = 128;
    aes.KeySize = 256;

    /// In Java, Same with below code
    /// Cipher _Cipher = Cipher.getInstance("AES");  // Java Code
    aes.Mode = CipherMode.ECB;

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArrBytes32Value = new byte[32];
    Array.Copy(keyArr, KeyArrBytes32Value, 32);

    aes.Key = KeyArrBytes32Value;

    ICryptoTransform decrypto = aes.CreateDecryptor();

    byte[] encryptedBytes = Convert.FromBase64CharArray(CipherText.ToCharArray(), 0, CipherText.Length);
    byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
    return ASCIIEncoding.UTF8.GetString(decryptedData);
}

通过使用上c#函数,现在我可以解密和读取密码文本<下面是我一次又一次出错后发现的情况

CryptographicException: Padding is invalid and cannot be removed.

 Solution:  
_RijndaelManaged.Padding = CipherMode.xxx;    ///should toggle here
_RijndaelManaged.Padding = PaddingMode.xxx;   ///should toggle here 


CryptographicException: Length of the data to decrypt is invalid. 
CryptographicException: Specified initialization vector (IV) does not match the block size for this algorithm.

Solution
1. _RijndaelManaged.BlockSize = 128; /// Must be
2. _RijndaelManaged.KeySize = 256; /// Must be
3. _RijndaelManaged.Key = Byte Array Size must be 32 in length ( more detail 32*8 = 256 KeySize )
4. _RijndaelManaged.IV = Byte Array Size must be 16 in length ( more detail 16*8 = 128 BlockSize)

但是当涉及到安全原因时,我认为我不应该使用欧洲央行模式。根据

  1. ECB模式不安全
  2. 堆栈溢出链路

所以我用Java和C再次修改了它。

// Java code - Cipher mode CBC version.
// CBC version need Initialization vector IV.
// Reference from https://stackoverflow.com/questions/6669181/why-does-my-aes-encryption-throws-an-invalidkeyexception/6669812#6669812

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class CryptoSecurity {

    public static String key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    public static byte[] key_Array = Base64.decodeBase64(key);

    public static String encrypt(String strToEncrypt)
    {       
        try
        {   
            //Cipher _Cipher = Cipher.getInstance("AES");
            //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");        

            // Initialization vector.   
            // It could be any value or generated using a random number generator.
            byte[] iv = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 };
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            Key SecretKey = new SecretKeySpec(key_Array, "AES");    
            _Cipher.init(Cipher.ENCRYPT_MODE, SecretKey, ivspec);       

            return Base64.encodeBase64String(_Cipher.doFinal(strToEncrypt.getBytes()));     
        }
        catch (Exception e)
        {
            System.out.println("[Exception]:"+e.getMessage());
        }
        return null;
    }

    public static String decrypt(String EncryptedMessage)
    {
        try
        {
            //Cipher _Cipher = Cipher.getInstance("AES");
            //Cipher _Cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");            

            // Initialization vector.   
            // It could be any value or generated using a random number generator.
            byte[] iv = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 };
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            Key SecretKey = new SecretKeySpec(key_Array, "AES");
            _Cipher.init(Cipher.DECRYPT_MODE, SecretKey, ivspec);           

            byte DecodedMessage[] = Base64.decodeBase64(EncryptedMessage);
            return new String(_Cipher.doFinal(DecodedMessage));

        }
        catch (Exception e)
        {
            System.out.println("[Exception]:"+e.getMessage());          

        }
        return null;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        StringBuilder sb = new StringBuilder();

        sb.append("xml file string ...");

        String outputOfEncrypt = encrypt(sb.toString());        
        System.out.println("[CryptoSecurity.outputOfEncrypt]:"+outputOfEncrypt);

        String outputOfDecrypt = decrypt(outputOfEncrypt);        
        //String outputOfDecrypt = decrypt(sb.toString());        
        System.out.println("[CryptoSecurity.outputOfDecrypt]:"+outputOfDecrypt);
    }

}

在C#中,我对其进行如下修改。

// C# Code, CipherMode.CBC
// CBC version need Initialization vector IV.

public static string keyStr = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
private static string Encrypt(string PlainText)
{
    RijndaelManaged aes = new RijndaelManaged();
    aes.BlockSize = 128;
    aes.KeySize = 256;

    // It is equal in java 
    /// Cipher _Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");    
    aes.Mode = CipherMode.CBC;  
    aes.Padding = PaddingMode.PKCS7; 

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArrBytes32Value = new byte[32];
    Array.Copy(keyArr, KeyArrBytes32Value, 32);

    // Initialization vector.   
    // It could be any value or generated using a random number generator.
    byte[] ivArr = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 };
    byte[] IVBytes16Value = new byte[16];
    Array.Copy(ivArr, IVBytes16Value, 16);

    aes.Key = KeyArrBytes32Value;
    aes.IV = IVBytes16Value;

    ICryptoTransform encrypto = aes.CreateEncryptor();

    byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(PlainText);
    byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);
    return Convert.ToBase64String(CipherText);

}

private static string Decrypt(string CipherText)
{
    RijndaelManaged aes = new RijndaelManaged();
    aes.BlockSize = 128;
    aes.KeySize = 256;

    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7;

    byte[] keyArr = Convert.FromBase64String(keyStr);
    byte[] KeyArrBytes32Value = new byte[32];
    Array.Copy(keyArr, KeyArrBytes32Value, 32);

    // Initialization vector.   
    // It could be any value or generated using a random number generator.
    byte[] ivArr = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1, 7, 7, 7, 7 };            
    byte[] IVBytes16Value = new byte[16];
    Array.Copy(ivArr, IVBytes16Value, 16);

    aes.Key = KeyArrBytes32Value;
    aes.IV = IVBytes16Value;

    ICryptoTransform decrypto = aes.CreateDecryptor();

    byte[] encryptedBytes = Convert.FromBase64CharArray(CipherText.ToCharArray(), 0, CipherText.Length);
    byte[] decryptedData = decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
    return ASCIIEncoding.UTF8.GetString(decryptedData);
}

现在一切都好了
有关AES的更多详细信息,请单击@deathismyfriend提供的此链接<它也非常有用。

 类似资料:
  • 问题内容: 1.我有java函数来加密xml文件并返回加密的字符串。 2.我有c#函数可以解密通过java函数加密的消息。 Java加密功能运行良好。但是问题是C#函数, 当我解密时出现以下错误消息 我通过使用下面的参考来搜索解决方案 Java中的AES加密和C#中的解密 C#/ Java | AES256加密/解密 C#和Java中的加密/解密 但我仍然遇到同样的错误。有人可以给我建议吗? 更新

  • 我将AES与salt和IV一起用于加密和解密一个唯一的ID,但它给出了javax。加密。解密时出现BadPaddingException。 每次解密数据时给出的完整错误堆栈跟踪 加密方法- 解密方法 我是JCA的新手。

  • 我试图解密C#加密数据在Java没有成功。我用的是128位密钥 这是java代码: 你知道会出什么问题吗? 谢谢 使现代化 对不起,我太笨了,我忘了写实际的错误消息。这是: 线程“main”javax中出现异常。加密。BadPaddingException:组织中的填充块已损坏。弹跳船舱。jcajce。供应商。对称的。util。基本分组密码。javax上的engineDoFinal(未知源代码)。

  • 问题内容: 我想将加密的密码存储在Java文件中。我在使用 javax.crypto 的解决方案中看到了一个问题,但是问题在于密钥是动态生成的,并且是随机的。 然后将在运行时在Java程序中获取并解密该密码。鉴于我要在文件中存储一个已经加密的密码-解密时我想要正确的文本。 有没有办法告诉javax.crypto方法: 可以将其替换为基于某个私钥生成的我自己的密钥吗? 谁能指出一些有关执行此操作的资

  • 问题内容: 我想用Java加密和解密密码,然后以加密形式存储到数据库中。如果它是开源的,那就太好了。有什么建议/建议吗? 问题答案: 编辑 :这个答案是旧的。现在 不建议 使用MD5,因为它很容易被破坏。 我想象中的MD5必须足够好?您可以使用MessageDigest实现它。 这里还列出了其他算法。 如果确实需要,这是它的第三方版本: Fast MD5

  • 问题内容: 我尝试解密最初使用Java中的Objective-C加密的数据。 还有其他问题要提及,但是它们确实很混乱,许多问题还没有解决,因此我将发表自己的问题。 这是加密数据的代码: 我执行此功能,并使用以下代码将结果数据写入光盘: 在Java中,我使用以下代码来尝试实现相同的行为: 如果现在尝试解密通过Objective-C加密的文件,则会收到错误的填充异常。如果我打开两个带有加密内容的文件,