代码之家  ›  专栏  ›  技术社区  ›  Wiktor

RSA加密非法块大小异常

  •  0
  • Wiktor  · 技术社区  · 7 年前

    我正试图通过端到端加密进行聊天,但我 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 回复  |  直到 7 年前
        1
  •  0
  •   Wiktor    7 年前

    好的,我找到了解决方案,看起来它完全不是我所期望的。

    问题其实是这条线 if (targetFriendSDK >= Build.VERSION_CODES.M)

    我创造了一个 User private int SDK; 使用大写字母,但在实际的Firestore中它被保存为 sdk 用小写字母,当我从Firestore获得用户时,我使用 .toObject(User.class); 那可能就是它要找的地方 sdk 因为它在数据库中,但只能找到 SDK 0 .

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