mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-26 04:33:36 +00:00
1) Split code into v1 and v2 message paths. 2) Do the Axolotl protocol for v2. 3) Switch all v2 entities to protobuf.
116 lines
3.8 KiB
Java
116 lines
3.8 KiB
Java
/**
|
|
* 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.storage;
|
|
|
|
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
|
import org.whispersystems.textsecure.crypto.MasterCipher;
|
|
import org.whispersystems.textsecure.crypto.MasterSecret;
|
|
import org.whispersystems.textsecure.crypto.kdf.NKDF;
|
|
import org.whispersystems.textsecure.util.Conversions;
|
|
import org.whispersystems.textsecure.util.Util;
|
|
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
/**
|
|
* Represents the currently negotiated session key for a given
|
|
* local key id and remote key id. This is stored encrypted on
|
|
* disk.
|
|
*
|
|
* @author Moxie Marlinspike
|
|
*/
|
|
|
|
public class SessionKey {
|
|
|
|
private int mode;
|
|
private int localKeyId;
|
|
private int remoteKeyId;
|
|
private SecretKeySpec cipherKey;
|
|
private SecretKeySpec macKey;
|
|
private MasterCipher masterCipher;
|
|
|
|
public SessionKey(int mode, int localKeyId, int remoteKeyId,
|
|
SecretKeySpec cipherKey, SecretKeySpec macKey,
|
|
MasterSecret masterSecret)
|
|
{
|
|
this.mode = mode;
|
|
this.localKeyId = localKeyId;
|
|
this.remoteKeyId = remoteKeyId;
|
|
this.cipherKey = cipherKey;
|
|
this.macKey = macKey;
|
|
this.masterCipher = new MasterCipher(masterSecret);
|
|
}
|
|
|
|
public SessionKey(byte[] bytes, MasterSecret masterSecret) throws InvalidMessageException {
|
|
this.masterCipher = new MasterCipher(masterSecret);
|
|
deserialize(bytes);
|
|
}
|
|
|
|
public byte[] serialize() {
|
|
byte[] localKeyIdBytes = Conversions.mediumToByteArray(localKeyId);
|
|
byte[] remoteKeyIdBytes = Conversions.mediumToByteArray(remoteKeyId);
|
|
byte[] cipherKeyBytes = cipherKey.getEncoded();
|
|
byte[] macKeyBytes = macKey.getEncoded();
|
|
byte[] modeBytes = {(byte)mode};
|
|
byte[] combined = Util.combine(localKeyIdBytes, remoteKeyIdBytes,
|
|
cipherKeyBytes, macKeyBytes, modeBytes);
|
|
|
|
return masterCipher.encryptBytes(combined);
|
|
}
|
|
|
|
private void deserialize(byte[] bytes) throws InvalidMessageException {
|
|
byte[] decrypted = masterCipher.decryptBytes(bytes);
|
|
|
|
this.localKeyId = Conversions.byteArrayToMedium(decrypted, 0);
|
|
this.remoteKeyId = Conversions.byteArrayToMedium(decrypted, 3);
|
|
|
|
byte[] keyBytes = new byte[NKDF.LEGACY_CIPHER_KEY_LENGTH];
|
|
System.arraycopy(decrypted, 6, keyBytes, 0, keyBytes.length);
|
|
|
|
byte[] macBytes = new byte[NKDF.LEGACY_MAC_KEY_LENGTH];
|
|
System.arraycopy(decrypted, 6 + keyBytes.length, macBytes, 0, macBytes.length);
|
|
|
|
if (decrypted.length < 6 + NKDF.LEGACY_CIPHER_KEY_LENGTH + NKDF.LEGACY_MAC_KEY_LENGTH + 1) {
|
|
throw new InvalidMessageException("No mode included");
|
|
}
|
|
|
|
this.mode = decrypted[6 + keyBytes.length + macBytes.length];
|
|
|
|
this.cipherKey = new SecretKeySpec(keyBytes, "AES");
|
|
this.macKey = new SecretKeySpec(macBytes, "HmacSHA1");
|
|
}
|
|
|
|
public int getLocalKeyId() {
|
|
return this.localKeyId;
|
|
}
|
|
|
|
public int getRemoteKeyId() {
|
|
return this.remoteKeyId;
|
|
}
|
|
|
|
public SecretKeySpec getCipherKey() {
|
|
return this.cipherKey;
|
|
}
|
|
|
|
public SecretKeySpec getMacKey() {
|
|
return this.macKey;
|
|
}
|
|
|
|
public int getMode() {
|
|
return mode;
|
|
}
|
|
}
|