Add decryption callback to group decrypt operations.

This commit is contained in:
Moxie Marlinspike 2015-04-06 12:21:54 -07:00
parent 0c98e9f80e
commit 3d9c944288
4 changed files with 35 additions and 5 deletions

View File

@ -0,0 +1,5 @@
package org.whispersystems.libaxolotl;
public interface DecryptionCallback {
public void handlePlaintext(byte[] plaintext);
}

View File

@ -455,10 +455,6 @@ public class SessionCipher {
} }
} }
public static interface DecryptionCallback {
public void handlePlaintext(byte[] plaintext);
}
private static class NullDecryptionCallback implements DecryptionCallback { private static class NullDecryptionCallback implements DecryptionCallback {
@Override @Override
public void handlePlaintext(byte[] plaintext) {} public void handlePlaintext(byte[] plaintext) {}

View File

@ -16,6 +16,7 @@
*/ */
package org.whispersystems.libaxolotl.groups; package org.whispersystems.libaxolotl.groups;
import org.whispersystems.libaxolotl.DecryptionCallback;
import org.whispersystems.libaxolotl.DuplicateMessageException; import org.whispersystems.libaxolotl.DuplicateMessageException;
import org.whispersystems.libaxolotl.InvalidKeyIdException; import org.whispersystems.libaxolotl.InvalidKeyIdException;
import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
@ -101,6 +102,27 @@ public class GroupCipher {
* @throws DuplicateMessageException * @throws DuplicateMessageException
*/ */
public byte[] decrypt(byte[] senderKeyMessageBytes) public byte[] decrypt(byte[] senderKeyMessageBytes)
throws LegacyMessageException, DuplicateMessageException, InvalidMessageException
{
return decrypt(senderKeyMessageBytes, new NullDecryptionCallback());
}
/**
* Decrypt a SenderKey group message.
*
* @param senderKeyMessageBytes The received ciphertext.
* @param callback A callback that is triggered after decryption is complete,
* but before the updated session state has been committed to the session
* DB. This allows some implementations to store the committed plaintext
* to a DB first, in case they are concerned with a crash happening between
* the time the session state is updated but before they're able to store
* the plaintext to disk.
* @return Plaintext
* @throws LegacyMessageException
* @throws InvalidMessageException
* @throws DuplicateMessageException
*/
public byte[] decrypt(byte[] senderKeyMessageBytes, DecryptionCallback callback)
throws LegacyMessageException, InvalidMessageException, DuplicateMessageException throws LegacyMessageException, InvalidMessageException, DuplicateMessageException
{ {
synchronized (LOCK) { synchronized (LOCK) {
@ -115,6 +137,8 @@ public class GroupCipher {
byte[] plaintext = getPlainText(senderKey.getIv(), senderKey.getCipherKey(), senderKeyMessage.getCipherText()); byte[] plaintext = getPlainText(senderKey.getIv(), senderKey.getCipherKey(), senderKeyMessage.getCipherText());
callback.handlePlaintext(plaintext);
senderKeyStore.storeSenderKey(senderKeyId, record); senderKeyStore.storeSenderKey(senderKeyId, record);
return plaintext; return plaintext;
@ -185,4 +209,9 @@ public class GroupCipher {
} }
} }
private static class NullDecryptionCallback implements DecryptionCallback {
@Override
public void handlePlaintext(byte[] plaintext) {}
}
} }

View File

@ -135,7 +135,7 @@ public class SessionBuilderTest extends TestCase {
bobStore.storeSignedPreKey(22, new SignedPreKeyRecord(22, System.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature)); bobStore.storeSignedPreKey(22, new SignedPreKeyRecord(22, System.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS); SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
byte[] plaintext = bobSessionCipher.decrypt(incomingMessage, new SessionCipher.DecryptionCallback() { byte[] plaintext = bobSessionCipher.decrypt(incomingMessage, new DecryptionCallback() {
@Override @Override
public void handlePlaintext(byte[] plaintext) { public void handlePlaintext(byte[] plaintext) {
assertTrue(originalMessage.equals(new String(plaintext))); assertTrue(originalMessage.equals(new String(plaintext)));