/*
* 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.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Vector;
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;
import net.java.otr4j.io.messages.AbstractEncodedMessage;
import net.java.otr4j.io.messages.AbstractMessage;
import net.java.otr4j.io.messages.DHCommitMessage;
import net.java.otr4j.io.messages.DHKeyMessage;
import net.java.otr4j.io.messages.QueryMessage;
import net.java.otr4j.io.messages.RevealSignatureMessage;
import net.java.otr4j.io.messages.SignatureM;
import net.java.otr4j.io.messages.SignatureMessage;
import net.java.otr4j.io.messages.SignatureX;
/** @author George Politis */
class AuthContextImpl implements AuthContext {
public AuthContextImpl(Session session) {
this.setSession(session);
this.reset();
//logger.addHandler(new AndroidLogHandler());
}
private Session session;
private int authenticationState;
SecureRandom secureRandom;
private byte[] r;
private DHPublicKey remoteDHPublicKey;
private byte[] remoteDHPublicKeyEncrypted;
private byte[] remoteDHPublicKeyHash;
private KeyPair localDHKeyPair;
private int localDHPrivateKeyID;
private byte[] localDHPublicKeyBytes;
private byte[] localDHPublicKeyHash;
private byte[] localDHPublicKeyEncrypted;
private BigInteger s;
private byte[] c;
private byte[] m1;
private byte[] m2;
private byte[] cp;
private byte[] m1p;
private byte[] m2p;
private KeyPair localLongTermKeyPair;
private Boolean isSecure = false;
private int protocolVersion;
private static Logger logger = Logger.getLogger(AuthContextImpl.class.getName());
private int getProtocolVersion() {
return this.protocolVersion;
}
private void setProtocolVersion(int protoVersion) {
this.protocolVersion = protoVersion;
}
class MessageFactory {
private QueryMessage getQueryMessage() {
Vector<Integer> versions = new Vector<Integer>();
versions.add(2);
return new QueryMessage(versions);
}
private DHCommitMessage getDHCommitMessage() throws OtrException {
return new DHCommitMessage(getProtocolVersion(), getLocalDHPublicKeyHash(),
getLocalDHPublicKeyEncrypted());
}
private DHKeyMessage getDHKeyMessage() throws OtrException {
return new DHKeyMessage(getProtocolVersion(), (DHPublicKey) getLocalDHKeyPair()
.getPublic());
}
private RevealSignatureMessage getRevealSignatureMessage() throws OtrException {
try {
SignatureM m = new SignatureM((DHPublicKey) getLocalDHKeyPair().getPublic(),
getRemoteDHPublicKey(), getLocalLongTermKeyPair().getPublic(),
getLocalDHKeyPairID());
OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl();
byte[] mhash = otrCryptoEngine.sha256Hmac(SerializationUtils.toByteArray(m),
getM1());
byte[] signature = otrCryptoEngine.sign(mhash, getLocalLongTermKeyPair()
.getPrivate());
SignatureX mysteriousX = new SignatureX(getLocalLongTermKeyPair().getPublic(),
getLocalDHKeyPairID(), signature);
byte[] xEncrypted = otrCryptoEngine.aesEncrypt(getC(), null,
SerializationUtils.toByteArray(mysteriousX));
byte[] tmp = SerializationUtils.writeData(xEncrypted);
byte[] xEncryptedHash = otrCryptoEngine.sha256Hmac160(tmp, getM2());
return new RevealSignatureMessage(getProtocolVersion(), xEncrypted, xEncryptedHash,
getR());
} catch (IOException e) {
throw new OtrException(e);
}
}
private SignatureMessage getSignatureMessage() throws OtrException {
SignatureM m = new SignatureM((DHPublicKey) getLocalDHKeyPair().getPublic(),
getRemoteDHPublicKey(), getLocalLongTermKeyPair().getPublic(),
getLocalDHKeyPairID());
OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl();
byte[] mhash;
try {
mhash = otrCryptoEngine.sha256Hmac(SerializationUtils.toByteArray(m), getM1p());
} catch (IOException e) {
throw new OtrException(e);
}
byte[] signature = otrCryptoEngine.sign(mhash, getLocalLongTermKeyPair().getPrivate());
SignatureX mysteriousX = new SignatureX(getLocalLongTermKeyPair().getPublic(),
getLocalDHKeyPairID(), signature);
byte[] xEncrypted;
try {
xEncrypted = otrCryptoEngine.aesEncrypt(getCp(), null,
SerializationUtils.toByteArray(mysteriousX));
byte[] tmp = SerializationUtils.writeData(xEncrypted);
byte[] xEncryptedHash = otrCryptoEngine.sha256Hmac160(tmp, getM2p());
return new SignatureMessage(getProtocolVersion(), xEncrypted, xEncryptedHash);
} catch (IOException e) {
throw new OtrException(e);
}
}
}
private MessageFactory messageFactory = new MessageFactory();
public void reset() {
logger.finest("Resetting authentication state.");
authenticationState = AuthContext.NONE;
r = null;
remoteDHPublicKey = null;
remoteDHPublicKeyEncrypted = null;
remoteDHPublicKeyHash = null;
localDHKeyPair = null;
localDHPrivateKeyID = 1;
localDHPublicKeyBytes = null;
localDHPublicKeyHash = null;
localDHPublicKeyEncrypted = null;
s = null;
c = m1 = m2 = cp = m1p = m2p = null;
localLongTermKeyPair = null;
protocolVersion = 0;
setIsSecure(false);
}
private void setIsSecure(Boolean isSecure) {
this.isSecure = isSecure;
}
public boolean getIsSecure() {
return isSecure;
}
private void setAuthenticationState(int authenticationState) {
this.authenticationState = authenticationState;
}
private int getAuthenticationState() {
return authenticationState;
}
private byte[] getR() {
if (secureRandom == null)
secureRandom = new java.security.SecureRandom();
if (r == null) {
logger.finest("Picking random key r.");
r = new byte[OtrCryptoEngine.AES_KEY_BYTE_LENGTH];
secureRandom.nextBytes(r);
}
return r;
}
public void setRemoteDHPublicKey(DHPublicKey dhPublicKey) {
// Verifies that Alice's gy is a legal value (2 <= gy <= modulus-2)
if (dhPublicKey.getY().compareTo(OtrCryptoEngine.MODULUS_MINUS_TWO) > 0) {
throw new IllegalArgumentException("Illegal D-H Public Key value, Ignoring message.");
} else if (dhPublicKey.getY().compareTo(OtrCryptoEngine.BIGINTEGER_TWO) < 0) {
throw new IllegalArgumentException("Illegal D-H Public Key value, Ignoring message.");
}
logger.finest("Received D-H Public Key is a legal value.");
this.remoteDHPublicKey = dhPublicKey;
}
public DHPublicKey getRemoteDHPublicKey() {
return remoteDHPublicKey;
}
private void setRemoteDHPublicKeyEncrypted(byte[] remoteDHPublicKeyEncrypted) {
logger.finest("Storing encrypted remote public key.");
this.remoteDHPublicKeyEncrypted = remoteDHPublicKeyEncrypted;
}
private byte[] getRemoteDHPublicKeyEncrypted() {
return remoteDHPublicKeyEncrypted;
}
private void setRemoteDHPublicKeyHash(byte[] remoteDHPublicKeyHash) {
logger.finest("Storing encrypted remote public key hash.");
this.remoteDHPublicKeyHash = remoteDHPublicKeyHash;
}
private byte[] getRemoteDHPublicKeyHash() {
return remoteDHPublicKeyHash;
}
public KeyPair getLocalDHKeyPair() throws OtrException {
if (localDHKeyPair == null) {
localDHKeyPair = new OtrCryptoEngineImpl().generateDHKeyPair();
logger.finest("Generated local D-H key pair.");
}
return localDHKeyPair;
}
private int getLocalDHKeyPairID() {
return localDHPrivateKeyID;
}
private byte[] getLocalDHPublicKeyHash() throws OtrException {
if (localDHPublicKeyHash == null) {
localDHPublicKeyHash = new OtrCryptoEngineImpl().sha256Hash(getLocalDHPublicKeyBytes());
logger.finest("Hashed local D-H public key.");
}
return localDHPublicKeyHash;
}
private byte[] getLocalDHPublicKeyEncrypted() throws OtrException {
if (localDHPublicKeyEncrypted == null) {
localDHPublicKeyEncrypted = new OtrCryptoEngineImpl().aesEncrypt(getR(), null,
getLocalDHPublicKeyBytes());
logger.finest("Encrypted our D-H public key.");
}
return localDHPublicKeyEncrypted;
}
public BigInteger getS() throws OtrException {
if (s == null) {
s = new OtrCryptoEngineImpl().generateSecret(this.getLocalDHKeyPair().getPrivate(),
this.getRemoteDHPublicKey());
logger.finest("Generated shared secret.");
}
return s;
}
public byte[] getExtraSymmetricKey() throws OtrException {
return h2(EXTRA_SYMMETRIC_KEY);
}
private byte[] getC() throws OtrException {
if (c != null)
return c;
byte[] h2 = h2(C_START);
ByteBuffer buff = ByteBuffer.wrap(h2);
this.c = new byte[OtrCryptoEngine.AES_KEY_BYTE_LENGTH];
buff.get(this.c);
logger.finest("Computed c.");
return c;
}
private byte[] getM1() throws OtrException {
if (m1 != null)
return m1;
byte[] h2 = h2(M1_START);
ByteBuffer buff = ByteBuffer.wrap(h2);
byte[] m1 = new byte[OtrCryptoEngine.SHA256_HMAC_KEY_BYTE_LENGTH];
buff.get(m1);
logger.finest("Computed m1.");
this.m1 = m1;
return m1;
}
private byte[] getM2() throws OtrException {
if (m2 != null)
return m2;
byte[] h2 = h2(M2_START);
ByteBuffer buff = ByteBuffer.wrap(h2);
byte[] m2 = new byte[OtrCryptoEngine.SHA256_HMAC_KEY_BYTE_LENGTH];
buff.get(m2);
logger.finest("Computed m2.");
this.m2 = m2;
return m2;
}
private byte[] getCp() throws OtrException {
if (cp != null)
return cp;
byte[] h2 = h2(C_START);
ByteBuffer buff = ByteBuffer.wrap(h2);
byte[] cp = new byte[OtrCryptoEngine.AES_KEY_BYTE_LENGTH];
buff.position(OtrCryptoEngine.AES_KEY_BYTE_LENGTH);
buff.get(cp);
logger.finest("Computed c'.");
this.cp = cp;
return cp;
}
private byte[] getM1p() throws OtrException {
if (m1p != null)
return m1p;
byte[] h2 = h2(M1p_START);
ByteBuffer buff = ByteBuffer.wrap(h2);
byte[] m1p = new byte[OtrCryptoEngine.SHA256_HMAC_KEY_BYTE_LENGTH];
buff.get(m1p);
this.m1p = m1p;
logger.finest("Computed m1'.");
return m1p;
}
private byte[] getM2p() throws OtrException {
if (m2p != null)
return m2p;
byte[] h2 = h2(M2p_START);
ByteBuffer buff = ByteBuffer.wrap(h2);
byte[] m2p = new byte[OtrCryptoEngine.SHA256_HMAC_KEY_BYTE_LENGTH];
buff.get(m2p);
this.m2p = m2p;
logger.finest("Computed m2'.");
return m2p;
}
public KeyPair getLocalLongTermKeyPair() {
if (localLongTermKeyPair == null) {
localLongTermKeyPair = getSession().getLocalKeyPair();
}
return localLongTermKeyPair;
}
private byte[] h2(byte b) throws OtrException {
byte[] secbytes;
try {
secbytes = SerializationUtils.writeMpi(getS());
} catch (IOException e) {
throw new OtrException(e);
}
int len = secbytes.length + 1;
ByteBuffer buff = ByteBuffer.allocate(len);
buff.put(b);
buff.put(secbytes);
byte[] sdata = buff.array();
return new OtrCryptoEngineImpl().sha256Hash(sdata);
}
private byte[] getLocalDHPublicKeyBytes() throws OtrException {
if (localDHPublicKeyBytes == null) {
try {
this.localDHPublicKeyBytes = SerializationUtils
.writeMpi(((DHPublicKey) getLocalDHKeyPair().getPublic()).getY());
} catch (IOException e) {
throw new OtrException(e);
}
}
return localDHPublicKeyBytes;
}
public void handleReceivingMessage(AbstractMessage m) throws OtrException {
switch (m.messageType) {
case AbstractEncodedMessage.MESSAGE_DH_COMMIT:
handleDHCommitMessage((DHCommitMessage) m);
break;
case AbstractEncodedMessage.MESSAGE_DHKEY:
handleDHKeyMessage((DHKeyMessage) m);
break;
case AbstractEncodedMessage.MESSAGE_REVEALSIG:
handleRevealSignatureMessage((RevealSignatureMessage) m);
break;
case AbstractEncodedMessage.MESSAGE_SIGNATURE:
handleSignatureMessage((SignatureMessage) m);
break;
default:
throw new UnsupportedOperationException();
}
}
private void handleSignatureMessage(SignatureMessage m) throws OtrException {
Session session = getSession();
SessionID sessionID = session.getSessionID();
logger.finest(sessionID.getLocalUserId() + " received a signature message from "
+ sessionID.getRemoteUserId() + " throught " + sessionID.getProtocolName() + ".");
if (!session.getSessionPolicy().getAllowV2()) {
logger.finest("Policy does not allow OTRv2, ignoring message.");
return;
}
switch (this.getAuthenticationState()) {
case AWAITING_SIG:
// Verify MAC.
if (!m.verify(this.getM2p())) {
logger.finest("Signature MACs are not equal, ignoring message.");
return;
}
// Decrypt X.
byte[] remoteXDecrypted = m.decrypt(this.getCp());
SignatureX remoteX;
try {
remoteX = SerializationUtils.toMysteriousX(remoteXDecrypted);
} catch (IOException e) {
throw new OtrException(e);
}
// Compute signature.
PublicKey remoteLongTermPublicKey = remoteX.longTermPublicKey;
SignatureM remoteM = new SignatureM(this.getRemoteDHPublicKey(), (DHPublicKey) this
.getLocalDHKeyPair().getPublic(), remoteLongTermPublicKey, remoteX.dhKeyID);
OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl();
// Verify signature.
byte[] signature;
try {
signature = otrCryptoEngine.sha256Hmac(SerializationUtils.toByteArray(remoteM),
this.getM1p());
} catch (IOException e) {
throw new OtrException(e);
}
if (!otrCryptoEngine.verify(signature, remoteLongTermPublicKey, remoteX.signature)) {
session.showWarning("Bad signature");
logger.finest("Signature verification failed.");
return;
}
this.setIsSecure(true);
this.setRemoteLongTermPublicKey(remoteLongTermPublicKey);
break;
default:
logger.finest("We were not expecting a signature, ignoring message.");
return;
}
}
private void handleRevealSignatureMessage(RevealSignatureMessage m) throws OtrException {
Session session = getSession();
SessionID sessionID = session.getSessionID();
logger.finest(sessionID.getLocalUserId() + " received a reveal signature message from "
+ sessionID.getRemoteUserId() + " throught " + sessionID.getProtocolName() + ".");
if (!session.getSessionPolicy().getAllowV2()) {
logger.finest("Policy does not allow OTRv2, ignoring message.");
return;
}
switch (this.getAuthenticationState()) {
case AWAITING_REVEALSIG:
// Use the received value of r to decrypt the value of gx
// received
// in the D-H Commit Message, and verify the hash therein.
// Decrypt
// the encrypted signature, and verify the signature and the
// MACs.
// If everything checks out:
// * Reply with a Signature Message.
// * Transition authstate to AUTHSTATE_NONE.
// * Transition msgstate to MSGSTATE_ENCRYPTED.
// * TODO If there is a recent stored message, encrypt it and
// send
// it as a Data Message.
OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl();
// Uses r to decrypt the value of gx sent earlier
byte[] remoteDHPublicKeyDecrypted = otrCryptoEngine.aesDecrypt(m.revealedKey, null,
this.getRemoteDHPublicKeyEncrypted());
// Verifies that HASH(gx) matches the value sent earlier
byte[] remoteDHPublicKeyHash = otrCryptoEngine.sha256Hash(remoteDHPublicKeyDecrypted);
if (!Arrays.equals(remoteDHPublicKeyHash, this.getRemoteDHPublicKeyHash())) {
logger.finest("Hashes don't match, ignoring message.");
return;
}
// Verifies that Bob's gx is a legal value (2 <= gx <=
// modulus-2)
BigInteger remoteDHPublicKeyMpi;
try {
remoteDHPublicKeyMpi = SerializationUtils.readMpi(remoteDHPublicKeyDecrypted);
} catch (IOException e) {
throw new OtrException(e);
}
this.setRemoteDHPublicKey(otrCryptoEngine.getDHPublicKey(remoteDHPublicKeyMpi));
// Verify received Data.
if (!m.verify(this.getM2())) {
logger.finest("Signature MACs are not equal, ignoring message.");
return;
}
// Decrypt X.
byte[] remoteXDecrypted = m.decrypt(this.getC());
SignatureX remoteX;
try {
remoteX = SerializationUtils.toMysteriousX(remoteXDecrypted);
} catch (IOException e) {
throw new OtrException(e);
}
// Compute signature.
PublicKey remoteLongTermPublicKey = remoteX.longTermPublicKey;
SignatureM remoteM = new SignatureM(this.getRemoteDHPublicKey(), (DHPublicKey) this
.getLocalDHKeyPair().getPublic(), remoteLongTermPublicKey, remoteX.dhKeyID);
// Verify signature.
byte[] signature;
try {
signature = otrCryptoEngine.sha256Hmac(SerializationUtils.toByteArray(remoteM),
this.getM1());
} catch (IOException e) {
throw new OtrException(e);
}
if (!otrCryptoEngine.verify(signature, remoteLongTermPublicKey, remoteX.signature)) {
session.showWarning("Bad revealed signature");
logger.finest("Signature verification failed.");
return;
}
logger.finest("Signature verification succeeded.");
this.setAuthenticationState(AuthContext.NONE);
this.setIsSecure(true);
this.setRemoteLongTermPublicKey(remoteLongTermPublicKey);
getSession().injectMessage(messageFactory.getSignatureMessage());
break;
default:
logger.finest("Ignoring message.");
break;
}
}
private void handleDHKeyMessage(DHKeyMessage m) throws OtrException {
Session session = getSession();
SessionID sessionID = session.getSessionID();
logger.finest(sessionID.getLocalUserId() + " received a D-H key message from "
+ sessionID.getRemoteUserId() + " throught " + sessionID.getProtocolName() + ".");
if (!session.getSessionPolicy().getAllowV2()) {
logger.finest("If ALLOW_V2 is not set, ignore this message.");
return;
}
switch (this.getAuthenticationState()) {
case AWAITING_DHKEY:
// Reply with a Reveal Signature Message and transition
// authstate to
// AUTHSTATE_AWAITING_SIG
this.setRemoteDHPublicKey(m.dhPublicKey);
this.setAuthenticationState(AuthContext.AWAITING_SIG);
getSession().injectMessage(messageFactory.getRevealSignatureMessage());
logger.finest("Sent Reveal Signature.");
break;
case AWAITING_SIG:
if (m.dhPublicKey.getY().equals(this.getRemoteDHPublicKey().getY())) {
// If this D-H Key message is the same the one you received
// earlier (when you entered AUTHSTATE_AWAITING_SIG):
// Retransmit
// your Reveal Signature Message.
getSession().injectMessage(messageFactory.getRevealSignatureMessage());
logger.finest("Resent Reveal Signature.");
} else {
// Otherwise: Ignore the message.
logger.finest("Ignoring message.");
}
break;
default:
// Ignore the message
break;
}
}
private void handleDHCommitMessage(DHCommitMessage m) throws OtrException {
Session session = getSession();
SessionID sessionID = session.getSessionID();
logger.finest(sessionID.getLocalUserId() + " received a D-H commit message from "
+ sessionID.getRemoteUserId() + " throught " + sessionID.getProtocolName() + ".");
if (!session.getSessionPolicy().getAllowV2()) {
logger.finest("ALLOW_V2 is not set, ignore this message.");
return;
}
switch (this.getAuthenticationState()) {
case NONE:
// Reply with a D-H Key Message, and transition authstate to
// AUTHSTATE_AWAITING_REVEALSIG.
this.reset();
this.setProtocolVersion(2);
this.setRemoteDHPublicKeyEncrypted(m.dhPublicKeyEncrypted);
this.setRemoteDHPublicKeyHash(m.dhPublicKeyHash);
this.setAuthenticationState(AuthContext.AWAITING_REVEALSIG);
getSession().injectMessage(messageFactory.getDHKeyMessage());
logger.finest("Sent D-H key.");
break;
case AWAITING_DHKEY:
// This is the trickiest transition in the whole protocol. It
// indicates that you have already sent a D-H Commit message to
// your
// correspondent, but that he either didn't receive it, or just
// didn't receive it yet, and has sent you one as well. The
// symmetry
// will be broken by comparing the hashed gx you sent in your
// D-H
// Commit Message with the one you received, considered as
// 32-byte
// unsigned big-endian values.
BigInteger ourHash = new BigInteger(1, this.getLocalDHPublicKeyHash());
BigInteger theirHash = new BigInteger(1, m.dhPublicKeyHash);
if (theirHash.compareTo(ourHash) == -1) {
// Ignore the incoming D-H Commit message, but resend your
// D-H
// Commit message.
getSession().injectMessage(messageFactory.getDHCommitMessage());
logger.finest("Ignored the incoming D-H Commit message, but resent our D-H Commit message.");
} else {
// *Forget* your old gx value that you sent (encrypted)
// earlier,
// and pretend you're in AUTHSTATE_NONE; i.e. reply with a
// D-H
// Key Message, and transition authstate to
// AUTHSTATE_AWAITING_REVEALSIG.
this.reset();
this.setProtocolVersion(2);
this.setRemoteDHPublicKeyEncrypted(m.dhPublicKeyEncrypted);
this.setRemoteDHPublicKeyHash(m.dhPublicKeyHash);
this.setAuthenticationState(AuthContext.AWAITING_REVEALSIG);
getSession().injectMessage(messageFactory.getDHKeyMessage());
logger.finest("Forgot our old gx value that we sent (encrypted) earlier, and pretended we're in AUTHSTATE_NONE -> Sent D-H key.");
}
break;
case AWAITING_REVEALSIG:
// Retransmit your D-H Key Message (the same one as you sent
// when
// you entered AUTHSTATE_AWAITING_REVEALSIG). Forget the old D-H
// Commit message, and use this new one instead.
this.setRemoteDHPublicKeyEncrypted(m.dhPublicKeyEncrypted);
this.setRemoteDHPublicKeyHash(m.dhPublicKeyHash);
getSession().injectMessage(messageFactory.getDHKeyMessage());
logger.finest("Sent D-H key.");
break;
case AWAITING_SIG:
// Reply with a new D-H Key message, and transition authstate to
// AUTHSTATE_AWAITING_REVEALSIG
this.reset();
this.setRemoteDHPublicKeyEncrypted(m.dhPublicKeyEncrypted);
this.setRemoteDHPublicKeyHash(m.dhPublicKeyHash);
this.setAuthenticationState(AuthContext.AWAITING_REVEALSIG);
getSession().injectMessage(messageFactory.getDHKeyMessage());
logger.finest("Sent D-H key.");
break;
case V1_SETUP:
throw new UnsupportedOperationException();
}
}
public void startV2Auth() throws OtrException {
logger.finest("Starting Authenticated Key Exchange, sending query message");
getSession().injectMessage(messageFactory.getQueryMessage());
}
public void respondV2Auth() throws OtrException {
logger.finest("Responding to Query Message");
this.reset();
this.setProtocolVersion(2);
this.setAuthenticationState(AuthContext.AWAITING_DHKEY);
logger.finest("Sending D-H Commit.");
getSession().injectMessage(messageFactory.getDHCommitMessage());
}
private void setSession(Session session) {
this.session = session;
}
private Session getSession() {
return session;
}
private PublicKey remoteLongTermPublicKey;
public PublicKey getRemoteLongTermPublicKey() {
return remoteLongTermPublicKey;
}
private void setRemoteLongTermPublicKey(PublicKey pubKey) {
this.remoteLongTermPublicKey = pubKey;
}
}