我正在尝试使用端到端加密进行聊天,但是我在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);
}
我正在做基本上相同的事情,但是有一个用户在另一个活动中,并且一切正常,这些活动之间的唯一区别是,在这个活动中,我尝试获取其他用户的公钥。
答案 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中获取文档作为对象类时会引起问题。