java - 在 java 中使用 Bouncy CaSTLe 进行 block 式 RSA 加密

标签 java c# cryptography rsa bouncycastle

在 C# 中,我通过执行以下操作来加密文本数据(请注意我正在以 block ( block )的形式加密数据):

        public string EncryptData(string publicKey, string data)
        {
            try
            {
                var bytesToEncrypt = Encoding.UTF8.GetBytes(data);
                int srclen = bytesToEncrypt.Length;

                //Prepare encryption engine
                var encryptEngine = new Pkcs1Encoding(new RsaEngine());

                //Initialize Key
                using (var txtreader = new StringReader(publicKey))
                {
                    var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
                    encryptEngine.Init(true, keyParameter);
                }

                //Encrypt in loop
                byte[] complete = new byte[0];
                int src_block_size = encryptEngine.GetInputBlockSize();
                for (int idx = 0; idx < srclen; idx += src_block_size)
                {
                    int data_len = srclen - idx;
                    if (data_len > src_block_size)
                    {
                        data_len = src_block_size;
                    }

                    var encryptedChunk = encryptEngine.ProcessBlock(bytesToEncrypt, idx, data_len);
                    complete = CombineByteArrays(complete, encryptedChunk);
                }

                var finalString = Convert.ToBase64String(complete);
                return finalString;
            }
            catch (InvalidCipherTextException)
            {
                //catch exception
            }
        }

现在,我需要为某些 java 人员(我一点也不熟悉 java)提供相同的加密逻辑。现在他们是这样做的:

public static byte[] encrypt(byte[] text, PublicKey key) throws Exception
    {
        byte[] cipherText = null;
        //
        // get an RSA cipher object and print the provider
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

        // encrypt the plain text using the public key
        cipher.init(Cipher.ENCRYPT_MODE, key);
        cipherText = cipher.doFinal(text);
        return cipherText;
    }

因此,有时解密(发生在基于 .Net 的服务器上)会失败并出现错误“输入对于 RSA 密码而言太大”。所以我怀疑这可能是因为加密和解密数据的逻辑不同(加密发生在基于 java 的客户端上,逻辑在上面,解密发生在基于 .Net 的客户端上,逻辑如下):

public string DecryptData(string privateKey, string base64Data)
        {
            try
            {
                var bytesToDecrypt = Convert.FromBase64String(base64Data);
                AsymmetricCipherKeyPair keyPair;
                //var internalEngine = new RsaEngine();
                var decryptEngine = new RsaEngine(); //No paddind. We'll hunt the data inside packets
                using (var txtreader = new StringReader(privateKey))
                {
                    keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();
                    decryptEngine.Init(false, keyPair.Private);
                }

                //Loop por todo el bloque y saca data
                byte[] complete = new byte[0];
                int blockSize = decryptEngine.GetInputBlockSize();
                for (int chunkPosition = 0; chunkPosition < bytesToDecrypt.Length; chunkPosition += blockSize)
                {
                    //int chunkSize = Math.Min(blockSize, bytesToDecrypt.Length - ((chunkPosition / blockSize) * blockSize));
                    int chunkSize = bytesToDecrypt.Length - chunkPosition;
                    if (chunkSize > blockSize)
                    {
                        chunkSize = blockSize;
                    }

                    var decryptedChunk = decryptEngine.ProcessBlock(bytesToDecrypt, chunkPosition, chunkSize);

                    //the actual decrypted data is in the middle, locate it!
                    int idxFirstZero = -1;
                    int outlen = decryptedChunk.Length;
                    int idxNextZero = (int)outlen;
                    for (int i = 0; i < outlen; i++)
                    {
                        if (decryptedChunk[i] == 0)
                        {
                            if (idxFirstZero < 0)
                            {
                                idxFirstZero = i;
                            }
                            else
                            {
                                idxNextZero = i;
                                break;
                            }
                        }
                    }

                    var totalSizeToCopy = idxNextZero - idxFirstZero - 1;
                    Array.Resize(ref complete, complete.Length + totalSizeToCopy);
                    int dstOffset = complete.Length - totalSizeToCopy > 0 ? complete.Length - totalSizeToCopy : 0;
                    Buffer.BlockCopy(decryptedChunk, idxFirstZero + 1, complete, dstOffset, totalSizeToCopy);
                }

                var finalString = Encoding.UTF8.GetString(complete).Trim('\0');
                return finalString;
            }
            catch (InvalidCipherTextException)
            {

            }
        }

如您所见,我正在以 block 的形式解密数据。所以我的问题是我们如何在 java 中(使用充气城堡)逐 block 进行加密(就像我在博文的第一个代码片段中在 .Net 中所做的那样)?

最佳答案

这不是一个常见的操作,因为对于大数据(甚至更小的数据)通常使用混合加密,其中使用对称密码的操作模式(例如 CBC)来加密更大的数据对象。

据我所知,没有直接的方法可以从 Cipher 实例请求 RSA/PKCS#1 的最大输入大小。

但是,这不是什么大问题,因为您可以根据 RSA key 大小自行计算。并且此 key 大小与模数的大小(以字节为单位)相同:

  1. 以字节为单位计算模数大小:(keysize - 1)/Byte.SIZE + 1 或者,如果 keysize 是 8 的倍数(像往常一样),只需 keysize/Byte .SIZE 当然是;
  2. 从结果中减去 11 个字节(对于 PKCS#1 v1.5 填充);

要获取 key 大小,只需将您的 key 转换为 RSAPublicKey,然后调用 getModulus(),然后调用 bitLength()结果 BigInteger


请注意,发送没有完整性保护(例如签名)的密文被认为不是很安全。 PKCS#1 也可能成为填充 oracle 攻击的受害者,尤其是在传输模式安全性中使用时。 RSA/OAEP 将是更好的选择,用于混合加密(如 RSA/OAEP will store even less )。

关于java - 在 java 中使用 Bouncy CaSTLe 进行 block 式 RSA 加密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43798966/

相关文章:

c# - 字符串上的自定义大写

javascript - 验证 Mandrill 的 X-Mandrill 签名

java - 需要帮助整理这个运动功能

java - 如何使用 BigInteger 加密字符串?

c# - 维护多个设置文件

c++ - x86 中是否有任何指令可以加速 SHA (SHA1/2/256/512) 编码?

ios - 使用 Objective-C 的 AES Java 加密 16 字节 key 解密

java - swing 中的 JLabel 数组

java - EasyMock 中未找到 Mock 功能

c# - 创建 C# Winform 开发和生产环境