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

如何在Java中对大数据进行RSA加密和解密

严景焕
2023-03-14

我正在尝试使用RSA和OAEPPadding对实际更大的数据(比如10 KB)执行非对称加密和解密。

许多Stackoverflow文章提到使用混合方法[不对称对称],但我并不是在寻找这种方法。我故意要求非对称加密。

我初始化加密和解密密码如下:

mDecryptCipher = Cipher.getInstance("RSA/None/OAEPPadding", new BouncyCastleProvider());
mDecryptCipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
Log.d(TAG, "Decrypt Cipher is successfully created");

mEncryptCipher = Cipher.getInstance("RSA/None/OAEPPadding", new BouncyCastleProvider());
mEncryptCipher.init(Cipher.ENCRYPT_MODE, mPublicKey);
Log.d(TAG, "Encrypt Cipher is successfully created");

下面是我试图加密或解密大小为10 KB的大数据的代码。

// Encrypt
byte[] encryptedPayload = mEncryptCipher.doFinal(payload);

// Decrypt
byte[] decryptedPayload = mDecryptCipher.doFinal(payload);

以下是我收到的例外情况:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block
    at org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(Unknown Source)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)

请告诉我如何对大数据执行RSA加密和解密。

共有1个答案

卫弘懿
2023-03-14

Java Cipher对象允许我们检索块大小,并使用它执行重复的加密和解密,这将使我们克服“RSA块数据过多”的例外。

以下是加密的逻辑:

public byte[] encrypt(String data) {
    Log.d(TAG, "Encryption begins");
    byte[] payload = data.getBytes(StandardCharsets.UTF_8);
    int payloadLength = payload.length;
    int blockSize = mEncryptCipher.getBlockSize();
    Log.d(TAG, "blockSize: " + blockSize + "; payloadLength: " + payloadLength);

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    int start = 0, end = 0;
    while (end < payloadLength) {
        end = end + blockSize;
        if (end > payloadLength) {
            end = payloadLength;
        }
        Log.d(TAG, "start: " + start + "; end: " + end + "; block: " + (end - start));
        try {
            byte[] encryptedSlice = mEncryptCipher.doFinal(payload, start, (end - start));
            Log.d(TAG, "Encrypted Slice Length: " + encryptedSlice.length);
            stream.write(encryptedSlice);
            start = end;
        } catch (IOException | BadPaddingException | IllegalBlockSizeException e) {
            Log.e(TAG, "update failed");
            e.printStackTrace();
            break;
        }
    }
    byte[] encryptedPayload = stream.toByteArray();
    try {
        stream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    Log.d(TAG, "encryptedPayload length: " + encryptedPayload.length);
    byte[] base64EncryptedPayload = org.apache.commons.codec.binary.Base64.encodeBase64(encryptedPayload);
    Log.d(TAG, "base64EncryptedPayload length: " + base64EncryptedPayload.length);
    Log.d(TAG, "Encryption ends");
    return base64EncryptedPayload;
}

以下是解密的逻辑:

public String decrypt(byte[] base64EncodedData) {
    Log.d(TAG, "Decryption begins");
    Log.d(TAG, "base64EncodedData length: " + base64EncodedData.length);
    byte[] encryptedData = org.apache.commons.codec.binary.Base64.decodeBase64(base64EncodedData);
    Log.d(TAG, "encryptedData length: " + encryptedData.length);

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    int payloadLength = encryptedData.length;
    int blockSize = mDecryptCipher.getBlockSize();
    int start = 0, end = 0;
    while (start < payloadLength) {
        end = end + blockSize;
        if (end > payloadLength) {
            end = payloadLength;
        }

        Log.d(TAG, "start: " + start + "; end: " + end + "; block: " + (end - start));
        try {
            byte[] decryptedBlockData = mDecryptCipher.doFinal(encryptedData, start, (end - start));
            Log.d(TAG, "decryptedBlockData Length: " + decryptedBlockData.length);
            stream.write(decryptedBlockData);
            start = end;
        } catch (BadPaddingException | IllegalBlockSizeException | IOException e) {
            Log.e(TAG, "Slicing failed");
            e.printStackTrace();
            break;
        }
    }
    String payload = stream.toString();
    try {
        stream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    Log.d(TAG, "Decryption ends");
    return payload;
}

请注意,在我的情况下,以下是Cipher对象的详细信息:

加密密码:

getBlockSize: 470
getAlgorithm: RSA/None/OAEPPadding
getProvider Name: BC
getProvider Info: BouncyCastle Security Provider v1.70

解密密码:

getBlockSize: 512
getAlgorithm: RSA/None/OAEPPadding
getProvider Name: BC
getProvider Info: BouncyCastle Security Provider v1.70

我也愿意接受任何更好的解决方案。

 类似资料:
  • 问题内容: 我想生成rsa密钥对(公共和私有),然后将它们用于AES加密和解密。例如,用于加密的公共密钥和用于解密的私有密钥。我为此编写了一个简单的代码,但是问题是当我运行时这段代码我得到这个错误: 我该如何解决这个问题?我的加密代码如下: 问题答案: 如评论中所建议,我搜索了“混合密码术”。这个例子解决了我的问题。

  • 问题内容: 我已经编写了服务器,并在中编写了客户端。他们的工作是将秘密消息从服务器发送到客户端,并使用进行加密。我正在使用库,也就是说,我使用私钥初始化对象,并使用加密消息。然后,我将此加密的消息发送到服务器,并尝试使用库 使用相同的私钥对其 进行 解密。问题是它无法正确解密。它总是输出128位长的消息,其中秘密消息被随机放置在其中,通常应返回just 。 问题答案: 问题是关于填充。Python

  • 我用RSA加密来加密C#中的一些数据。现在我想用Java解密加密的数据。但是我遇到了一些问题。 主要问题可能是将加密消息从c#获取到java。在c#中,我们有无符号字节,字节序是不同的 因此,为了进行测试,我将c#中加密数据的数组转换为数组并获得它的字符串表示形式。然后我将字节数组的字符串表示形式复制到我的java代码中并将其转换回“字节”数组。之后,我反转数组以匹配java的endianess。

  • 问题内容: 我需要用openssl生成的和密钥替换从Unix到Java代码的加密和解密步骤 我生成密钥 我在Unix中使用键(我需要在Java中执行) 这是我的尝试 但它不起作用,PKCS8EncodedKeySpec / X509EncodedKeySpec不正确…但是我不知道该放什么 问题答案: 我认为您在读取PEM文件时遇到问题。JPA不直接支持PEM格式。您有两种选择,要么将它们转换为DE

  • 文件解密后,输出包含一些不相关的额外值。为什么结果中有额外的数据?