/* * otr4j, the open source java otr library. * * Distributable under LGPL license. See terms of license at gnu.org. */ package net.java.otr4j.session; import info.guardianproject.otr.app.im.app.ImApp; import info.guardianproject.util.Debug; import java.math.BigInteger; import java.nio.ByteBuffer; import java.security.KeyPair; import java.util.Arrays; 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; import android.util.Log; /** @author George Politis */ class SessionKeysImpl implements SessionKeys { 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); if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,keyDescription + " current local key ID: " + this.getLocalKeyID()); this.reset(); } public void setRemoteDHPublicKey(DHPublicKey pubKey, int remoteKeyID) { this.setRemoteKey(pubKey); this.setRemoteKeyID(remoteKeyID); if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,keyDescription + " current remote key ID: " + this.getRemoteKeyID()); this.reset(); } private byte[] sendingCtr = new byte[16]; private byte[] receivingCtr = new byte[16]; public void incrementSendingCtr() { if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,"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() { if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,"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); if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,"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); if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,"Calculated receiving AES key."); this.receivingAESKey = key; return receivingAESKey; } public byte[] getSendingMACKey() throws OtrException { if (sendingMACKey != null) return sendingMACKey; sendingMACKey = new OtrCryptoEngineImpl().sha1Hash(getSendingAESKey()); if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,"Calculated sending MAC key."); return sendingMACKey; } public byte[] getReceivingMACKey() throws OtrException { if (receivingMACKey == null) { receivingMACKey = new OtrCryptoEngineImpl().sha1Hash(getReceivingAESKey()); if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,"Calculated receiving AES key."); } return receivingMACKey; } private BigInteger getS() throws OtrException { if (s == null) { s = new OtrCryptoEngineImpl().generateSecret(getLocalPair().getPrivate(), getRemoteKey()); if (Debug.DEBUG_ENABLED) Log.d(ImApp.LOG_TAG,"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; }