Make sure senderkeys encrypt is correctly initialized.

This commit is contained in:
Moxie Marlinspike 2014-09-30 11:58:56 -07:00
parent 9a0ed659f7
commit 5fcc135f81
6 changed files with 43 additions and 26 deletions

View File

@ -6,6 +6,7 @@ import android.util.Log;
import org.whispersystems.libaxolotl.DuplicateMessageException; import org.whispersystems.libaxolotl.DuplicateMessageException;
import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.libaxolotl.LegacyMessageException; import org.whispersystems.libaxolotl.LegacyMessageException;
import org.whispersystems.libaxolotl.NoSessionException;
import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.groups.GroupCipher; import org.whispersystems.libaxolotl.groups.GroupCipher;
import org.whispersystems.libaxolotl.groups.GroupSessionBuilder; import org.whispersystems.libaxolotl.groups.GroupSessionBuilder;
@ -21,7 +22,7 @@ import java.util.List;
public class GroupCipherTest extends AndroidTestCase { public class GroupCipherTest extends AndroidTestCase {
public void testBasicEncryptDecrypt() public void testBasicEncryptDecrypt()
throws LegacyMessageException, DuplicateMessageException, InvalidMessageException throws LegacyMessageException, DuplicateMessageException, InvalidMessageException, NoSessionException
{ {
InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore(); InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore();
InMemorySenderKeyStore bobStore = new InMemorySenderKeyStore(); InMemorySenderKeyStore bobStore = new InMemorySenderKeyStore();
@ -49,7 +50,7 @@ public class GroupCipherTest extends AndroidTestCase {
} }
public void testBasicRatchet() public void testBasicRatchet()
throws LegacyMessageException, DuplicateMessageException, InvalidMessageException throws LegacyMessageException, DuplicateMessageException, InvalidMessageException, NoSessionException
{ {
InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore(); InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore();
InMemorySenderKeyStore bobStore = new InMemorySenderKeyStore(); InMemorySenderKeyStore bobStore = new InMemorySenderKeyStore();
@ -92,7 +93,7 @@ public class GroupCipherTest extends AndroidTestCase {
} }
public void testOutOfOrder() public void testOutOfOrder()
throws LegacyMessageException, DuplicateMessageException, InvalidMessageException throws LegacyMessageException, DuplicateMessageException, InvalidMessageException, NoSessionException
{ {
InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore(); InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore();
InMemorySenderKeyStore bobStore = new InMemorySenderKeyStore(); InMemorySenderKeyStore bobStore = new InMemorySenderKeyStore();
@ -129,6 +130,17 @@ public class GroupCipherTest extends AndroidTestCase {
} }
} }
public void testEncryptNoSession() {
InMemorySenderKeyStore aliceStore = new InMemorySenderKeyStore();
GroupCipher aliceGroupCipher = new GroupCipher(aliceStore, "groupWithBobInIt");
try {
aliceGroupCipher.encrypt("up the punks".getBytes());
throw new AssertionError("Should have failed!");
} catch (NoSessionException nse) {
// good
}
}
private int randomInt() { private int randomInt() {
try { try {
return SecureRandom.getInstance("SHA1PRNG").nextInt(Integer.MAX_VALUE); return SecureRandom.getInstance("SHA1PRNG").nextInt(Integer.MAX_VALUE);

View File

@ -4,4 +4,8 @@ public class NoSessionException extends Exception {
public NoSessionException(String s) { public NoSessionException(String s) {
super(s); super(s);
} }
public NoSessionException(Exception nested) {
super(nested);
}
} }

View File

@ -1,18 +1,16 @@
package org.whispersystems.libaxolotl.groups; package org.whispersystems.libaxolotl.groups;
import android.util.Log;
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;
import org.whispersystems.libaxolotl.LegacyMessageException; import org.whispersystems.libaxolotl.LegacyMessageException;
import org.whispersystems.libaxolotl.NoSessionException;
import org.whispersystems.libaxolotl.groups.ratchet.SenderChainKey; import org.whispersystems.libaxolotl.groups.ratchet.SenderChainKey;
import org.whispersystems.libaxolotl.groups.ratchet.SenderMessageKey; import org.whispersystems.libaxolotl.groups.ratchet.SenderMessageKey;
import org.whispersystems.libaxolotl.groups.state.SenderKeyRecord; import org.whispersystems.libaxolotl.groups.state.SenderKeyRecord;
import org.whispersystems.libaxolotl.groups.state.SenderKeyState; import org.whispersystems.libaxolotl.groups.state.SenderKeyState;
import org.whispersystems.libaxolotl.protocol.SenderKeyMessage;
import org.whispersystems.libaxolotl.groups.state.SenderKeyStore; import org.whispersystems.libaxolotl.groups.state.SenderKeyStore;
import org.whispersystems.libaxolotl.protocol.SenderKeyMessage;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -36,23 +34,27 @@ public class GroupCipher {
this.senderKeyId = senderKeyId; this.senderKeyId = senderKeyId;
} }
public byte[] encrypt(byte[] paddedPlaintext) { public byte[] encrypt(byte[] paddedPlaintext) throws NoSessionException {
synchronized (LOCK) { synchronized (LOCK) {
SenderKeyRecord record = senderKeyStore.loadSenderKey(senderKeyId); try {
SenderKeyState senderKeyState = record.getSenderKeyState(); SenderKeyRecord record = senderKeyStore.loadSenderKey(senderKeyId);
SenderMessageKey senderKey = senderKeyState.getSenderChainKey().getSenderMessageKey(); SenderKeyState senderKeyState = record.getSenderKeyState();
byte[] ciphertext = getCipherText(senderKey.getIv(), senderKey.getCipherKey(), paddedPlaintext); SenderMessageKey senderKey = senderKeyState.getSenderChainKey().getSenderMessageKey();
byte[] ciphertext = getCipherText(senderKey.getIv(), senderKey.getCipherKey(), paddedPlaintext);
SenderKeyMessage senderKeyMessage = new SenderKeyMessage(senderKeyState.getKeyId(), SenderKeyMessage senderKeyMessage = new SenderKeyMessage(senderKeyState.getKeyId(),
senderKey.getIteration(), senderKey.getIteration(),
ciphertext, ciphertext,
senderKeyState.getSigningKeyPrivate()); senderKeyState.getSigningKeyPrivate());
senderKeyState.setSenderChainKey(senderKeyState.getSenderChainKey().getNext()); senderKeyState.setSenderChainKey(senderKeyState.getSenderChainKey().getNext());
senderKeyStore.storeSenderKey(senderKeyId, record); senderKeyStore.storeSenderKey(senderKeyId, record);
return senderKeyMessage.serialize(); return senderKeyMessage.serialize();
} catch (InvalidKeyIdException e) {
throw new NoSessionException(e);
}
} }
} }

View File

@ -3,7 +3,6 @@ package org.whispersystems.libaxolotl.groups.state;
import org.whispersystems.libaxolotl.InvalidKeyIdException; import org.whispersystems.libaxolotl.InvalidKeyIdException;
import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.libaxolotl.ecc.ECKeyPair;
import org.whispersystems.libaxolotl.ecc.ECPublicKey; import org.whispersystems.libaxolotl.ecc.ECPublicKey;
import org.whispersystems.libaxolotl.groups.state.SenderKeyState;
import org.whispersystems.libaxolotl.state.StorageProtos; import org.whispersystems.libaxolotl.state.StorageProtos;
import java.io.IOException; import java.io.IOException;
@ -26,8 +25,12 @@ public class SenderKeyRecord {
} }
} }
public SenderKeyState getSenderKeyState() { public SenderKeyState getSenderKeyState() throws InvalidKeyIdException {
return senderKeyStates.get(0); if (!senderKeyStates.isEmpty()) {
return senderKeyStates.get(0);
} else {
throw new InvalidKeyIdException("No key state in record!");
}
} }
public SenderKeyState getSenderKeyState(int keyId) throws InvalidKeyIdException { public SenderKeyState getSenderKeyState(int keyId) throws InvalidKeyIdException {

View File

@ -1,7 +1,5 @@
package org.whispersystems.libaxolotl.groups.state; package org.whispersystems.libaxolotl.groups.state;
import android.util.Log;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import org.whispersystems.libaxolotl.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyException;

View File

@ -1,7 +1,5 @@
package org.whispersystems.libaxolotl.groups.state; package org.whispersystems.libaxolotl.groups.state;
import org.whispersystems.libaxolotl.groups.state.SenderKeyRecord;
public interface SenderKeyStore { public interface SenderKeyStore {
public void storeSenderKey(String senderKeyId, SenderKeyRecord record); public void storeSenderKey(String senderKeyId, SenderKeyRecord record);
public SenderKeyRecord loadSenderKey(String senderKeyId); public SenderKeyRecord loadSenderKey(String senderKeyId);