src/net/java/otr4j/session/SessionKeysImpl.java
changeset 906 0ff0059f2ec3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/net/java/otr4j/session/SessionKeysImpl.java	Sun Dec 05 18:43:51 2010 +0100
@@ -0,0 +1,240 @@
+/*
+ * otr4j, the open source java otr library.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.otr4j.session;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.KeyPair;
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+import javax.crypto.interfaces.DHPublicKey;
+
+import net.java.otr4j.OtrException;
+import net.java.otr4j.crypto.OtrCryptoEngine;
+import net.java.otr4j.crypto.OtrCryptoEngineImpl;
+import net.java.otr4j.io.SerializationUtils;
+
+/**
+ * 
+ * @author George Politis
+ */
+class SessionKeysImpl implements SessionKeys {
+
+	private static Logger logger = Logger.getLogger(SessionKeysImpl.class
+			.getName());
+	private String keyDescription;
+
+	public SessionKeysImpl(int localKeyIndex, int remoteKeyIndex) {
+		if (localKeyIndex == 0)
+			keyDescription = "(Previous local, ";
+		else
+			keyDescription = "(Most recent local, ";
+
+		if (remoteKeyIndex == 0)
+			keyDescription += "Previous remote)";
+		else
+			keyDescription += "Most recent remote)";
+
+	}
+
+	public void setLocalPair(KeyPair keyPair, int localPairKeyID) {
+		this.localPair = keyPair;
+		this.setLocalKeyID(localPairKeyID);
+		logger.finest(keyDescription + " current local key ID: "
+				+ this.getLocalKeyID());
+		this.reset();
+	}
+
+	public void setRemoteDHPublicKey(DHPublicKey pubKey, int remoteKeyID) {
+		this.setRemoteKey(pubKey);
+		this.setRemoteKeyID(remoteKeyID);
+		logger.finest(keyDescription + " current remote key ID: "
+				+ this.getRemoteKeyID());
+		this.reset();
+	}
+
+	private byte[] sendingCtr = new byte[16];
+	private byte[] receivingCtr = new byte[16];
+
+	public void incrementSendingCtr() {
+		logger.finest("Incrementing counter for (localkeyID, remoteKeyID) = ("
+				+ getLocalKeyID() + "," + getRemoteKeyID() + ")");
+		// logger.debug("Counter prior increament: " +
+		// Utils.dump(sendingCtr,
+		// true, 16));
+		for (int i = 7; i >= 0; i--)
+			if (++sendingCtr[i] != 0)
+				break;
+		// logger.debug("Counter after increament: " +
+		// Utils.dump(sendingCtr,
+		// true, 16));
+	}
+
+	public byte[] getSendingCtr() {
+		return sendingCtr;
+	}
+
+	public byte[] getReceivingCtr() {
+		return receivingCtr;
+	}
+
+	public void setReceivingCtr(byte[] ctr) {
+		for (int i = 0; i < ctr.length; i++)
+			receivingCtr[i] = ctr[i];
+	}
+
+	private void reset() {
+		logger.finest("Resetting " + keyDescription + " session keys.");
+		Arrays.fill(this.sendingCtr, (byte) 0x00);
+		Arrays.fill(this.receivingCtr, (byte) 0x00);
+		this.sendingAESKey = null;
+		this.receivingAESKey = null;
+		this.sendingMACKey = null;
+		this.receivingMACKey = null;
+		this.setIsUsedReceivingMACKey(false);
+		this.s = null;
+		if (getLocalPair() != null && getRemoteKey() != null) {
+			this.isHigh = ((DHPublicKey) getLocalPair().getPublic()).getY()
+					.abs().compareTo(getRemoteKey().getY().abs()) == 1;
+		}
+
+	}
+
+	private byte[] h1(byte b) throws OtrException {
+
+		try {
+			byte[] secbytes = SerializationUtils.writeMpi(getS());
+
+			int len = secbytes.length + 1;
+			ByteBuffer buff = ByteBuffer.allocate(len);
+			buff.put(b);
+			buff.put(secbytes);
+			byte[] result = new OtrCryptoEngineImpl().sha1Hash(buff.array());
+			return result;
+		} catch (Exception e) {
+			throw new OtrException(e);
+		}
+	}
+
+	public byte[] getSendingAESKey() throws OtrException {
+		if (sendingAESKey != null)
+			return sendingAESKey;
+
+		byte sendbyte = LOW_SEND_BYTE;
+		if (this.isHigh)
+			sendbyte = HIGH_SEND_BYTE;
+
+		byte[] h1 = h1(sendbyte);
+
+		byte[] key = new byte[OtrCryptoEngine.AES_KEY_BYTE_LENGTH];
+		ByteBuffer buff = ByteBuffer.wrap(h1);
+		buff.get(key);
+		logger.finest("Calculated sending AES key.");
+		this.sendingAESKey = key;
+		return sendingAESKey;
+	}
+
+	public byte[] getReceivingAESKey() throws OtrException {
+		if (receivingAESKey != null)
+			return receivingAESKey;
+
+		byte receivebyte = LOW_RECEIVE_BYTE;
+		if (this.isHigh)
+			receivebyte = HIGH_RECEIVE_BYTE;
+
+		byte[] h1 = h1(receivebyte);
+
+		byte[] key = new byte[OtrCryptoEngine.AES_KEY_BYTE_LENGTH];
+		ByteBuffer buff = ByteBuffer.wrap(h1);
+		buff.get(key);
+		logger.finest("Calculated receiving AES key.");
+		this.receivingAESKey = key;
+
+		return receivingAESKey;
+	}
+
+	public byte[] getSendingMACKey() throws OtrException {
+		if (sendingMACKey != null)
+			return sendingMACKey;
+
+		sendingMACKey = new OtrCryptoEngineImpl().sha1Hash(getSendingAESKey());
+		logger.finest("Calculated sending MAC key.");
+		return sendingMACKey;
+	}
+
+	public byte[] getReceivingMACKey() throws OtrException {
+		if (receivingMACKey == null) {
+			receivingMACKey = new OtrCryptoEngineImpl()
+					.sha1Hash(getReceivingAESKey());
+			logger.finest("Calculated receiving AES key.");
+		}
+		return receivingMACKey;
+	}
+
+	private BigInteger getS() throws OtrException {
+		if (s == null) {
+			s = new OtrCryptoEngineImpl().generateSecret(getLocalPair()
+					.getPrivate(), getRemoteKey());
+			logger.finest("Calculating shared secret S.");
+		}
+		return s;
+	}
+
+	public void setS(BigInteger s) {
+		this.s = s;
+	}
+
+	public void setIsUsedReceivingMACKey(Boolean isUsedReceivingMACKey) {
+		this.isUsedReceivingMACKey = isUsedReceivingMACKey;
+	}
+
+	public Boolean getIsUsedReceivingMACKey() {
+		return isUsedReceivingMACKey;
+	}
+
+	private void setLocalKeyID(int localKeyID) {
+		this.localKeyID = localKeyID;
+	}
+
+	public int getLocalKeyID() {
+		return localKeyID;
+	}
+
+	private void setRemoteKeyID(int remoteKeyID) {
+		this.remoteKeyID = remoteKeyID;
+	}
+
+	public int getRemoteKeyID() {
+		return remoteKeyID;
+	}
+
+	private void setRemoteKey(DHPublicKey remoteKey) {
+		this.remoteKey = remoteKey;
+	}
+
+	public DHPublicKey getRemoteKey() {
+		return remoteKey;
+	}
+
+	public KeyPair getLocalPair() {
+		return localPair;
+	}
+
+	private int localKeyID;
+	private int remoteKeyID;
+	private DHPublicKey remoteKey;
+	private KeyPair localPair;
+
+	private byte[] sendingAESKey;
+	private byte[] receivingAESKey;
+	private byte[] sendingMACKey;
+	private byte[] receivingMACKey;
+	private Boolean isUsedReceivingMACKey;
+	private BigInteger s;
+	private Boolean isHigh;
+}