如何修复javax.crypto.IllegalBlockSizeException:android中的输入必须小于64个字节?

时间:2017-11-29 22:58:38

标签: java android encryption rsa

我有一个连接到服务器的android消息传递应用程序。应用和服务器通过"数据包"进行通信。这些数据包是通过hybrid encryption加密的反序列化对象。出于某种原因,我在尝试加密数据时遇到以下错误:

W/System.err: javax.crypto.IllegalBlockSizeException: input must be under 64 bytes
W/System.err:     at com.android.org.conscrypt.OpenSSLCipherRSA.engineDoFinal(OpenSSLCipherRSA.java:245)
W/System.err:     at javax.crypto.Cipher.doFinal(Cipher.java:1204)
W/System.err:     at javax.crypto.SealedObject.<init>(SealedObject.java:103)
W/System.err:     at com.baiocchi.enigma.client.util.encryption.EncryptionOutputStream.writeObject(EncryptionOutputStream.java:35)
W/System.err:     at com.baiocchi.enigma.client.util.CredentialInflator.deflateCredentials(CredentialInflator.java:31)
W/System.err:     at com.baiocchi.enigma.shared.packet.Packet.encryptCredentials(Packet.java:55)
W/System.err:     at com.baiocchi.enigma.client.util.handlers.PacketDeflationHandler.run(PacketDeflationHandler.java:34)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
W/System.err:     at java.lang.Thread.run(Thread.java:841)

我没有想法,也没有网上答案。请帮忙! 以下是使用的方法:

加密器:

public class Encryptor {


    public static byte[] encrypt(byte[] data, RSAKey asymmetricKey) {
        if (asymmetricKey instanceof RSAPublicKey) {
            return encrypt(data, (RSAPublicKey) asymmetricKey);
        }
        return encrypt(data, (RSAPrivateKey) asymmetricKey);
    }

    private static byte[] encrypt(byte[] data, RSAPublicKey asymmetricKey) {
        try {
            final Cipher cipher = Cipher.getInstance(Config.ASYMMETRIC_TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, asymmetricKey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static byte[] encrypt(byte[] data, RSAPrivateKey asymmetricKey) {
        try {
            final Cipher cipher = Cipher.getInstance(Config.ASYMMETRIC_TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, asymmetricKey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

EncryptionOutputStream:

import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SealedObject;
import javax.crypto.spec.IvParameterSpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class EncryptionOutputStream extends ByteArrayOutputStream {
    private final Cipher cipher;

    public EncryptionOutputStream(SymmetricEncryptionKey symmetricEncryptionKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException {
        super();
        cipher = Cipher.getInstance(Config.SYMMETRIC_TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, symmetricEncryptionKey.getKey(), new IvParameterSpec(symmetricEncryptionKey.getIvParameter()));
    }

    public void writeObject(Serializable object) throws IOException {
        try {
            final SealedObject sealedObject = new SealedObject(object, cipher);
            final ObjectOutputStream outputStream = new ObjectOutputStream(this);
            outputStream.writeObject(sealedObject);
        } catch (final IllegalBlockSizeException e) {
            e.printStackTrace();
        }
    }

}

数据包加密方法:

public final void encryptCredentials(RSAKey asymmetricKey) throws IOException {
    if (credentials != null) {
        SymmetricEncryptionKey symmetricEncryptionKey = EncryptionKeyGenerator.createNewSymmetricKey().getSymmetricEncryptionKey();
        encryptedCredentials = CredentialInflator.deflateCredentials(symmetricEncryptionKey, credentials);
        credentials = null;
        encryptedKey = Encryptor.encrypt(symmetricEncryptionKey.getKey().getEncoded(), asymmetricKey);
        encryptedIvParameter = Encryptor.encrypt(symmetricEncryptionKey.getIvParameter(), asymmetricKey);
    }
}

凭证加密方法:

 public static byte[] deflateCredentials(SymmetricEncryptionKey key, Credentials credentials) throws IOException {
    try (EncryptionOutputStream outStream = new EncryptionOutputStream(key)) {
        outStream.writeObject(credentials);
        return outStream.toByteArray();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return null;
}

SymmetricEncryptionKey类:

import javax.crypto.SecretKey;
public class SymmetricEncryptionKey {

private final SecretKey key;
private byte[] ivParameter = new byte[16];

public SymmetricEncryptionKey(SecretKey key, byte[] ivParameter) {
    this.key = key;
    this.ivParameter = ivParameter;
}

public SecretKey getKey() {
    return key;
}

public byte[] getIvParameter() {
    return ivParameter;
}}

1 个答案:

答案 0 :(得分:0)

数据的最后一块必须是64字节或更少(可包括0字节)。这是因为该算法适用于64字节块,并且需要在最后一个块中适当填充数据。如果剩下64个或更多字节,则不应该执行最后一个块,应该将接下来的64个字节加密为非最终字节。

如果你不知道,你还没有多少研究加密。我考虑不要这样做,而是通过SSL隧道连接。即使专家出错也很容易加密。例如,你是如何进行密钥交换的?最好使用经过测试的库/解决方案而不是自己滚动任何东西。