Skip to content

Commit

Permalink
Remove verification tag.
Browse files Browse the repository at this point in the history
1) Remove verification tag from PreKeyWhisperMessage.

2) Include sender and recipient identity keys in the MAC of
   each WhisperMessage.
  • Loading branch information
moxie0 committed Oct 20, 2014
1 parent 641ac9a commit 5ea3b30
Show file tree
Hide file tree
Showing 13 changed files with 80 additions and 556 deletions.
1 change: 0 additions & 1 deletion libaxolotl/protobuf/LocalStorageProtocol.proto
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ message SessionStructure {

optional bool needsRefresh = 12;
optional bytes aliceBaseKey = 13;
optional bytes verification = 14;
}

message RecordStructure {
Expand Down
1 change: 0 additions & 1 deletion libaxolotl/protobuf/WhisperTextProtocol.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ message PreKeyWhisperMessage {
optional uint32 signedPreKeyId = 6;
optional bytes baseKey = 2;
optional bytes identityKey = 3;
optional bytes verification = 7;
optional bytes message = 4; // WhisperMessage
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,82 +406,6 @@ public void testRepeatBundleMessageV3() throws InvalidKeyException, UntrustedIde

}

public void testBadVerificationTagV3() throws InvalidKeyException, UntrustedIdentityException, InvalidVersionException, InvalidMessageException, InvalidKeyIdException, DuplicateMessageException, LegacyMessageException, NoSessionException {
SessionStore aliceSessionStore = new InMemorySessionStore();
SignedPreKeyStore aliceSignedPreKeyStore = new InMemorySignedPreKeyStore();
PreKeyStore alicePreKeyStore = new InMemoryPreKeyStore();
IdentityKeyStore aliceIdentityKeyStore = new InMemoryIdentityKeyStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceSessionStore, alicePreKeyStore,
aliceSignedPreKeyStore,
aliceIdentityKeyStore,
BOB_RECIPIENT_ID, 1);

SessionStore bobSessionStore = new InMemorySessionStore();
PreKeyStore bobPreKeyStore = new InMemoryPreKeyStore();
SignedPreKeyStore bobSignedPreKeyStore = new InMemorySignedPreKeyStore();
IdentityKeyStore bobIdentityKeyStore = new InMemoryIdentityKeyStore();


ECKeyPair bobPreKeyPair = Curve.generateKeyPair(true);
ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair(true);
byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobIdentityKeyStore.getIdentityKeyPair().getPrivateKey(),
bobSignedPreKeyPair.getPublicKey().serialize());

PreKeyBundle bobPreKey = new PreKeyBundle(bobIdentityKeyStore.getLocalRegistrationId(), 1,
31337, bobPreKeyPair.getPublicKey(),
22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
bobIdentityKeyStore.getIdentityKeyPair().getPublicKey());

bobPreKeyStore.storePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
bobSignedPreKeyStore.storeSignedPreKey(22, new SignedPreKeyRecord(22, System.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

aliceSessionBuilder.process(bobPreKey);

String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentityKeyStore, BOB_RECIPIENT_ID, 1);
CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(originalMessage.getBytes());

assertTrue(outgoingMessageOne.getType() == CiphertextMessage.PREKEY_TYPE);

PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessageOne.serialize());

SessionCipher bobSessionCipher = new SessionCipher(bobSessionStore, bobPreKeyStore, bobSignedPreKeyStore, bobIdentityKeyStore, ALICE_RECIPIENT_ID, 1);

for (int i=0;i<incomingMessage.getVerification().length * 8;i++) {
byte[] modifiedVerification = new byte[incomingMessage.getVerification().length];
System.arraycopy(incomingMessage.getVerification(), 0, modifiedVerification, 0, modifiedVerification.length);
modifiedVerification[i / 8] ^= (0x01 << i % 8);

PreKeyWhisperMessage modifiedMessage = new PreKeyWhisperMessage(incomingMessage.getMessageVersion(),
incomingMessage.getRegistrationId(),
incomingMessage.getPreKeyId(),
incomingMessage.getSignedPreKeyId(),
incomingMessage.getBaseKey(),
incomingMessage.getIdentityKey(),
modifiedVerification,
incomingMessage.getWhisperMessage());

try {
bobSessionCipher.decrypt(modifiedMessage);
throw new AssertionError("Modified verification tag passed!");
} catch (InvalidKeyException e) {
// good
}
}

PreKeyWhisperMessage unmodifiedMessage = new PreKeyWhisperMessage(incomingMessage.getMessageVersion(),
incomingMessage.getRegistrationId(),
incomingMessage.getPreKeyId(),
incomingMessage.getSignedPreKeyId(),
incomingMessage.getBaseKey(),
incomingMessage.getIdentityKey(),
incomingMessage.getVerification(),
incomingMessage.getWhisperMessage());

bobSessionCipher.decrypt(unmodifiedMessage);
}


