RSA加密非法块大小异常

时间:2018-11-24 16:23:24

标签: android encryption rsa

我正在尝试使用端到端加密进行聊天,但是我在javax.crypto. IllegalBlockSizeException这行上得到了byte[] decryptedMessage = cipher.doFinal(decodedMessage);

我通过以下方式获取他人的公共密钥:

CollectionReference userCollection = FirebaseFirestore.getInstance().collection("users");

userCollection.whereEqualTo("userID", targetFriendID).get().addOnCompleteListener(new OnCompleteListener < QuerySnapshot > () {@Override
    public void onComplete(@NonNull Task < QuerySnapshot > task) {

        if (task.isSuccessful()) {

            for (QueryDocumentSnapshot doc: task.getResult()) {

                User tempUser = doc.toObject(User.class);

                targetFriendSDK = tempUser.getSDK();

                String keyString = tempUser.getPublicKey();

                byte[] keyBytes = Base64.decode(keyString, Base64.NO_WRAP);

                try {

                    friendPublicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyBytes));

                    dialog.cancel();

                } catch(Exception e) {
                    dialog.cancel();
                    Toast.makeText(ChatRoom.this, "Error, try again", Toast.LENGTH_SHORT).show();
                }

            }

        } else {
            dialog.cancel();
            Toast.makeText(ChatRoom.this, "Error", Toast.LENGTH_SHORT).show();
        }

    }
});

解密是这样完成的:

String encodedMessage = cloudMessage.getMessage();
Date date = cloudMessage.getDate();
tring senderID = cloudMessage.getSenderID();
String receivID = cloudMessage.getReceiverID();

int sdk = Build.VERSION.SDK_INT;

byte[] decodedMessage = Base64.decode(encodedMessage, Base64.NO_WRAP);

String finalMessage;

try {

    if (sdk >= Build.VERSION_CODES.M) {

        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");

        OAEPParameterSpec sp = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);

        cipher.init(Cipher.DECRYPT_MODE, privateKey, sp);

        byte[] decryptedMessage = cipher.doFinal(decodedMessage);

        finalMessage = new String(decryptedMessage);

    } else {

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        byte[] decryptedMessage = cipher.doFinal(decodedMessage);

        finalMessage = new String(decryptedMessage);

    }

和加密:

byte[] messageBytes = messageText.getBytes();

String encodedMessage;

try {

    if (targetFriendSDK >= Build.VERSION_CODES.M) {

        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");

        OAEPParameterSpec sp = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);

        cipher.init(Cipher.ENCRYPT_MODE, friendPublicKey, sp);

        byte[] cipherText = cipher.doFinal(messageBytes);

        encodedMessage = Base64.encodeToString(cipherText, Base64.NO_WRAP);

    } else {

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, friendPublicKey);

        byte[] cipherText = cipher.doFinal(messageBytes);

        encodedMessage = Base64.encodeToString(cipherText, Base64.NO_WRAP);

    } 

我正在做基本上相同的事情,但是有一个用户在另一个活动中,并且一切正常,这些活动之间的唯一区别是,在这个活动中,我尝试获取其他用户的公钥。

1 个答案:

答案 0 :(得分:0)

好吧,我找到了解决方案,看来它根本不在我期望的位置。

问题实际上是此行if (targetFriendSDK >= Build.VERSION_CODES.M),我在其中检查其他用户的设备Android版本,以区分我应使用的加密类型。我意识到由于Firestore命名问题,它总是返回0。

我创建了一个User文档,用于解析自定义User类以创建文档,其中一个字段sdk字段以大写字母命名为private int SDK;,但在实际的Firestore中,它另存为{ {1}}带有小写字母,当我从Firestore获取用户时,我使用了sdk,这可能是它在数据库中寻找.toObject(User.class);的地方,但只发现了{{1} },因此字段不匹配,因此保留为sdk

结论:在Firestore中命名字段时,请勿使用大写字母,因为这会将它们更改为数据库中的小写字母,并且在尝试从Firestore中获取文档作为对象类时会引起问题。