Signal-Android/src/org/thoughtcrime/securesms/protocol/Message.java

152 lines
5.6 KiB
Java
Raw Normal View History

2012-09-30 19:56:29 -07:00
/**
2011-12-20 10:20:44 -08:00
* Copyright (C) 2011 Whisper Systems
2012-09-30 19:56:29 -07:00
*
2011-12-20 10:20:44 -08:00
* 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.
2012-09-30 19:56:29 -07:00
*
2011-12-20 10:20:44 -08:00
* 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.thoughtcrime.securesms.protocol;
2012-09-30 19:56:29 -07:00
import android.util.Log;
2011-12-20 10:20:44 -08:00
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
import org.thoughtcrime.securesms.crypto.InvalidMessageException;
import org.thoughtcrime.securesms.crypto.PublicKey;
import org.thoughtcrime.securesms.util.Conversions;
2012-09-30 19:56:29 -07:00
import java.nio.ByteBuffer;
2011-12-20 10:20:44 -08:00
/**
* Parses and serializes the encrypted message format.
2012-09-30 19:56:29 -07:00
*
2011-12-20 10:20:44 -08:00
* @author Moxie Marlinspike
*/
public class Message {
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public static final int SUPPORTED_VERSION = 1;
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
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;
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
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;
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
private PublicKey nextKey;
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
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;
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public Message(byte[] messageBytes) throws InvalidMessageException {
try {
if (messageBytes.length <= HEADER_LENGTH)
throw new InvalidMessageException("Message is shorter than headers.");
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
this.messageVersion = Conversions.highBitsToInt(messageBytes[VERSION_OFFSET]);
this.supportedVersion = Conversions.lowBitsToInt(messageBytes[VERSION_OFFSET]);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
Log.w("Message", "Message Version: " + messageVersion);
Log.w("Message", "Supported Version: " + supportedVersion);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
if (messageVersion > SUPPORTED_VERSION)
throw new InvalidMessageException("Message protocol version not supported: " + messageVersion);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
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);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
Log.w("Message", "Parsed current version: " + messageVersion + " supported version: " + supportedVersion);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
byte[] nextKeyBytes = new byte[NEXT_KEY_LENGTH];
byte[] textBytes = new byte[messageBytes.length - HEADER_LENGTH];
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
System.arraycopy(messageBytes, NEXT_KEY_OFFSET, nextKeyBytes, 0, nextKeyBytes.length);
System.arraycopy(messageBytes, TEXT_OFFSET, textBytes, 0, textBytes.length);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
Log.w("Message", "Pulling next key out of message...");
this.nextKey = new PublicKey(nextKeyBytes);
this.message = textBytes;
} catch (InvalidKeyException ike) {
throw new AssertionError(ike);
}
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public byte[] serialize() {
ByteBuffer buffer = ByteBuffer.allocate(HEADER_LENGTH + message.length);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
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);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
buffer.put(versionByte);
buffer.put(senderKeyIdBytes);
buffer.put(receiverKeyIdBytes);
buffer.put(nextKeyBytes);
buffer.put(counterBytes);
buffer.put(message);
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
return buffer.array();
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public int getHighestMutuallySupportedVersion() {
return Math.min(SUPPORTED_VERSION, this.supportedVersion);
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public int getSenderKeyId() {
return this.senderKeyId;
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public int getReceiverKeyId() {
return this.receiverKeyId;
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public PublicKey getNextKey() {
return this.nextKey;
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public int getCounter() {
return this.counter;
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
public byte[] getMessageText() {
return this.message;
}
2012-09-30 19:56:29 -07:00
2011-12-20 10:20:44 -08:00
}