public void testBasicKeyExchange() throws InvalidKeyException, LegacyMessageException, InvalidMessageException, DuplicateMessageException, UntrustedIdentityException, StaleKeyExchangeException, InvalidVersionException, NoSessionException {
SessionStore aliceSessionStore = new InMemorySessionStore();
PreKeyStore alicePreKeyStore = new InMemoryPreKeyStore();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
import org.whispersystems.libaxolotl.util.Medium;
import org.whispersystems.libaxolotl.util.guava.Optional;

import java.security.MessageDigest;

/**
* SessionBuilder is responsible for setting up encrypted sessions.
* Once a session has been established, {@link org.whispersystems.libaxolotl.SessionCipher}
Expand Down Expand Up @@ -143,10 +141,6 @@ private boolean processV3(PreKeyWhisperMessage message)

RatchetingSession.initializeSession(sessionRecord.getSessionState(), message.getMessageVersion(), parameters.create());

if (!MessageDigest.isEqual(sessionRecord.getSessionState().getVerification(), message.getVerification())) {
throw new InvalidKeyException("Verification secret mismatch!");
}

sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
sessionRecord.getSessionState().setAliceBaseKey(message.getBaseKey().serialize());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ public CiphertextMessage encrypt(byte[] paddedMessage) {
byte[] ciphertextBody = getCiphertext(messageKeys, paddedMessage);
CiphertextMessage ciphertextMessage = new WhisperMessage(sessionVersion, messageKeys.getMacKey(),
senderEphemeral, chainKey.getIndex(),
previousCounter, ciphertextBody);
previousCounter, ciphertextBody,
sessionState.getLocalIdentityKey(),
sessionState.getRemoteIdentityKey());

if (sessionState.hasUnacknowledgedPreKeyMessage()) {
UnacknowledgedPreKeyMessageItems items = sessionState.getUnacknowledgedPreKeyMessageItems();
Expand All @@ -114,7 +116,6 @@ public CiphertextMessage encrypt(byte[] paddedMessage) {
ciphertextMessage = new PreKeyWhisperMessage(sessionVersion, localRegistrationId, items.getPreKeyId(),
items.getSignedPreKeyId(), items.getBaseKey(),
sessionState.getLocalIdentityKey(),
sessionState.getVerification(),
(WhisperMessage) ciphertextMessage);
}

Expand Down Expand Up @@ -229,7 +230,10 @@ private byte[] decrypt(SessionState sessionState, WhisperMessage ciphertextMessa
MessageKeys messageKeys = getOrCreateMessageKeys(sessionState, theirEphemeral,
chainKey, counter);

ciphertextMessage.verifyMac(messageKeys.getMacKey());
ciphertextMessage.verifyMac(ciphertextMessage.getMessageVersion(),
sessionState.getRemoteIdentityKey(),
sessionState.getLocalIdentityKey(),
messageKeys.getMacKey());

byte[] plaintext = getPlaintext(messageKeys, ciphertextMessage.getBody());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
private final int signedPreKeyId;
private final ECPublicKey baseKey;
private final IdentityKey identityKey;
private final byte[] verification;
private final WhisperMessage message;
private final byte[] serialized;

Expand All @@ -57,7 +56,6 @@ public PreKeyWhisperMessage(byte[] serialized)

if ((version == 2 && !preKeyWhisperMessage.hasPreKeyId()) ||
(version == 3 && !preKeyWhisperMessage.hasSignedPreKeyId()) ||
(version == 3 && !preKeyWhisperMessage.hasVerification()) ||
!preKeyWhisperMessage.hasBaseKey() ||
!preKeyWhisperMessage.hasIdentityKey() ||
!preKeyWhisperMessage.hasMessage())
Expand All @@ -71,24 +69,21 @@ public PreKeyWhisperMessage(byte[] serialized)
this.signedPreKeyId = preKeyWhisperMessage.hasSignedPreKeyId() ? preKeyWhisperMessage.getSignedPreKeyId() : -1;
this.baseKey = Curve.decodePoint(preKeyWhisperMessage.getBaseKey().toByteArray(), 0);
this.identityKey = new IdentityKey(Curve.decodePoint(preKeyWhisperMessage.getIdentityKey().toByteArray(), 0));
this.verification = preKeyWhisperMessage.getVerification().toByteArray();
this.message = new WhisperMessage(preKeyWhisperMessage.getMessage().toByteArray());
} catch (InvalidProtocolBufferException | InvalidKeyException | LegacyMessageException e) {
throw new InvalidMessageException(e);
}
}

public PreKeyWhisperMessage(int messageVersion, int registrationId, int preKeyId, int signedPreKeyId,
ECPublicKey baseKey, IdentityKey identityKey, byte[] verification,
WhisperMessage message)
ECPublicKey baseKey, IdentityKey identityKey, WhisperMessage message)
{
this.version = messageVersion;
this.registrationId = registrationId;
this.preKeyId = preKeyId;
this.signedPreKeyId = signedPreKeyId;
this.baseKey = baseKey;
this.identityKey = identityKey;
this.verification = verification;
this.message = message;

byte[] versionBytes = {ByteUtil.intsToByteHighAndLow(this.version, CURRENT_VERSION)};
Expand All @@ -97,7 +92,6 @@ public PreKeyWhisperMessage(int messageVersion, int registrationId, int preKeyId
.setSignedPreKeyId(signedPreKeyId)
.setBaseKey(ByteString.copyFrom(baseKey.serialize()))
.setIdentityKey(ByteString.copyFrom(identityKey.serialize()))
.setVerification(ByteString.copyFrom(verification))
.setMessage(ByteString.copyFrom(message.serialize()))
.setRegistrationId(registrationId)
.build().toByteArray();
Expand Down Expand Up @@ -129,10 +123,6 @@ public ECPublicKey getBaseKey() {
return baseKey;
}

public byte[] getVerification() {
return verification;
}

public WhisperMessage getWhisperMessage() {
return message;
}
Expand Down

0 comments on commit 5ea3b30

Please sign in to comment.