【问题标题】:Why is RSA encryption in Java producing different length ciphertext than C#为什么Java中的RSA加密产生的密文长度与C#不同
【发布时间】:2019-07-11 02:30:49
【问题描述】:

我正在 AES 使用随机生成的密钥加密一些文本,然后 RSA 使用私钥加密该密钥,以便我可以将其上传到数据库。

RSA 密钥是使用 Java 中的 KeyPairGenerator 生成的,并保存为文件。使用File.ReadAllBytes() 读入密钥。

当我在 Java 中执行此操作时,一切正常,加密密钥始终为 172 bytes,但当我在 C# 中执行此操作时,加密密钥始终为 844 bytes。我很确定使用AES 正确加密了文本,但RSA 加密出了点问题。

我检查了 Java 和 C# 中的密钥大小,它们总是匹配的。从字面上看,我能看到的唯一区别是 RSA 加密的密文长度,这使得数据无法使用。我相信它与填充有关,但我不知道如何修复它。

Java

public String encryptText(String msg, PrivateKey key) 
            throws NoSuchAlgorithmException, NoSuchPaddingException,
            UnsupportedEncodingException, IllegalBlockSizeException, 
            BadPaddingException, InvalidKeyException {

        KeyGenerator generator;   
        this.cipher.init(Cipher.ENCRYPT_MODE, key); //cipher is initialized earlier with this.cipher = Cipher.getInstance("RSA");

            try {
                generator = KeyGenerator.getInstance(AES);
                generator.init(128); // The AES key size in number of bits
                SecretKey secKey = generator.generateKey();

                Cipher aesCipher = Cipher.getInstance(AES);
                aesCipher.init(Cipher.ENCRYPT_MODE, secKey);

                String encText = Base64.getEncoder().encodeToString(aesCipher.doFinal(msg.getBytes("UTF-8")));
                String encKey = Base64.getEncoder().encodeToString(cipher.doFinal(secKey.getEncoded()));

                return "(" + encText + ")" + encKey;                
            } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        return null;
    }

C#

public String EncryptText(byte[] privateKeyBytes, string msg)
        {
            try
            {
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                RSAParameters RSAKeyInfo = RSA.ExportParameters(false);

                RSAKeyInfo.Modulus = privateKeyBytes;
                RSA.ImportParameters(RSAKeyInfo);

                RijndaelManaged aes = new RijndaelManaged();
                aes.BlockSize = 128;
                aes.KeySize = 128;
                aes.Mode = CipherMode.ECB;
                byte[] keyGenerated = aes.Key;

                string keyStr = Convert.ToBase64String(keyGenerated);
                byte[] keyArr = Convert.FromBase64String(keyStr);
                byte[] KeyArrBytes16Value = new byte[16];
                Array.Copy(keyArr, KeyArrBytes16Value, 16);

                aes.Key = KeyArrBytes16Value;

                ICryptoTransform encrypto = aes.CreateEncryptor();

                byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(msg);
                byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);

                string encText = Convert.ToBase64String(CipherText);
                string encKey = Convert.ToBase64String(RSA.Encrypt(aes.Key, true));

                return "(" + encText + ")" + encKey;

            }
            catch (CryptographicException e)
            {
                Console.WriteLine("FAILED: " + e.Message);
            }

            return null;
        }

更新
感谢 Henno 指出问题在于我如何阅读密钥。我最终使用 Bouncy Castle 来处理 C# 中的 RSA 加密。我还更改了我的 java 代码以使用公钥而不是私钥进行加密。

新的 C#

public String EncryptText(byte[] keyBytes, string msg)
        {
            try
            {
                AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
                RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
                RSAParameters rsaParameters = new RSAParameters();
                rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
                rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.ImportParameters(rsaParameters);

                RijndaelManaged aes = new RijndaelManaged();
                aes.BlockSize = 128;
                aes.KeySize = 128;
                aes.Mode = CipherMode.ECB;
                byte[] keyGenerated = aes.Key;

                string keyStr = Convert.ToBase64String(keyGenerated);
                byte[] keyArr = Convert.FromBase64String(keyStr);
                byte[] KeyArrBytes16Value = new byte[16];
                Array.Copy(keyArr, KeyArrBytes16Value, 16);

                aes.Key = KeyArrBytes16Value;

                ICryptoTransform encrypto = aes.CreateEncryptor();

                byte[] plainTextByte = ASCIIEncoding.UTF8.GetBytes(msg);
                byte[] CipherText = encrypto.TransformFinalBlock(plainTextByte, 0, plainTextByte.Length);

                string encText = Convert.ToBase64String(CipherText);
                string encKey = Convert.ToBase64String(rsa.Encrypt(aes.Key, false));

                return "(" + encText + ")" + encKey;

            }
            catch (CryptographicException e)
            {
                Console.WriteLine("FAILED: " + e.Message);
            }

            return null;
        }

【问题讨论】:

  • 您的问题缺少很多内容。您的代码不可重现 - 它们不会自行编译,因为它们引用了您未向我们展示的内容,例如 Java 中的 RSA 密码。您也没有显示这些加密密钥的外观,这可能会提示出现了什么问题。而且您没有显示会生成该输出的私钥和输入消息。可能有很多事情是错误的,没有一个真实的可重复的例子很难说。见minimal reproducible example
  • 1024 位 RSA 密钥?这将提供 128 字节的加密 RSA 原始数据,因此大致为 172 字节的 base64 编码。
  • RSAKeyInfo.Modulus = privateKeyBytes 在密码学上没有意义?你在那里做什么?

标签: java c# encryption rsa


【解决方案1】:

似乎出了问题的是您在 C# 中读取了保存的“私钥文件”,大概在变量 privateKeyBytes 中(但您的代码不完整,所以我猜)然后执行 RSAKeyInfo.Modulus = privateKeyBytes,这很奇怪,而且在密码学上是不可信的。您还应该根据您读入的字节在 C# 中实例化某种 RSA 类,这就是我认为您在 C# 代码(前四行)开头尝试做的事情。我认为应该有另一个 API,在文档中查看:

RSA.ImportParameters(RSAKeyInfo) 然后可能从这些字节中设置 RSAKeyInfo,但它不是模数。以字节为单位的读取应该是 PKCS1 格式或类似格式,maye base64 编码在文件中,或原始等。您必须查看 Java 使用什么格式将完整密钥导出到磁盘。

您使用从文件中读取的原始字节作为模数,这肯定会带来麻烦并给出一个无效且太大的“密钥”。

【讨论】:

  • 我知道问题与 RSA 部分有关。你猜对了,问题出在我读钥匙的方式上。我最终使用 Bouncy Castle 来处理加密的 RSA 部分。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 2011-02-08
  • 1970-01-01
  • 2020-10-23
  • 1970-01-01
相关资源
最近更新 更多