mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-11 16:33:39 +00:00
Remove verification tag.
1) Remove verification tag from PreKeyWhisperMessage. 2) Include sender and recipient identity keys in the MAC of each WhisperMessage.
This commit is contained in:
parent
641ac9aed9
commit
5ea3b3038e
@ -58,7 +58,6 @@ message SessionStructure {
|
||||
|
||||
optional bool needsRefresh = 12;
|
||||
optional bytes aliceBaseKey = 13;
|
||||
optional bytes verification = 14;
|
||||
}
|
||||
|
||||
message RecordStructure {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -406,82 +406,6 @@ public class SessionBuilderTest extends AndroidTestCase {
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -1,90 +0,0 @@
|
||||
package org.whispersystems.test.ratchet;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.ratchet.VerifyKey;
|
||||
import org.whispersystems.libaxolotl.util.Hex;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class VerifyKeyTest extends AndroidTestCase {
|
||||
|
||||
public void testVerify() throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
byte[] aliceBaseKeyBytes = {(byte) 0x05, (byte) 0x2d, (byte) 0x0c, (byte) 0xdd, (byte) 0xde,
|
||||
(byte) 0xa8, (byte) 0x9f, (byte) 0x6a, (byte) 0x2c, (byte) 0xe0,
|
||||
(byte) 0x21, (byte) 0xfa, (byte) 0x69, (byte) 0x39, (byte) 0x30,
|
||||
(byte) 0x43, (byte) 0x28, (byte) 0xd0, (byte) 0xa3, (byte) 0x53,
|
||||
(byte) 0xe0, (byte) 0x67, (byte) 0xb9, (byte) 0x11, (byte) 0xf5,
|
||||
(byte) 0xa9, (byte) 0xbd, (byte) 0xa4, (byte) 0x7b, (byte) 0x29,
|
||||
(byte) 0x41, (byte) 0x6e, (byte) 0x2b};
|
||||
|
||||
byte[] aliceIdentityKeyBytes = {(byte) 0x05, (byte) 0x9d, (byte) 0x86, (byte) 0xef, (byte) 0x77,
|
||||
(byte) 0x7d, (byte) 0x71, (byte) 0x0c, (byte) 0xc2, (byte) 0xb1,
|
||||
(byte) 0x4e, (byte) 0xd6, (byte) 0x15, (byte) 0x2e, (byte) 0x91,
|
||||
(byte) 0xfb, (byte) 0x7f, (byte) 0xa2, (byte) 0x34, (byte) 0xe5,
|
||||
(byte) 0x5b, (byte) 0x57, (byte) 0x2e, (byte) 0x52, (byte) 0xb8,
|
||||
(byte) 0x5f, (byte) 0x84, (byte) 0xdb, (byte) 0x34, (byte) 0x16,
|
||||
(byte) 0x69, (byte) 0xfd, (byte) 0x45};
|
||||
|
||||
byte[] bobBaseKeyBytes = {(byte) 0x05, (byte) 0xc0, (byte) 0xbd, (byte) 0x26, (byte) 0x62,
|
||||
(byte) 0xf7, (byte) 0xea, (byte) 0xa8, (byte) 0x5a, (byte) 0x5e,
|
||||
(byte) 0x43, (byte) 0x95, (byte) 0x34, (byte) 0x3a, (byte) 0xcf,
|
||||
(byte) 0x66, (byte) 0x36, (byte) 0xec, (byte) 0x75, (byte) 0x54,
|
||||
(byte) 0x7b, (byte) 0x96, (byte) 0x02, (byte) 0x6d, (byte) 0x8a,
|
||||
(byte) 0x16, (byte) 0xb6, (byte) 0x39, (byte) 0x10, (byte) 0x36,
|
||||
(byte) 0xf6, (byte) 0x9f, (byte) 0x39};
|
||||
|
||||
byte[] bobPreKeyBytes = {(byte) 0x05, (byte) 0xb8, (byte) 0x28, (byte) 0x04, (byte) 0xe6,
|
||||
(byte) 0x46, (byte) 0xeb, (byte) 0x04, (byte) 0xaf, (byte) 0x54,
|
||||
(byte) 0xeb, (byte) 0xea, (byte) 0xfa, (byte) 0x8e, (byte) 0x27,
|
||||
(byte) 0xb1, (byte) 0xa7, (byte) 0xa8, (byte) 0x00, (byte) 0xef,
|
||||
(byte) 0xcf, (byte) 0xd7, (byte) 0xe8, (byte) 0x9c, (byte) 0x92,
|
||||
(byte) 0xfc, (byte) 0x51, (byte) 0x66, (byte) 0xb8, (byte) 0x70,
|
||||
(byte) 0xee, (byte) 0x63, (byte) 0x74};
|
||||
|
||||
byte[] bobIdentityKeyBytes = {(byte) 0x05, (byte) 0x3a, (byte) 0x32, (byte) 0x3a, (byte) 0xda,
|
||||
(byte) 0xe8, (byte) 0x46, (byte) 0x1b, (byte) 0x57, (byte) 0x8d,
|
||||
(byte) 0x46, (byte) 0x70, (byte) 0x80, (byte) 0x0e, (byte) 0x06,
|
||||
(byte) 0x76, (byte) 0x5a, (byte) 0xf1, (byte) 0x50, (byte) 0x51,
|
||||
(byte) 0xd3, (byte) 0x74, (byte) 0xa0, (byte) 0x65, (byte) 0x85,
|
||||
(byte) 0xea, (byte) 0x03, (byte) 0xff, (byte) 0x58, (byte) 0x7c,
|
||||
(byte) 0x81, (byte) 0xa8, (byte) 0x04};
|
||||
|
||||
|
||||
byte[] key = {(byte)0xfc, (byte)0x57, (byte)0x05, (byte)0xdc, (byte)0xe0,
|
||||
(byte)0x34, (byte)0x4c, (byte)0x8f, (byte)0x1c, (byte)0xeb,
|
||||
(byte)0x9b, (byte)0x05, (byte)0x7c, (byte)0xaa, (byte)0xb0,
|
||||
(byte)0x08, (byte)0xf0, (byte)0xb7, (byte)0x26, (byte)0x73,
|
||||
(byte)0x46, (byte)0xa4, (byte)0x00, (byte)0xa3, (byte)0x66,
|
||||
(byte)0x79, (byte)0x00, (byte)0xef, (byte)0x1b, (byte)0x40,
|
||||
(byte)0x0f, (byte)0xdc};
|
||||
|
||||
byte[] expectedTag = {(byte)0xd3, (byte)0x62, (byte)0x84, (byte)0x3c,
|
||||
(byte)0x9d, (byte)0x59, (byte)0x8c, (byte)0x6f};
|
||||
|
||||
ECPublicKey aliceBaseKey = Curve.decodePoint(aliceBaseKeyBytes, 0);
|
||||
ECPublicKey alicePreKey = aliceBaseKey;
|
||||
ECPublicKey aliceIdentityKey = Curve.decodePoint(aliceIdentityKeyBytes, 0);
|
||||
|
||||
ECPublicKey bobBaseKey = Curve.decodePoint(bobBaseKeyBytes, 0);
|
||||
ECPublicKey bobPreKey = Curve.decodePoint(bobPreKeyBytes, 0);
|
||||
ECPublicKey bobIdentityKey = Curve.decodePoint(bobIdentityKeyBytes, 0);
|
||||
|
||||
VerifyKey verifyKey = new VerifyKey(key);
|
||||
|
||||
byte[] verification = verifyKey.generateVerification(new IdentityKey(aliceIdentityKey),
|
||||
new IdentityKey(bobIdentityKey),
|
||||
aliceBaseKey, bobBaseKey,
|
||||
Optional.of(bobPreKey));
|
||||
|
||||
assertTrue(MessageDigest.isEqual(verification, expectedTag));
|
||||
}
|
||||
|
||||
}
|
@ -23,8 +23,6 @@ import org.whispersystems.libaxolotl.util.KeyHelper;
|
||||
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}
|
||||
@ -143,10 +141,6 @@ public class SessionBuilder {
|
||||
|
||||
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());
|
||||
|
@ -105,7 +105,9 @@ public class SessionCipher {
|
||||
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();
|
||||
@ -114,7 +116,6 @@ public class SessionCipher {
|
||||
ciphertextMessage = new PreKeyWhisperMessage(sessionVersion, localRegistrationId, items.getPreKeyId(),
|
||||
items.getSignedPreKeyId(), items.getBaseKey(),
|
||||
sessionState.getLocalIdentityKey(),
|
||||
sessionState.getVerification(),
|
||||
(WhisperMessage) ciphertextMessage);
|
||||
}
|
||||
|
||||
@ -229,7 +230,10 @@ public class SessionCipher {
|
||||
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());
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -57,7 +56,6 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
|
||||
if ((version == 2 && !preKeyWhisperMessage.hasPreKeyId()) ||
|
||||
(version == 3 && !preKeyWhisperMessage.hasSignedPreKeyId()) ||
|
||||
(version == 3 && !preKeyWhisperMessage.hasVerification()) ||
|
||||
!preKeyWhisperMessage.hasBaseKey() ||
|
||||
!preKeyWhisperMessage.hasIdentityKey() ||
|
||||
!preKeyWhisperMessage.hasMessage())
|
||||
@ -71,7 +69,6 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
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);
|
||||
@ -79,8 +76,7 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
}
|
||||
|
||||
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;
|
||||
@ -88,7 +84,6 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
this.signedPreKeyId = signedPreKeyId;
|
||||
this.baseKey = baseKey;
|
||||
this.identityKey = identityKey;
|
||||
this.verification = verification;
|
||||
this.message = message;
|
||||
|
||||
byte[] versionBytes = {ByteUtil.intsToByteHighAndLow(this.version, CURRENT_VERSION)};
|
||||
@ -97,7 +92,6 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
.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();
|
||||
@ -129,10 +123,6 @@ public class PreKeyWhisperMessage implements CiphertextMessage {
|
||||
return baseKey;
|
||||
}
|
||||
|
||||
public byte[] getVerification() {
|
||||
return verification;
|
||||
}
|
||||
|
||||
public WhisperMessage getWhisperMessage() {
|
||||
return message;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package org.whispersystems.libaxolotl.protocol;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
@ -80,7 +81,9 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
}
|
||||
|
||||
public WhisperMessage(int messageVersion, SecretKeySpec macKey, ECPublicKey senderRatchetKey,
|
||||
int counter, int previousCounter, byte[] ciphertext)
|
||||
int counter, int previousCounter, byte[] ciphertext,
|
||||
IdentityKey senderIdentityKey,
|
||||
IdentityKey receiverIdentityKey)
|
||||
{
|
||||
byte[] version = {ByteUtil.intsToByteHighAndLow(messageVersion, CURRENT_VERSION)};
|
||||
byte[] message = WhisperProtos.WhisperMessage.newBuilder()
|
||||
@ -89,7 +92,9 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
.setPreviousCounter(previousCounter)
|
||||
.setCiphertext(ByteString.copyFrom(ciphertext))
|
||||
.build().toByteArray();
|
||||
byte[] mac = getMac(macKey, ByteUtil.combine(version, message));
|
||||
|
||||
byte[] mac = getMac(messageVersion, senderIdentityKey, receiverIdentityKey, macKey,
|
||||
ByteUtil.combine(version, message));
|
||||
|
||||
this.serialized = ByteUtil.combine(version, message, mac);
|
||||
this.senderRatchetKey = senderRatchetKey;
|
||||
@ -115,11 +120,12 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
public void verifyMac(SecretKeySpec macKey)
|
||||
public void verifyMac(int messageVersion, IdentityKey senderIdentityKey,
|
||||
IdentityKey receiverIdentityKey, SecretKeySpec macKey)
|
||||
throws InvalidMessageException
|
||||
{
|
||||
byte[][] parts = ByteUtil.split(serialized, serialized.length - MAC_LENGTH, MAC_LENGTH);
|
||||
byte[] ourMac = getMac(macKey, parts[0]);
|
||||
byte[] ourMac = getMac(messageVersion, senderIdentityKey, receiverIdentityKey, macKey, parts[0]);
|
||||
byte[] theirMac = parts[1];
|
||||
|
||||
if (!MessageDigest.isEqual(ourMac, theirMac)) {
|
||||
@ -127,11 +133,20 @@ public class WhisperMessage implements CiphertextMessage {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getMac(SecretKeySpec macKey, byte[] serialized) {
|
||||
private byte[] getMac(int messageVersion,
|
||||
IdentityKey senderIdentityKey,
|
||||
IdentityKey receiverIdentityKey,
|
||||
SecretKeySpec macKey, byte[] serialized)
|
||||
{
|
||||
try {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(macKey);
|
||||
|
||||
if (messageVersion >= 3) {
|
||||
mac.update(senderIdentityKey.getPublicKey().serialize());
|
||||
mac.update(receiverIdentityKey.getPublicKey().serialize());
|
||||
}
|
||||
|
||||
byte[] fullMac = mac.doFinal(serialized);
|
||||
return ByteUtil.trim(fullMac, MAC_LENGTH);
|
||||
} catch (NoSuchAlgorithmException | java.security.InvalidKeyException e) {
|
||||
|
@ -706,16 +706,6 @@ public final class WhisperProtos {
|
||||
*/
|
||||
com.google.protobuf.ByteString getIdentityKey();
|
||||
|
||||
// optional bytes verification = 7;
|
||||
/**
|
||||
* <code>optional bytes verification = 7;</code>
|
||||
*/
|
||||
boolean hasVerification();
|
||||
/**
|
||||
* <code>optional bytes verification = 7;</code>
|
||||
*/
|
||||
com.google.protobuf.ByteString getVerification();
|
||||
|
||||
// optional bytes message = 4;
|
||||
/**
|
||||
* <code>optional bytes message = 4;</code>
|
||||
@ -801,7 +791,7 @@ public final class WhisperProtos {
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
bitField0_ |= 0x00000040;
|
||||
bitField0_ |= 0x00000020;
|
||||
message_ = input.readBytes();
|
||||
break;
|
||||
}
|
||||
@ -815,11 +805,6 @@ public final class WhisperProtos {
|
||||
signedPreKeyId_ = input.readUInt32();
|
||||
break;
|
||||
}
|
||||
case 58: {
|
||||
bitField0_ |= 0x00000020;
|
||||
verification_ = input.readBytes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||
@ -940,22 +925,6 @@ public final class WhisperProtos {
|
||||
return identityKey_;
|
||||
}
|
||||
|
||||
// optional bytes verification = 7;
|
||||
public static final int VERIFICATION_FIELD_NUMBER = 7;
|
||||
private com.google.protobuf.ByteString verification_;
|
||||
/**
|
||||
* <code>optional bytes verification = 7;</code>
|
||||
*/
|
||||
public boolean hasVerification() {
|
||||
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes verification = 7;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString getVerification() {
|
||||
return verification_;
|
||||
}
|
||||
|
||||
// optional bytes message = 4;
|
||||
public static final int MESSAGE_FIELD_NUMBER = 4;
|
||||
private com.google.protobuf.ByteString message_;
|
||||
@ -967,7 +936,7 @@ public final class WhisperProtos {
|
||||
* </pre>
|
||||
*/
|
||||
public boolean hasMessage() {
|
||||
return ((bitField0_ & 0x00000040) == 0x00000040);
|
||||
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes message = 4;</code>
|
||||
@ -986,7 +955,6 @@ public final class WhisperProtos {
|
||||
signedPreKeyId_ = 0;
|
||||
baseKey_ = com.google.protobuf.ByteString.EMPTY;
|
||||
identityKey_ = com.google.protobuf.ByteString.EMPTY;
|
||||
verification_ = com.google.protobuf.ByteString.EMPTY;
|
||||
message_ = com.google.protobuf.ByteString.EMPTY;
|
||||
}
|
||||
private byte memoizedIsInitialized = -1;
|
||||
@ -1010,7 +978,7 @@ public final class WhisperProtos {
|
||||
if (((bitField0_ & 0x00000010) == 0x00000010)) {
|
||||
output.writeBytes(3, identityKey_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000040) == 0x00000040)) {
|
||||
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||
output.writeBytes(4, message_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000001) == 0x00000001)) {
|
||||
@ -1019,9 +987,6 @@ public final class WhisperProtos {
|
||||
if (((bitField0_ & 0x00000004) == 0x00000004)) {
|
||||
output.writeUInt32(6, signedPreKeyId_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||
output.writeBytes(7, verification_);
|
||||
}
|
||||
getUnknownFields().writeTo(output);
|
||||
}
|
||||
|
||||
@ -1043,7 +1008,7 @@ public final class WhisperProtos {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBytesSize(3, identityKey_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000040) == 0x00000040)) {
|
||||
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBytesSize(4, message_);
|
||||
}
|
||||
@ -1055,10 +1020,6 @@ public final class WhisperProtos {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeUInt32Size(6, signedPreKeyId_);
|
||||
}
|
||||
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBytesSize(7, verification_);
|
||||
}
|
||||
size += getUnknownFields().getSerializedSize();
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
@ -1185,10 +1146,8 @@ public final class WhisperProtos {
|
||||
bitField0_ = (bitField0_ & ~0x00000008);
|
||||
identityKey_ = com.google.protobuf.ByteString.EMPTY;
|
||||
bitField0_ = (bitField0_ & ~0x00000010);
|
||||
verification_ = com.google.protobuf.ByteString.EMPTY;
|
||||
bitField0_ = (bitField0_ & ~0x00000020);
|
||||
message_ = com.google.protobuf.ByteString.EMPTY;
|
||||
bitField0_ = (bitField0_ & ~0x00000040);
|
||||
bitField0_ = (bitField0_ & ~0x00000020);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1240,10 +1199,6 @@ public final class WhisperProtos {
|
||||
if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
|
||||
to_bitField0_ |= 0x00000020;
|
||||
}
|
||||
result.verification_ = verification_;
|
||||
if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
|
||||
to_bitField0_ |= 0x00000040;
|
||||
}
|
||||
result.message_ = message_;
|
||||
result.bitField0_ = to_bitField0_;
|
||||
onBuilt();
|
||||
@ -1276,9 +1231,6 @@ public final class WhisperProtos {
|
||||
if (other.hasIdentityKey()) {
|
||||
setIdentityKey(other.getIdentityKey());
|
||||
}
|
||||
if (other.hasVerification()) {
|
||||
setVerification(other.getVerification());
|
||||
}
|
||||
if (other.hasMessage()) {
|
||||
setMessage(other.getMessage());
|
||||
}
|
||||
@ -1480,42 +1432,6 @@ public final class WhisperProtos {
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional bytes verification = 7;
|
||||
private com.google.protobuf.ByteString verification_ = com.google.protobuf.ByteString.EMPTY;
|
||||
/**
|
||||
* <code>optional bytes verification = 7;</code>
|
||||
*/
|
||||
public boolean hasVerification() {
|
||||
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes verification = 7;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString getVerification() {
|
||||
return verification_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes verification = 7;</code>
|
||||
*/
|
||||
public Builder setVerification(com.google.protobuf.ByteString value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
bitField0_ |= 0x00000020;
|
||||
verification_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes verification = 7;</code>
|
||||
*/
|
||||
public Builder clearVerification() {
|
||||
bitField0_ = (bitField0_ & ~0x00000020);
|
||||
verification_ = getDefaultInstance().getVerification();
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional bytes message = 4;
|
||||
private com.google.protobuf.ByteString message_ = com.google.protobuf.ByteString.EMPTY;
|
||||
/**
|
||||
@ -1526,7 +1442,7 @@ public final class WhisperProtos {
|
||||
* </pre>
|
||||
*/
|
||||
public boolean hasMessage() {
|
||||
return ((bitField0_ & 0x00000040) == 0x00000040);
|
||||
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes message = 4;</code>
|
||||
@ -1549,7 +1465,7 @@ public final class WhisperProtos {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
bitField0_ |= 0x00000040;
|
||||
bitField0_ |= 0x00000020;
|
||||
message_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
@ -1562,7 +1478,7 @@ public final class WhisperProtos {
|
||||
* </pre>
|
||||
*/
|
||||
public Builder clearMessage() {
|
||||
bitField0_ = (bitField0_ & ~0x00000040);
|
||||
bitField0_ = (bitField0_ & ~0x00000020);
|
||||
message_ = getDefaultInstance().getMessage();
|
||||
onChanged();
|
||||
return this;
|
||||
@ -1625,18 +1541,10 @@ public final class WhisperProtos {
|
||||
// optional bytes baseKeySignature = 5;
|
||||
/**
|
||||
* <code>optional bytes baseKeySignature = 5;</code>
|
||||
*
|
||||
* <pre>
|
||||
* optional bytes verification = 6;
|
||||
* </pre>
|
||||
*/
|
||||
boolean hasBaseKeySignature();
|
||||
/**
|
||||
* <code>optional bytes baseKeySignature = 5;</code>
|
||||
*
|
||||
* <pre>
|
||||
* optional bytes verification = 6;
|
||||
* </pre>
|
||||
*/
|
||||
com.google.protobuf.ByteString getBaseKeySignature();
|
||||
}
|
||||
@ -1825,20 +1733,12 @@ public final class WhisperProtos {
|
||||
private com.google.protobuf.ByteString baseKeySignature_;
|
||||
/**
|
||||
* <code>optional bytes baseKeySignature = 5;</code>
|
||||
*
|
||||
* <pre>
|
||||
* optional bytes verification = 6;
|
||||
* </pre>
|
||||
*/
|
||||
public boolean hasBaseKeySignature() {
|
||||
return ((bitField0_ & 0x00000010) == 0x00000010);
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes baseKeySignature = 5;</code>
|
||||
*
|
||||
* <pre>
|
||||
* optional bytes verification = 6;
|
||||
* </pre>
|
||||
*/
|
||||
public com.google.protobuf.ByteString getBaseKeySignature() {
|
||||
return baseKeySignature_;
|
||||
@ -2284,30 +2184,18 @@ public final class WhisperProtos {
|
||||
private com.google.protobuf.ByteString baseKeySignature_ = com.google.protobuf.ByteString.EMPTY;
|
||||
/**
|
||||
* <code>optional bytes baseKeySignature = 5;</code>
|
||||
*
|
||||
* <pre>
|
||||
* optional bytes verification = 6;
|
||||
* </pre>
|
||||
*/
|
||||
public boolean hasBaseKeySignature() {
|
||||
return ((bitField0_ & 0x00000010) == 0x00000010);
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes baseKeySignature = 5;</code>
|
||||
*
|
||||
* <pre>
|
||||
* optional bytes verification = 6;
|
||||
* </pre>
|
||||
*/
|
||||
public com.google.protobuf.ByteString getBaseKeySignature() {
|
||||
return baseKeySignature_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes baseKeySignature = 5;</code>
|
||||
*
|
||||
* <pre>
|
||||
* optional bytes verification = 6;
|
||||
* </pre>
|
||||
*/
|
||||
public Builder setBaseKeySignature(com.google.protobuf.ByteString value) {
|
||||
if (value == null) {
|
||||
@ -2320,10 +2208,6 @@ public final class WhisperProtos {
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes baseKeySignature = 5;</code>
|
||||
*
|
||||
* <pre>
|
||||
* optional bytes verification = 6;
|
||||
* </pre>
|
||||
*/
|
||||
public Builder clearBaseKeySignature() {
|
||||
bitField0_ = (bitField0_ & ~0x00000010);
|
||||
@ -2370,16 +2254,15 @@ public final class WhisperProtos {
|
||||
"\n\031WhisperTextProtocol.proto\022\ntextsecure\"" +
|
||||
"b\n\016WhisperMessage\022\022\n\nratchetKey\030\001 \001(\014\022\017\n" +
|
||||
"\007counter\030\002 \001(\r\022\027\n\017previousCounter\030\003 \001(\r\022" +
|
||||
"\022\n\nciphertext\030\004 \001(\014\"\245\001\n\024PreKeyWhisperMes" +
|
||||
"\022\n\nciphertext\030\004 \001(\014\"\217\001\n\024PreKeyWhisperMes" +
|
||||
"sage\022\026\n\016registrationId\030\005 \001(\r\022\020\n\010preKeyId" +
|
||||
"\030\001 \001(\r\022\026\n\016signedPreKeyId\030\006 \001(\r\022\017\n\007baseKe" +
|
||||
"y\030\002 \001(\014\022\023\n\013identityKey\030\003 \001(\014\022\024\n\014verifica" +
|
||||
"tion\030\007 \001(\014\022\017\n\007message\030\004 \001(\014\"t\n\022KeyExchan" +
|
||||
"geMessage\022\n\n\002id\030\001 \001(\r\022\017\n\007baseKey\030\002 \001(\014\022\022" +
|
||||
"\n\nratchetKey\030\003 \001(\014\022\023\n\013identityKey\030\004 \001(\014\022",
|
||||
"\030\n\020baseKeySignature\030\005 \001(\014B7\n&org.whisper" +
|
||||
"systems.libaxolotl.protocolB\rWhisperProt" +
|
||||
"os"
|
||||
"y\030\002 \001(\014\022\023\n\013identityKey\030\003 \001(\014\022\017\n\007message\030" +
|
||||
"\004 \001(\014\"t\n\022KeyExchangeMessage\022\n\n\002id\030\001 \001(\r\022" +
|
||||
"\017\n\007baseKey\030\002 \001(\014\022\022\n\nratchetKey\030\003 \001(\014\022\023\n\013" +
|
||||
"identityKey\030\004 \001(\014\022\030\n\020baseKeySignature\030\005 ",
|
||||
"\001(\014B7\n&org.whispersystems.libaxolotl.pro" +
|
||||
"tocolB\rWhisperProtos"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
@ -2397,7 +2280,7 @@ public final class WhisperProtos {
|
||||
internal_static_textsecure_PreKeyWhisperMessage_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_textsecure_PreKeyWhisperMessage_descriptor,
|
||||
new java.lang.String[] { "RegistrationId", "PreKeyId", "SignedPreKeyId", "BaseKey", "IdentityKey", "Verification", "Message", });
|
||||
new java.lang.String[] { "RegistrationId", "PreKeyId", "SignedPreKeyId", "BaseKey", "IdentityKey", "Message", });
|
||||
internal_static_textsecure_KeyExchangeMessage_descriptor =
|
||||
getDescriptor().getMessageTypes().get(2);
|
||||
internal_static_textsecure_KeyExchangeMessage_fieldAccessorTable = new
|
||||
|
@ -28,7 +28,6 @@ import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RatchetingSession {
|
||||
@ -98,11 +97,6 @@ public class RatchetingSession {
|
||||
sessionState.addReceiverChain(parameters.getTheirRatchetKey(), derivedKeys.getChainKey());
|
||||
sessionState.setSenderChain(sendingRatchetKey, sendingChain.second());
|
||||
sessionState.setRootKey(sendingChain.first());
|
||||
|
||||
if (sessionVersion >= 3) {
|
||||
sessionState.setVerification(calculateVerificationTag(derivedKeys.getVerifyKey(), parameters));
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
@ -141,39 +135,11 @@ public class RatchetingSession {
|
||||
|
||||
sessionState.setSenderChain(parameters.getOurRatchetKey(), derivedKeys.getChainKey());
|
||||
sessionState.setRootKey(derivedKeys.getRootKey());
|
||||
|
||||
if (sessionVersion >= 3) {
|
||||
sessionState.setVerification(calculateVerificationTag(derivedKeys.getVerifyKey(), parameters));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] calculateVerificationTag(VerifyKey verifyKey, AliceAxolotlParameters parameters) {
|
||||
return verifyKey.generateVerification(parameters.getOurIdentityKey().getPublicKey(),
|
||||
parameters.getTheirIdentityKey(),
|
||||
parameters.getOurBaseKey().getPublicKey(),
|
||||
parameters.getTheirSignedPreKey(),
|
||||
parameters.getTheirOneTimePreKey());
|
||||
}
|
||||
|
||||
private static byte[] calculateVerificationTag(VerifyKey verifyKey, BobAxolotlParameters parameters) {
|
||||
Optional<ECPublicKey> ourOneTimePreKey;
|
||||
|
||||
if (parameters.getOurOneTimePreKey().isPresent()) {
|
||||
ourOneTimePreKey = Optional.of(parameters.getOurOneTimePreKey().get().getPublicKey());
|
||||
} else {
|
||||
ourOneTimePreKey = Optional.absent();
|
||||
}
|
||||
|
||||
return verifyKey.generateVerification(parameters.getTheirIdentityKey(),
|
||||
parameters.getOurIdentityKey().getPublicKey(),
|
||||
parameters.getTheirBaseKey(),
|
||||
parameters.getOurSignedPreKey().getPublicKey(),
|
||||
ourOneTimePreKey);
|
||||
}
|
||||
|
||||
private static byte[] getDiscontinuityBytes() {
|
||||
byte[] discontinuity = new byte[32];
|
||||
Arrays.fill(discontinuity, (byte) 0xFF);
|
||||
@ -181,33 +147,25 @@ public class RatchetingSession {
|
||||
}
|
||||
|
||||
private static DerivedKeys calculateDerivedKeys(int sessionVersion, byte[] masterSecret) {
|
||||
try {
|
||||
HKDF kdf = HKDF.createFor(sessionVersion);
|
||||
byte[] derivedSecretBytes = kdf.deriveSecrets(masterSecret, "WhisperText".getBytes(), 96);
|
||||
byte[][] derivedSecrets = ByteUtil.split(derivedSecretBytes, 32, 32, 32);
|
||||
HKDF kdf = HKDF.createFor(sessionVersion);
|
||||
byte[] derivedSecretBytes = kdf.deriveSecrets(masterSecret, "WhisperText".getBytes(), 64);
|
||||
byte[][] derivedSecrets = ByteUtil.split(derivedSecretBytes, 32, 32);
|
||||
|
||||
return new DerivedKeys(new RootKey(kdf, derivedSecrets[0]),
|
||||
new ChainKey(kdf, derivedSecrets[1], 0),
|
||||
new VerifyKey(derivedSecrets[2]));
|
||||
} catch (ParseException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return new DerivedKeys(new RootKey(kdf, derivedSecrets[0]),
|
||||
new ChainKey(kdf, derivedSecrets[1], 0));
|
||||
}
|
||||
|
||||
private static boolean isAlice(ECPublicKey ourKey, ECPublicKey theirKey) {
|
||||
return ourKey.compareTo(theirKey) < 0;
|
||||
}
|
||||
|
||||
|
||||
private static class DerivedKeys {
|
||||
private final RootKey rootKey;
|
||||
private final ChainKey chainKey;
|
||||
private final VerifyKey verifyKey;
|
||||
|
||||
private DerivedKeys(RootKey rootKey, ChainKey chainKey, VerifyKey verifyKey) {
|
||||
private DerivedKeys(RootKey rootKey, ChainKey chainKey) {
|
||||
this.rootKey = rootKey;
|
||||
this.chainKey = chainKey;
|
||||
this.verifyKey = verifyKey;
|
||||
}
|
||||
|
||||
public RootKey getRootKey() {
|
||||
@ -217,9 +175,5 @@ public class RatchetingSession {
|
||||
public ChainKey getChainKey() {
|
||||
return chainKey;
|
||||
}
|
||||
|
||||
public VerifyKey getVerifyKey() {
|
||||
return verifyKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
package org.whispersystems.libaxolotl.ratchet;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.util.ByteUtil;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class VerifyKey {
|
||||
|
||||
private static final byte[] VERIFICATION_INFO = "TextSecure Verification Tag".getBytes();
|
||||
|
||||
private final byte[] key;
|
||||
|
||||
public VerifyKey(byte[] key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public byte[] getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public byte[] generateVerification(IdentityKey aliceIdentity,
|
||||
IdentityKey bobIdentity,
|
||||
ECPublicKey aliceBaseKey,
|
||||
ECPublicKey bobSignedPreKey,
|
||||
Optional<ECPublicKey> bobOneTimePreKey)
|
||||
{
|
||||
try {
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(new SecretKeySpec(key, "HmacSHA256"));
|
||||
|
||||
mac.update(VERIFICATION_INFO);
|
||||
mac.update(aliceIdentity.getPublicKey().serialize());
|
||||
mac.update(bobIdentity.getPublicKey().serialize());
|
||||
mac.update(aliceBaseKey.serialize());
|
||||
mac.update(bobSignedPreKey.serialize());
|
||||
|
||||
if (bobOneTimePreKey.isPresent()) {
|
||||
mac.update(bobOneTimePreKey.get().serialize());
|
||||
}
|
||||
|
||||
return ByteUtil.trim(mac.doFinal(), 8);
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -61,16 +61,6 @@ public class SessionState {
|
||||
return sessionStructure;
|
||||
}
|
||||
|
||||
public byte[] getVerification() {
|
||||
return this.sessionStructure.getVerification().toByteArray();
|
||||
}
|
||||
|
||||
public void setVerification(byte[] verification) {
|
||||
this.sessionStructure = this.sessionStructure.toBuilder()
|
||||
.setVerification(ByteString.copyFrom(verification))
|
||||
.build();
|
||||
}
|
||||
|
||||
public byte[] getAliceBaseKey() {
|
||||
return this.sessionStructure.getAliceBaseKey().toByteArray();
|
||||
}
|
||||
|
@ -167,16 +167,6 @@ public final class StorageProtos {
|
||||
* <code>optional bytes aliceBaseKey = 13;</code>
|
||||
*/
|
||||
com.google.protobuf.ByteString getAliceBaseKey();
|
||||
|
||||
// optional bytes verification = 14;
|
||||
/**
|
||||
* <code>optional bytes verification = 14;</code>
|
||||
*/
|
||||
boolean hasVerification();
|
||||
/**
|
||||
* <code>optional bytes verification = 14;</code>
|
||||
*/
|
||||
com.google.protobuf.ByteString getVerification();
|
||||
}
|
||||
/**
|
||||
* Protobuf type {@code textsecure.SessionStructure}
|
||||
@ -321,11 +311,6 @@ public final class StorageProtos {
|
||||
aliceBaseKey_ = input.readBytes();
|
||||
break;
|
||||
}
|
||||
case 114: {
|
||||
bitField0_ |= 0x00001000;
|
||||
verification_ = input.readBytes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
|
||||
@ -4157,22 +4142,6 @@ public final class StorageProtos {
|
||||
return aliceBaseKey_;
|
||||
}
|
||||
|
||||
// optional bytes verification = 14;
|
||||
public static final int VERIFICATION_FIELD_NUMBER = 14;
|
||||
private com.google.protobuf.ByteString verification_;
|
||||
/**
|
||||
* <code>optional bytes verification = 14;</code>
|
||||
*/
|
||||
public boolean hasVerification() {
|
||||
return ((bitField0_ & 0x00001000) == 0x00001000);
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes verification = 14;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString getVerification() {
|
||||
return verification_;
|
||||
}
|
||||
|
||||
private void initFields() {
|
||||
sessionVersion_ = 0;
|
||||
localIdentityPublic_ = com.google.protobuf.ByteString.EMPTY;
|
||||
@ -4187,7 +4156,6 @@ public final class StorageProtos {
|
||||
localRegistrationId_ = 0;
|
||||
needsRefresh_ = false;
|
||||
aliceBaseKey_ = com.google.protobuf.ByteString.EMPTY;
|
||||
verification_ = com.google.protobuf.ByteString.EMPTY;
|
||||
}
|
||||
private byte memoizedIsInitialized = -1;
|
||||
public final boolean isInitialized() {
|
||||
@ -4240,9 +4208,6 @@ public final class StorageProtos {
|
||||
if (((bitField0_ & 0x00000800) == 0x00000800)) {
|
||||
output.writeBytes(13, aliceBaseKey_);
|
||||
}
|
||||
if (((bitField0_ & 0x00001000) == 0x00001000)) {
|
||||
output.writeBytes(14, verification_);
|
||||
}
|
||||
getUnknownFields().writeTo(output);
|
||||
}
|
||||
|
||||
@ -4304,10 +4269,6 @@ public final class StorageProtos {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBytesSize(13, aliceBaseKey_);
|
||||
}
|
||||
if (((bitField0_ & 0x00001000) == 0x00001000)) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeBytesSize(14, verification_);
|
||||
}
|
||||
size += getUnknownFields().getSerializedSize();
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
@ -4470,8 +4431,6 @@ public final class StorageProtos {
|
||||
bitField0_ = (bitField0_ & ~0x00000800);
|
||||
aliceBaseKey_ = com.google.protobuf.ByteString.EMPTY;
|
||||
bitField0_ = (bitField0_ & ~0x00001000);
|
||||
verification_ = com.google.protobuf.ByteString.EMPTY;
|
||||
bitField0_ = (bitField0_ & ~0x00002000);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -4569,10 +4528,6 @@ public final class StorageProtos {
|
||||
to_bitField0_ |= 0x00000800;
|
||||
}
|
||||
result.aliceBaseKey_ = aliceBaseKey_;
|
||||
if (((from_bitField0_ & 0x00002000) == 0x00002000)) {
|
||||
to_bitField0_ |= 0x00001000;
|
||||
}
|
||||
result.verification_ = verification_;
|
||||
result.bitField0_ = to_bitField0_;
|
||||
onBuilt();
|
||||
return result;
|
||||
@ -4651,9 +4606,6 @@ public final class StorageProtos {
|
||||
if (other.hasAliceBaseKey()) {
|
||||
setAliceBaseKey(other.getAliceBaseKey());
|
||||
}
|
||||
if (other.hasVerification()) {
|
||||
setVerification(other.getVerification());
|
||||
}
|
||||
this.mergeUnknownFields(other.getUnknownFields());
|
||||
return this;
|
||||
}
|
||||
@ -5581,42 +5533,6 @@ public final class StorageProtos {
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional bytes verification = 14;
|
||||
private com.google.protobuf.ByteString verification_ = com.google.protobuf.ByteString.EMPTY;
|
||||
/**
|
||||
* <code>optional bytes verification = 14;</code>
|
||||
*/
|
||||
public boolean hasVerification() {
|
||||
return ((bitField0_ & 0x00002000) == 0x00002000);
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes verification = 14;</code>
|
||||
*/
|
||||
public com.google.protobuf.ByteString getVerification() {
|
||||
return verification_;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes verification = 14;</code>
|
||||
*/
|
||||
public Builder setVerification(com.google.protobuf.ByteString value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
bitField0_ |= 0x00002000;
|
||||
verification_ = value;
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <code>optional bytes verification = 14;</code>
|
||||
*/
|
||||
public Builder clearVerification() {
|
||||
bitField0_ = (bitField0_ & ~0x00002000);
|
||||
verification_ = getDefaultInstance().getVerification();
|
||||
onChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:textsecure.SessionStructure)
|
||||
}
|
||||
|
||||
@ -8333,7 +8249,7 @@ public final class StorageProtos {
|
||||
static {
|
||||
java.lang.String[] descriptorData = {
|
||||
"\n\032LocalStorageProtocol.proto\022\ntextsecure" +
|
||||
"\"\335\010\n\020SessionStructure\022\026\n\016sessionVersion\030" +
|
||||
"\"\307\010\n\020SessionStructure\022\026\n\016sessionVersion\030" +
|
||||
"\001 \001(\r\022\033\n\023localIdentityPublic\030\002 \001(\014\022\034\n\024re" +
|
||||
"moteIdentityPublic\030\003 \001(\014\022\017\n\007rootKey\030\004 \001(" +
|
||||
"\014\022\027\n\017previousCounter\030\005 \001(\r\0227\n\013senderChai" +
|
||||
@ -8345,34 +8261,33 @@ public final class StorageProtos {
|
||||
"\001(\0132*.textsecure.SessionStructure.Pendin" +
|
||||
"gPreKey\022\034\n\024remoteRegistrationId\030\n \001(\r\022\033\n" +
|
||||
"\023localRegistrationId\030\013 \001(\r\022\024\n\014needsRefre" +
|
||||
"sh\030\014 \001(\010\022\024\n\014aliceBaseKey\030\r \001(\014\022\024\n\014verifi" +
|
||||
"cation\030\016 \001(\014\032\255\002\n\005Chain\022\030\n\020senderRatchetK" +
|
||||
"ey\030\001 \001(\014\022\037\n\027senderRatchetKeyPrivate\030\002 \001(" +
|
||||
"\014\022=\n\010chainKey\030\003 \001(\0132+.textsecure.Session" +
|
||||
"Structure.Chain.ChainKey\022B\n\013messageKeys\030" +
|
||||
"\004 \003(\0132-.textsecure.SessionStructure.Chai" +
|
||||
"n.MessageKey\032&\n\010ChainKey\022\r\n\005index\030\001 \001(\r\022",
|
||||
"\013\n\003key\030\002 \001(\014\032>\n\nMessageKey\022\r\n\005index\030\001 \001(" +
|
||||
"\r\022\021\n\tcipherKey\030\002 \001(\014\022\016\n\006macKey\030\003 \001(\014\032\315\001\n" +
|
||||
"\022PendingKeyExchange\022\020\n\010sequence\030\001 \001(\r\022\024\n" +
|
||||
"\014localBaseKey\030\002 \001(\014\022\033\n\023localBaseKeyPriva" +
|
||||
"te\030\003 \001(\014\022\027\n\017localRatchetKey\030\004 \001(\014\022\036\n\026loc" +
|
||||
"alRatchetKeyPrivate\030\005 \001(\014\022\030\n\020localIdenti" +
|
||||
"tyKey\030\007 \001(\014\022\037\n\027localIdentityKeyPrivate\030\010" +
|
||||
" \001(\014\032J\n\rPendingPreKey\022\020\n\010preKeyId\030\001 \001(\r\022" +
|
||||
"\026\n\016signedPreKeyId\030\003 \001(\005\022\017\n\007baseKey\030\002 \001(\014" +
|
||||
"\"\177\n\017RecordStructure\0224\n\016currentSession\030\001 ",
|
||||
"\001(\0132\034.textsecure.SessionStructure\0226\n\020pre" +
|
||||
"viousSessions\030\002 \003(\0132\034.textsecure.Session" +
|
||||
"Structure\"J\n\025PreKeyRecordStructure\022\n\n\002id" +
|
||||
"\030\001 \001(\r\022\021\n\tpublicKey\030\002 \001(\014\022\022\n\nprivateKey\030" +
|
||||
"\003 \001(\014\"v\n\033SignedPreKeyRecordStructure\022\n\n\002" +
|
||||
"id\030\001 \001(\r\022\021\n\tpublicKey\030\002 \001(\014\022\022\n\nprivateKe" +
|
||||
"y\030\003 \001(\014\022\021\n\tsignature\030\004 \001(\014\022\021\n\ttimestamp\030" +
|
||||
"\005 \001(\006\"A\n\030IdentityKeyPairStructure\022\021\n\tpub" +
|
||||
"licKey\030\001 \001(\014\022\022\n\nprivateKey\030\002 \001(\014B4\n#org." +
|
||||
"whispersystems.libaxolotl.stateB\rStorage",
|
||||
"Protos"
|
||||
"sh\030\014 \001(\010\022\024\n\014aliceBaseKey\030\r \001(\014\032\255\002\n\005Chain" +
|
||||
"\022\030\n\020senderRatchetKey\030\001 \001(\014\022\037\n\027senderRatc" +
|
||||
"hetKeyPrivate\030\002 \001(\014\022=\n\010chainKey\030\003 \001(\0132+." +
|
||||
"textsecure.SessionStructure.Chain.ChainK" +
|
||||
"ey\022B\n\013messageKeys\030\004 \003(\0132-.textsecure.Ses" +
|
||||
"sionStructure.Chain.MessageKey\032&\n\010ChainK" +
|
||||
"ey\022\r\n\005index\030\001 \001(\r\022\013\n\003key\030\002 \001(\014\032>\n\nMessag",
|
||||
"eKey\022\r\n\005index\030\001 \001(\r\022\021\n\tcipherKey\030\002 \001(\014\022\016" +
|
||||
"\n\006macKey\030\003 \001(\014\032\315\001\n\022PendingKeyExchange\022\020\n" +
|
||||
"\010sequence\030\001 \001(\r\022\024\n\014localBaseKey\030\002 \001(\014\022\033\n" +
|
||||
"\023localBaseKeyPrivate\030\003 \001(\014\022\027\n\017localRatch" +
|
||||
"etKey\030\004 \001(\014\022\036\n\026localRatchetKeyPrivate\030\005 " +
|
||||
"\001(\014\022\030\n\020localIdentityKey\030\007 \001(\014\022\037\n\027localId" +
|
||||
"entityKeyPrivate\030\010 \001(\014\032J\n\rPendingPreKey\022" +
|
||||
"\020\n\010preKeyId\030\001 \001(\r\022\026\n\016signedPreKeyId\030\003 \001(" +
|
||||
"\005\022\017\n\007baseKey\030\002 \001(\014\"\177\n\017RecordStructure\0224\n" +
|
||||
"\016currentSession\030\001 \001(\0132\034.textsecure.Sessi",
|
||||
"onStructure\0226\n\020previousSessions\030\002 \003(\0132\034." +
|
||||
"textsecure.SessionStructure\"J\n\025PreKeyRec" +
|
||||
"ordStructure\022\n\n\002id\030\001 \001(\r\022\021\n\tpublicKey\030\002 " +
|
||||
"\001(\014\022\022\n\nprivateKey\030\003 \001(\014\"v\n\033SignedPreKeyR" +
|
||||
"ecordStructure\022\n\n\002id\030\001 \001(\r\022\021\n\tpublicKey\030" +
|
||||
"\002 \001(\014\022\022\n\nprivateKey\030\003 \001(\014\022\021\n\tsignature\030\004" +
|
||||
" \001(\014\022\021\n\ttimestamp\030\005 \001(\006\"A\n\030IdentityKeyPa" +
|
||||
"irStructure\022\021\n\tpublicKey\030\001 \001(\014\022\022\n\nprivat" +
|
||||
"eKey\030\002 \001(\014B4\n#org.whispersystems.libaxol" +
|
||||
"otl.stateB\rStorageProtos"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
@ -8384,7 +8299,7 @@ public final class StorageProtos {
|
||||
internal_static_textsecure_SessionStructure_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_textsecure_SessionStructure_descriptor,
|
||||
new java.lang.String[] { "SessionVersion", "LocalIdentityPublic", "RemoteIdentityPublic", "RootKey", "PreviousCounter", "SenderChain", "ReceiverChains", "PendingKeyExchange", "PendingPreKey", "RemoteRegistrationId", "LocalRegistrationId", "NeedsRefresh", "AliceBaseKey", "Verification", });
|
||||
new java.lang.String[] { "SessionVersion", "LocalIdentityPublic", "RemoteIdentityPublic", "RootKey", "PreviousCounter", "SenderChain", "ReceiverChains", "PendingKeyExchange", "PendingPreKey", "RemoteRegistrationId", "LocalRegistrationId", "NeedsRefresh", "AliceBaseKey", });
|
||||
internal_static_textsecure_SessionStructure_Chain_descriptor =
|
||||
internal_static_textsecure_SessionStructure_descriptor.getNestedTypes().get(0);
|
||||
internal_static_textsecure_SessionStructure_Chain_fieldAccessorTable = new
|
||||
|
Loading…
x
Reference in New Issue
Block a user