Move prekey jsonifcation into the push code, add identity key.

This commit is contained in:
Moxie Marlinspike
2013-08-17 19:06:04 -07:00
parent b8f663b69c
commit 499de2d2bf
11 changed files with 134 additions and 65 deletions

View File

@@ -65,22 +65,6 @@ public class PreKeyUtil {
}
}
public static PreKeyList toJson(List<PreKeyRecord> records) {
List<String> encoded = new LinkedList<String>();
for (PreKeyRecord record : records) {
PreKeyEntity entity = PreKeyEntity.newBuilder().setId(record.getId())
.setKey(ByteString.copyFrom(KeyUtil.encodePoint(record.getKeyPair().getPublicKey().getQ())))
.build();
String encodedEntity = Base64.encodeBytesWithoutPadding(entity.toByteArray());
encoded.add(encodedEntity);
}
return new PreKeyList(encoded);
}
private static long getNextPreKeyId(Context context) {
try {
File directory = getPreKeysDirectory(context);

View File

@@ -22,7 +22,7 @@ import android.util.Log;
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
import org.spongycastle.crypto.agreement.ECDHBasicAgreement;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.whispersystems.textsecure.protocol.Message;
import org.whispersystems.textsecure.crypto.protocol.Message;
import org.whispersystems.textsecure.storage.CanonicalRecipientAddress;
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
import org.whispersystems.textsecure.storage.LocalKeyRecord;

View File

@@ -0,0 +1,151 @@
/**
* Copyright (C) 2011 Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecure.crypto.protocol;
import android.util.Log;
import org.whispersystems.textsecure.crypto.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidMessageException;
import org.whispersystems.textsecure.crypto.PublicKey;
import org.whispersystems.textsecure.util.Conversions;
import java.nio.ByteBuffer;
/**
* Parses and serializes the encrypted message format.
*
* @author Moxie Marlinspike
*/
public class Message {
public static final int SUPPORTED_VERSION = 1;
private static final int VERSION_LENGTH = 1;
private static final int SENDER_KEY_ID_LENGTH = 3;
private static final int RECEIVER_KEY_ID_LENGTH = 3;
private static final int NEXT_KEY_LENGTH = PublicKey.KEY_SIZE;
private static final int COUNTER_LENGTH = 3;
public static final int HEADER_LENGTH = VERSION_LENGTH + SENDER_KEY_ID_LENGTH + RECEIVER_KEY_ID_LENGTH + COUNTER_LENGTH + NEXT_KEY_LENGTH;
private static final int VERSION_OFFSET = 0;
private static final int SENDER_KEY_ID_OFFSET = VERSION_OFFSET + VERSION_LENGTH;
private static final int RECEIVER_KEY_ID_OFFSET = SENDER_KEY_ID_OFFSET + SENDER_KEY_ID_LENGTH;
private static final int NEXT_KEY_OFFSET = RECEIVER_KEY_ID_OFFSET + RECEIVER_KEY_ID_LENGTH;
private static final int COUNTER_OFFSET = NEXT_KEY_OFFSET + NEXT_KEY_LENGTH;
private static final int TEXT_OFFSET = COUNTER_OFFSET + COUNTER_LENGTH;
private int senderKeyId;
private int receiverKeyId;
private int counter;
private int messageVersion;
private int supportedVersion;
private byte[] message;
private PublicKey nextKey;
public Message(int senderKeyId, int receiverKeyId, PublicKey nextKey, int counter, byte[] message, int messageVersion, int supportedVersion) {
this.senderKeyId = senderKeyId;
this.receiverKeyId = receiverKeyId;
this.nextKey = nextKey;
this.counter = counter;
this.message = message;
this.messageVersion = messageVersion;
this.supportedVersion = supportedVersion;
}
public Message(byte[] messageBytes) throws InvalidMessageException {
try {
if (messageBytes.length <= HEADER_LENGTH)
throw new InvalidMessageException("Message is shorter than headers.");
this.messageVersion = Conversions.highBitsToInt(messageBytes[VERSION_OFFSET]);
this.supportedVersion = Conversions.lowBitsToInt(messageBytes[VERSION_OFFSET]);
Log.w("Message", "Message Version: " + messageVersion);
Log.w("Message", "Supported Version: " + supportedVersion);
if (messageVersion > SUPPORTED_VERSION)
throw new InvalidMessageException("Message protocol version not supported: " + messageVersion);
this.senderKeyId = Conversions.byteArrayToMedium(messageBytes, SENDER_KEY_ID_OFFSET);
this.receiverKeyId = Conversions.byteArrayToMedium(messageBytes, RECEIVER_KEY_ID_OFFSET);
this.counter = Conversions.byteArrayToMedium(messageBytes, COUNTER_OFFSET);
Log.w("Message", "Parsed current version: " + messageVersion + " supported version: " + supportedVersion);
byte[] nextKeyBytes = new byte[NEXT_KEY_LENGTH];
byte[] textBytes = new byte[messageBytes.length - HEADER_LENGTH];
System.arraycopy(messageBytes, NEXT_KEY_OFFSET, nextKeyBytes, 0, nextKeyBytes.length);
System.arraycopy(messageBytes, TEXT_OFFSET, textBytes, 0, textBytes.length);
Log.w("Message", "Pulling next key out of message...");
this.nextKey = new PublicKey(nextKeyBytes);
this.message = textBytes;
} catch (InvalidKeyException ike) {
throw new AssertionError(ike);
}
}
public byte[] serialize() {
ByteBuffer buffer = ByteBuffer.allocate(HEADER_LENGTH + message.length);
Log.w("Message", "Constructing Message Version: (" + messageVersion + "," + supportedVersion + ")");
byte versionByte = Conversions.intsToByteHighAndLow(messageVersion, supportedVersion);
byte[] senderKeyIdBytes = Conversions.mediumToByteArray(senderKeyId);
byte[] receiverKeyIdBytes = Conversions.mediumToByteArray(receiverKeyId);
Log.w("Message", "Serializing next key into message...");
byte[] nextKeyBytes = nextKey.serialize();
byte[] counterBytes = Conversions.mediumToByteArray(counter);
buffer.put(versionByte);
buffer.put(senderKeyIdBytes);
buffer.put(receiverKeyIdBytes);
buffer.put(nextKeyBytes);
buffer.put(counterBytes);
buffer.put(message);
return buffer.array();
}
public int getHighestMutuallySupportedVersion() {
return Math.min(SUPPORTED_VERSION, this.supportedVersion);
}
public int getSenderKeyId() {
return this.senderKeyId;
}
public int getReceiverKeyId() {
return this.receiverKeyId;
}
public PublicKey getNextKey() {
return this.nextKey;
}
public int getCounter() {
return this.counter;
}
public byte[] getMessageText() {
return this.message;
}
}