# HG changeset patch # User Da Risk # Date 1426448477 -3600 # Node ID 9b965359eaea2e615ae9c632de2990f7e8facab1 # Parent 6ca974ea549b9724ba718b80ad199908910cb146 OTR: Update to otr4j-0.22 diff -r 6ca974ea549b -r 9b965359eaea app/build.gradle --- a/app/build.gradle Sun Mar 15 18:57:24 2015 +0100 +++ b/app/build.gradle Sun Mar 15 20:41:17 2015 +0100 @@ -26,7 +26,8 @@ } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) + compile fileTree(include: ['*.jar'], dir: 'libs') + compile 'org.jitsi:org.otr4j:0.22' } apply from: "$project.rootDir/tools/android-checkstyle.gradle" diff -r 6ca974ea549b -r 9b965359eaea app/libs/lcrypto-jdk16-146-20110415.jar Binary file app/libs/lcrypto-jdk16-146-20110415.jar has changed diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/com/beem/project/beem/otr/BeemOtrManager.java --- a/app/src/main/java/com/beem/project/beem/otr/BeemOtrManager.java Sun Mar 15 18:57:24 2015 +0100 +++ b/app/src/main/java/com/beem/project/beem/otr/BeemOtrManager.java Sun Mar 15 20:41:17 2015 +0100 @@ -31,14 +31,14 @@ import java.util.HashMap; import java.util.Map; -import net.java.otr4j.OtrEngine; import net.java.otr4j.OtrEngineHost; -import net.java.otr4j.OtrEngineImpl; import net.java.otr4j.OtrEngineListener; import net.java.otr4j.OtrException; import net.java.otr4j.OtrKeyManagerImpl; import net.java.otr4j.OtrPolicy; import net.java.otr4j.OtrPolicyImpl; +import net.java.otr4j.session.FragmenterInstructions; +import net.java.otr4j.session.InstanceTag; import net.java.otr4j.session.SessionID; import net.java.otr4j.session.SessionStatus; import android.util.Log; @@ -53,7 +53,7 @@ private static final String TAG = "BeemOtrEngineHostImpl"; private static BeemOtrManager INSTANCE; //We will have a global policy for Beem as long as we won't need to modify the policy per chat. - private static final OtrPolicy mGlobalPolicy = new OtrPolicyImpl(OtrPolicy.ALLOW_V2 | OtrPolicy.ERROR_START_AKE); + private static final OtrPolicy mGlobalPolicy = new OtrPolicyImpl(OtrPolicy.ALLOW_V2 | OtrPolicy.ALLOW_V3 | OtrPolicy.ERROR_START_AKE); private OtrEngine mOtrEngine; private OtrKeyManagerImpl mOtrKeyManager; @@ -65,8 +65,7 @@ * Private constructor prevents instantiation from other classes. */ private BeemOtrManager() { - mOtrEngine = new OtrEngineImpl(this); - mOtrEngine.addOtrEngineListener(new BeemOtrListener()); + mOtrEngine = new OtrEngine(this, new BeemOtrListener()); try { mOtrKeyManager = new OtrKeyManagerImpl("/sdcard/beem.keystore"); } catch (IOException e) { @@ -125,7 +124,7 @@ * @param sessionId the current otr session */ public void verifyRemoteFingerprint(final SessionID sessionId) { - mOtrKeyManager.verify(sessionId); + verify(sessionId, null, true); } /** @@ -133,7 +132,7 @@ * @param sessionId the current otr session */ public void unverifyRemoteFingerprint(final SessionID sessionId) { - mOtrKeyManager.unverify(sessionId); + unverify(sessionId, null); } /** @@ -152,8 +151,13 @@ } @Override - public void showWarning(SessionID sessionID, String warning) { - Log.d(TAG, "Warning for " + sessionID + " : " + warning); + public void unreadableMessageReceived(SessionID sessionID) throws OtrException { + + } + + @Override + public void unencryptedMessageReceived(SessionID sessionID, String msg) throws OtrException { + mOtrEngine.endSession(sessionID); } @Override @@ -162,12 +166,78 @@ } @Override + public void smpError(SessionID sessionID, int tlvType, boolean cheated) throws OtrException { + Log.d(TAG, "SmpError for " + sessionID); + } + + @Override + public void smpAborted(SessionID sessionID) throws OtrException { + Log.d(TAG, "SmpAborted for " + sessionID); + } + + @Override + public void finishedSessionMessage(SessionID sessionID, String msgText) throws OtrException { + + } + + @Override + public void requireEncryptedMessage(SessionID sessionID, String msgText) throws OtrException { + + } + + @Override public OtrPolicy getSessionPolicy(SessionID sessionID) { return mGlobalPolicy; } @Override - public KeyPair getKeyPair(SessionID sessionID) { + public FragmenterInstructions getFragmenterInstructions(SessionID sessionID) { + return null; + } + + + @Override + public byte[] getLocalFingerprintRaw(SessionID sessionID) { + return mOtrKeyManager.getLocalFingerprintRaw(sessionID); + } + + @Override + public void askForSecret(SessionID sessionID, InstanceTag receiverTag, String question) { + + } + + @Override + public void verify(SessionID sessionID, String fingerprint, boolean approved) { + mOtrKeyManager.verify(sessionID); + } + + @Override + public void unverify(SessionID sessionID, String fingerprint) { + mOtrKeyManager.unverify(sessionID); + } + + @Override + public String getReplyForUnreadableMessage(SessionID sessionID) { + return null; + } + + @Override + public String getFallbackMessage(SessionID sessionID) { + return null; + } + + @Override + public void messageFromAnotherInstanceReceived(SessionID sessionID) { + + } + + @Override + public void multipleInstancesDetected(SessionID sessionID) { + + } + + @Override + public KeyPair getLocalKeyPair(SessionID sessionID) throws OtrException { KeyPair kp = mOtrKeyManager.loadLocalKeyPair(sessionID); if (kp != null) @@ -206,5 +276,15 @@ } } } + + @Override + public void multipleInstancesDetected(SessionID sessionID) { + + } + + @Override + public void outgoingSessionChanged(SessionID sessionID) { + + } } } diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/com/beem/project/beem/otr/OtrEngine.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/src/main/java/com/beem/project/beem/otr/OtrEngine.java Sun Mar 15 20:41:17 2015 +0100 @@ -0,0 +1,75 @@ + +package com.beem.project.beem.otr; + +import net.java.otr4j.OtrEngineHost; +import net.java.otr4j.OtrEngineListener; +import net.java.otr4j.OtrException; +import net.java.otr4j.session.Session; +import net.java.otr4j.session.SessionID; +import net.java.otr4j.session.SessionImpl; +import net.java.otr4j.session.SessionStatus; + +import java.security.PublicKey; +import java.util.Hashtable; +import java.util.Map; + +public class OtrEngine { + + public OtrEngine(OtrEngineHost host, OtrEngineListener listener) { + this.host = host; + this.listener = listener; + } + + private OtrEngineHost host; + private Map sessions; + + private Session getSession(SessionID sessionID) { + + if (sessionID == null || sessionID.equals(SessionID.Empty)) + throw new IllegalArgumentException(); + + if (sessions == null) + sessions = new Hashtable(); + + if (!sessions.containsKey(sessionID)) { + Session session = new SessionImpl(sessionID, host); + sessions.put(sessionID, session); + + session.addOtrEngineListener(listener); + return session; + } else + return sessions.get(sessionID); + } + + public SessionStatus getSessionStatus(SessionID sessionID) { + return this.getSession(sessionID).getSessionStatus(); + } + + public String transformReceiving(SessionID sessionID, String msgText) + throws OtrException { + return this.getSession(sessionID).transformReceiving(msgText); + } + + public String[] transformSending(SessionID sessionID, String msgText) + throws OtrException { + return this.getSession(sessionID).transformSending(msgText, null); + } + + public void endSession(SessionID sessionID) throws OtrException { + this.getSession(sessionID).endSession(); + } + + public void startSession(SessionID sessionID) throws OtrException { + this.getSession(sessionID).startSession(); + } + + public void refreshSession(SessionID sessionID) throws OtrException { + this.getSession(sessionID).refreshSession(); + } + + public PublicKey getRemotePublicKey(SessionID sessionID) { + return this.getSession(sessionID).getRemotePublicKey(); + } + + private final OtrEngineListener listener; +} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/com/beem/project/beem/service/BeemChatManager.java --- a/app/src/main/java/com/beem/project/beem/service/BeemChatManager.java Sun Mar 15 18:57:24 2015 +0100 +++ b/app/src/main/java/com/beem/project/beem/service/BeemChatManager.java Sun Mar 15 20:41:17 2015 +0100 @@ -397,7 +397,7 @@ return; } - if (Status.getStatusFromPresence(presence) >= Status.CONTACT_STATUS_DISCONNECT) { + if (Status.getStatusFromPresence(presence) <= Status.CONTACT_STATUS_DISCONNECT) { try { mChats.get(key).localEndOtrSession(); } catch (OtrException e) { diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/com/beem/project/beem/service/ChatAdapter.java --- a/app/src/main/java/com/beem/project/beem/service/ChatAdapter.java Sun Mar 15 18:57:24 2015 +0100 +++ b/app/src/main/java/com/beem/project/beem/service/ChatAdapter.java Sun Mar 15 20:41:17 2015 +0100 @@ -332,10 +332,15 @@ if (mOtrSessionId != null && unencrypted != null && unencrypted.getBody() != null) { try { - String body = BeemOtrManager.getInstance().getOtrManager() + + String[] bodies = BeemOtrManager.getInstance().getOtrManager() .transformSending(mOtrSessionId, unencrypted.getBody()); + StringBuilder concatBody = new StringBuilder(); + for(String body: bodies) { + concatBody.append(body); + } Message result = new Message(unencrypted.getTo(), unencrypted.getType()); - result.setBody(body); + result.setBody(concatBody.toString()); return result; } catch (OtrException e) { Log.e(TAG, "OTR: Unable to encrypt message", e); diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrEngine.java --- a/app/src/main/java/net/java/otr4j/OtrEngine.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -package net.java.otr4j; - -import java.security.PublicKey; - -import net.java.otr4j.session.SessionID; -import net.java.otr4j.session.SessionStatus; - -/** - * - * @author George Politis - * - */ -public interface OtrEngine { - - /** - * - * @param sessionID - * The session identifier. - * @param content - * The message content to be transformed. - * @return The transformed message content. - * @throws OtrException - */ - public abstract String transformReceiving(SessionID sessionID, - String content) throws OtrException; - - /** - * - * @param sessionID - * The session identifier. - * @param content - * The message content to be transformed. - * @return The transformed message content. - * @throws OtrException - */ - public abstract String transformSending(SessionID sessionID, String content) throws OtrException; - - /** - * Starts an Off-the-Record session, if there is no active one. - * - * @param sessionID - * The session identifier. - * @throws OtrException - */ - public abstract void startSession(SessionID sessionID) throws OtrException; - - /** - * Ends the Off-the-Record session, if exists. - * - * @param sessionID - * The session identifier. - * @throws OtrException - */ - public abstract void endSession(SessionID sessionID) throws OtrException; - - /** - * Stops/Starts the Off-the-Record session. - * - * @param sessionID - * The session identifier. - * @throws OtrException - */ - public abstract void refreshSession(SessionID sessionID) throws OtrException; - - /** - * - * @param sessionID - * The session identifier. - * @return The status of an Off-the-Record session. - */ - public abstract SessionStatus getSessionStatus(SessionID sessionID); - - /** - * - * @param sessionID - * The session identifier. - * @return The remote public key. - */ - public abstract PublicKey getRemotePublicKey(SessionID sessionID); - - public abstract void addOtrEngineListener(OtrEngineListener l); - - public abstract void removeOtrEngineListener(OtrEngineListener l); -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrEngineHost.java --- a/app/src/main/java/net/java/otr4j/OtrEngineHost.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j; - -import java.security.KeyPair; - -import net.java.otr4j.session.SessionID; - -/** - * - * This interface should be implemented by the host application. It is required - * for otr4j to work properly. - * - * @author George Politis - * - */ -public abstract interface OtrEngineHost { - public abstract void injectMessage(SessionID sessionID, String msg); - - public abstract void showWarning(SessionID sessionID, String warning); - - public abstract void showError(SessionID sessionID, String error); - - public abstract OtrPolicy getSessionPolicy(SessionID sessionID); - - public abstract KeyPair getKeyPair(SessionID sessionID); -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrEngineImpl.java --- a/app/src/main/java/net/java/otr4j/OtrEngineImpl.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * otr4j, the open source java otr librar - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -package net.java.otr4j; - -import java.security.PublicKey; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.Vector; - -import net.java.otr4j.session.Session; -import net.java.otr4j.session.SessionID; -import net.java.otr4j.session.SessionImpl; -import net.java.otr4j.session.SessionStatus; - -/** - * - * @author George Politis - * - */ -public class OtrEngineImpl implements OtrEngine { - - public OtrEngineImpl(OtrEngineHost host) { - if (host == null) - throw new IllegalArgumentException("OtrEgineHost is required."); - - this.setHost(host); - } - - private OtrEngineHost host; - private Map sessions; - - private Session getSession(SessionID sessionID) { - - if (sessionID == null || sessionID.equals(SessionID.Empty)) - throw new IllegalArgumentException(); - - if (sessions == null) - sessions = new Hashtable(); - - if (!sessions.containsKey(sessionID)) { - Session session = new SessionImpl(sessionID, getHost()); - sessions.put(sessionID, session); - - session.addOtrEngineListener(new OtrEngineListener() { - - public void sessionStatusChanged(SessionID sessionID) { - for (OtrEngineListener l : listeners) - l.sessionStatusChanged(sessionID); - } - }); - return session; - } else - return sessions.get(sessionID); - } - - public SessionStatus getSessionStatus(SessionID sessionID) { - return this.getSession(sessionID).getSessionStatus(); - } - - public String transformReceiving(SessionID sessionID, String msgText) - throws OtrException { - return this.getSession(sessionID).transformReceiving(msgText); - } - - public String transformSending(SessionID sessionID, String msgText) - throws OtrException { - return this.getSession(sessionID).transformSending(msgText, null); - } - - public void endSession(SessionID sessionID) throws OtrException { - this.getSession(sessionID).endSession(); - } - - public void startSession(SessionID sessionID) throws OtrException { - this.getSession(sessionID).startSession(); - } - - private void setHost(OtrEngineHost host) { - this.host = host; - } - - private OtrEngineHost getHost() { - return host; - } - - public void refreshSession(SessionID sessionID) throws OtrException { - this.getSession(sessionID).refreshSession(); - } - - public PublicKey getRemotePublicKey(SessionID sessionID) { - return this.getSession(sessionID).getRemotePublicKey(); - } - - private List listeners = new Vector(); - - public void addOtrEngineListener(OtrEngineListener l) { - synchronized (listeners) { - if (!listeners.contains(l)) - listeners.add(l); - } - } - - public void removeOtrEngineListener(OtrEngineListener l) { - synchronized (listeners) { - listeners.remove(l); - } - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrEngineListener.java --- a/app/src/main/java/net/java/otr4j/OtrEngineListener.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -package net.java.otr4j; - -import net.java.otr4j.session.SessionID; - -/** - * This interface should be implemented by the host application. It notifies - * about session status changes. - * - * @author George Politis - * - */ -public interface OtrEngineListener { - public abstract void sessionStatusChanged(SessionID sessionID); -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrException.java --- a/app/src/main/java/net/java/otr4j/OtrException.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -package net.java.otr4j; - - -public class OtrException extends Exception { - private static final long serialVersionUID = 1L; - - public OtrException(Exception e){ - super(e); - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrKeyManager.java --- a/app/src/main/java/net/java/otr4j/OtrKeyManager.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -package net.java.otr4j; - -import java.security.KeyPair; -import java.security.PublicKey; - -import net.java.otr4j.session.SessionID; - -public abstract interface OtrKeyManager { - - public abstract void addListener(OtrKeyManagerListener l); - - public abstract void removeListener(OtrKeyManagerListener l); - - public abstract void verify(SessionID sessionID); - - public abstract void unverify(SessionID sessionID); - - public abstract boolean isVerified(SessionID sessionID); - - public abstract String getRemoteFingerprint(SessionID sessionID); - - public abstract String getLocalFingerprint(SessionID sessionID); - - public abstract void savePublicKey(SessionID sessionID, PublicKey pubKey); - - public abstract PublicKey loadRemotePublicKey(SessionID sessionID); - - public abstract KeyPair loadLocalKeyPair(SessionID sessionID); - - public abstract void generateLocalKeyPair(SessionID sessionID); -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrKeyManagerImpl.java --- a/app/src/main/java/net/java/otr4j/OtrKeyManagerImpl.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,304 +0,0 @@ -package net.java.otr4j; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.List; -import java.util.Properties; -import java.util.Vector; - -import org.bouncycastle2.util.encoders.Base64; - -import net.java.otr4j.crypto.OtrCryptoEngineImpl; -import net.java.otr4j.crypto.OtrCryptoException; -import net.java.otr4j.session.SessionID; - -public class OtrKeyManagerImpl implements OtrKeyManager { - - private OtrKeyManagerStore store; - - public OtrKeyManagerImpl(OtrKeyManagerStore store) { - this.store = store; - } - - class DefaultPropertiesStore implements OtrKeyManagerStore { - private final Properties properties = new Properties(); - private String filepath; - - public DefaultPropertiesStore(String filepath) throws IOException { - if (filepath == null || filepath.length() < 1) - throw new IllegalArgumentException(); - this.filepath = filepath; - properties.clear(); - - InputStream in = new BufferedInputStream(new FileInputStream( - getConfigurationFile())); - try { - properties.load(in); - } finally { - in.close(); - } - } - - private File getConfigurationFile() throws IOException { - File configFile = new File(filepath); - if (!configFile.exists()) - configFile.createNewFile(); - return configFile; - } - - public void setProperty(String id, boolean value) { - properties.setProperty(id, "true"); - try { - this.store(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void store() throws FileNotFoundException, IOException { - OutputStream out = new FileOutputStream(getConfigurationFile()); - properties.store(out, null); - out.close(); - } - - public void setProperty(String id, byte[] value) { - properties.setProperty(id, new String(Base64.encode(value))); - try { - this.store(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void removeProperty(String id) { - properties.remove(id); - - } - - public byte[] getPropertyBytes(String id) { - String value = properties.getProperty(id); - if (value == null) - return null; - return Base64.decode(value); - } - - public boolean getPropertyBoolean(String id, boolean defaultValue) { - try { - return Boolean.valueOf(properties.get(id).toString()); - } catch (Exception e) { - return defaultValue; - } - } - } - - public OtrKeyManagerImpl(String filepath) throws IOException { - this.store = new DefaultPropertiesStore(filepath); - } - - private List listeners = new Vector(); - - public void addListener(OtrKeyManagerListener l) { - synchronized (listeners) { - if (!listeners.contains(l)) - listeners.add(l); - } - } - - public void removeListener(OtrKeyManagerListener l) { - synchronized (listeners) { - listeners.remove(l); - } - } - - public void generateLocalKeyPair(SessionID sessionID) { - if (sessionID == null) - return; - - String accountID = sessionID.getAccountID(); - KeyPair keyPair; - try { - keyPair = KeyPairGenerator.getInstance("DSA").genKeyPair(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - return; - } - - // Store Public Key. - PublicKey pubKey = keyPair.getPublic(); - X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKey - .getEncoded()); - - this.store.setProperty(accountID + ".publicKey", x509EncodedKeySpec - .getEncoded()); - - // Store Private Key. - PrivateKey privKey = keyPair.getPrivate(); - PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec( - privKey.getEncoded()); - - this.store.setProperty(accountID + ".privateKey", pkcs8EncodedKeySpec - .getEncoded()); - } - - public String getLocalFingerprint(SessionID sessionID) { - KeyPair keyPair = loadLocalKeyPair(sessionID); - - if (keyPair == null) - return null; - - PublicKey pubKey = keyPair.getPublic(); - - try { - return new OtrCryptoEngineImpl().getFingerprint(pubKey); - } catch (OtrCryptoException e) { - e.printStackTrace(); - return null; - } - } - - public String getRemoteFingerprint(SessionID sessionID) { - PublicKey remotePublicKey = loadRemotePublicKey(sessionID); - if (remotePublicKey == null) - return null; - try { - return new OtrCryptoEngineImpl().getFingerprint(remotePublicKey); - } catch (OtrCryptoException e) { - e.printStackTrace(); - return null; - } - } - - public boolean isVerified(SessionID sessionID) { - if (sessionID == null) - return false; - - return this.store.getPropertyBoolean(sessionID.getUserID() - + ".publicKey.verified", false); - } - - public KeyPair loadLocalKeyPair(SessionID sessionID) { - if (sessionID == null) - return null; - - String accountID = sessionID.getAccountID(); - // Load Private Key. - byte[] b64PrivKey = this.store.getPropertyBytes(accountID - + ".privateKey"); - if (b64PrivKey == null) - return null; - - PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(b64PrivKey); - - // Load Public Key. - byte[] b64PubKey = this.store - .getPropertyBytes(accountID + ".publicKey"); - if (b64PubKey == null) - return null; - - X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(b64PubKey); - - PublicKey publicKey; - PrivateKey privateKey; - - // Generate KeyPair. - KeyFactory keyFactory; - try { - keyFactory = KeyFactory.getInstance("DSA"); - publicKey = keyFactory.generatePublic(publicKeySpec); - privateKey = keyFactory.generatePrivate(privateKeySpec); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - return null; - } catch (InvalidKeySpecException e) { - e.printStackTrace(); - return null; - } - - return new KeyPair(publicKey, privateKey); - } - - public PublicKey loadRemotePublicKey(SessionID sessionID) { - if (sessionID == null) - return null; - - String userID = sessionID.getUserID(); - - byte[] b64PubKey = this.store.getPropertyBytes(userID + ".publicKey"); - if (b64PubKey == null) - return null; - - X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(b64PubKey); - - // Generate KeyPair. - KeyFactory keyFactory; - try { - keyFactory = KeyFactory.getInstance("DSA"); - return keyFactory.generatePublic(publicKeySpec); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - return null; - } catch (InvalidKeySpecException e) { - e.printStackTrace(); - return null; - } - } - - public void savePublicKey(SessionID sessionID, PublicKey pubKey) { - if (sessionID == null) - return; - - X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKey - .getEncoded()); - - String userID = sessionID.getUserID(); - this.store.setProperty(userID + ".publicKey", x509EncodedKeySpec - .getEncoded()); - - this.store.removeProperty(userID + ".publicKey.verified"); - } - - public void unverify(SessionID sessionID) { - if (sessionID == null) - return; - - if (!isVerified(sessionID)) - return; - - this.store - .removeProperty(sessionID.getUserID() + ".publicKey.verified"); - - for (OtrKeyManagerListener l : listeners) - l.verificationStatusChanged(sessionID); - - } - - public void verify(SessionID sessionID) { - if (sessionID == null) - return; - - if (this.isVerified(sessionID)) - return; - - this.store.setProperty(sessionID.getUserID() + ".publicKey.verified", - true); - - for (OtrKeyManagerListener l : listeners) - l.verificationStatusChanged(sessionID); - } - -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrKeyManagerListener.java --- a/app/src/main/java/net/java/otr4j/OtrKeyManagerListener.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -package net.java.otr4j; - -import net.java.otr4j.session.SessionID; - -public interface OtrKeyManagerListener { - public abstract void verificationStatusChanged(SessionID session); -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrKeyManagerStore.java --- a/app/src/main/java/net/java/otr4j/OtrKeyManagerStore.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -package net.java.otr4j; - -public interface OtrKeyManagerStore { - public abstract byte[] getPropertyBytes(String id); - - public abstract boolean getPropertyBoolean(String id, boolean defaultValue); - - public abstract void setProperty(String id, byte[] value); - - public abstract void setProperty(String id, boolean value); - - public abstract void removeProperty(String id); -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrPolicy.java --- a/app/src/main/java/net/java/otr4j/OtrPolicy.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j; - -/** - * - * @author George Politis - * - */ -public interface OtrPolicy { - - public static final int ALLOW_V1 = 0x01; - public static final int ALLOW_V2 = 0x02; - public static final int REQUIRE_ENCRYPTION = 0x04; - public static final int SEND_WHITESPACE_TAG = 0x08; - public static final int WHITESPACE_START_AKE = 0x10; - public static final int ERROR_START_AKE = 0x20; - public static final int VERSION_MASK = (ALLOW_V1 | ALLOW_V2); - - // The four old version 1 policies correspond to the following combinations - // of flags (adding an allowance for version 2 of the protocol): - - public static final int NEVER = 0x00; - public static final int OPPORTUNISTIC = (ALLOW_V1 | ALLOW_V2 - | SEND_WHITESPACE_TAG | WHITESPACE_START_AKE | ERROR_START_AKE); - public static final int OTRL_POLICY_MANUAL = (ALLOW_V1 | ALLOW_V2); - public static final int OTRL_POLICY_ALWAYS = (ALLOW_V1 | ALLOW_V2 - | REQUIRE_ENCRYPTION | WHITESPACE_START_AKE | ERROR_START_AKE); - public static final int OTRL_POLICY_DEFAULT = OPPORTUNISTIC; - - public abstract boolean getAllowV1(); - - public abstract boolean getAllowV2(); - - public abstract boolean getRequireEncryption(); - - public abstract boolean getSendWhitespaceTag(); - - public abstract boolean getWhitespaceStartAKE(); - - public abstract boolean getErrorStartAKE(); - - public abstract int getPolicy(); - - public abstract void setAllowV1(boolean value); - - public abstract void setAllowV2(boolean value); - - public abstract void setRequireEncryption(boolean value); - - public abstract void setSendWhitespaceTag(boolean value); - - public abstract void setWhitespaceStartAKE(boolean value); - - public abstract void setErrorStartAKE(boolean value); - - public abstract void setEnableAlways(boolean value); - - public abstract boolean getEnableAlways(); - - public abstract void setEnableManual(boolean value); - - public abstract boolean getEnableManual(); -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/OtrPolicyImpl.java --- a/app/src/main/java/net/java/otr4j/OtrPolicyImpl.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -package net.java.otr4j; - -public class OtrPolicyImpl implements OtrPolicy { - - public OtrPolicyImpl() { - this.setPolicy(NEVER); - } - - public OtrPolicyImpl(int policy) { - this.setPolicy(policy); - } - - private int policy; - - public int getPolicy() { - return policy; - } - - private void setPolicy(int policy) { - this.policy = policy; - } - - public boolean getAllowV1() { - return (policy & OtrPolicy.ALLOW_V1) != 0; - } - - public boolean getAllowV2() { - return (policy & OtrPolicy.ALLOW_V2) != 0; - } - - public boolean getErrorStartAKE() { - return (policy & OtrPolicy.ERROR_START_AKE) != 0; - } - - public boolean getRequireEncryption() { - return getEnableManual() - && (policy & OtrPolicy.REQUIRE_ENCRYPTION) != 0; - } - - public boolean getSendWhitespaceTag() { - return (policy & OtrPolicy.SEND_WHITESPACE_TAG) != 0; - } - - public boolean getWhitespaceStartAKE() { - return (policy & OtrPolicy.WHITESPACE_START_AKE) != 0; - } - - public void setAllowV1(boolean value) { - if (value) - policy |= ALLOW_V1; - else - policy &= ~ALLOW_V1; - } - - public void setAllowV2(boolean value) { - if (value) - policy |= ALLOW_V2; - else - policy &= ~ALLOW_V2; - } - - public void setErrorStartAKE(boolean value) { - if (value) - policy |= ERROR_START_AKE; - else - policy &= ~ERROR_START_AKE; - } - - public void setRequireEncryption(boolean value) { - if (value) - policy |= REQUIRE_ENCRYPTION; - else - policy &= ~REQUIRE_ENCRYPTION; - } - - public void setSendWhitespaceTag(boolean value) { - if (value) - policy |= SEND_WHITESPACE_TAG; - else - policy &= ~SEND_WHITESPACE_TAG; - } - - public void setWhitespaceStartAKE(boolean value) { - if (value) - policy |= WHITESPACE_START_AKE; - else - policy &= ~WHITESPACE_START_AKE; - } - - public boolean getEnableAlways() { - return getEnableManual() && getErrorStartAKE() - && getSendWhitespaceTag() && getWhitespaceStartAKE(); - } - - public void setEnableAlways(boolean value) { - if (value) - setEnableManual(true); - - setErrorStartAKE(value); - setSendWhitespaceTag(value); - setWhitespaceStartAKE(value); - - } - - public boolean getEnableManual() { - return getAllowV1() && getAllowV2(); - } - - public void setEnableManual(boolean value) { - setAllowV1(value); - setAllowV2(value); - } - - public boolean equals(Object obj) { - if (obj == this) - return true; - if (obj == null || obj.getClass() != this.getClass()) - return false; - - OtrPolicy policy = (OtrPolicy) obj; - - return policy.getPolicy() == this.getPolicy(); - } - - public int hashCode() { - return this.getPolicy(); - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/crypto/OtrCryptoEngine.java --- a/app/src/main/java/net/java/otr4j/crypto/OtrCryptoEngine.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -package net.java.otr4j.crypto; - -import java.math.BigInteger; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; - -import javax.crypto.interfaces.DHPublicKey; - -/** - * - * @author George Politis - * - */ -public interface OtrCryptoEngine { - - public static final String MODULUS_TEXT = "00FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"; - public static final BigInteger MODULUS = new BigInteger(MODULUS_TEXT, 16); - public static final BigInteger BIGINTEGER_TWO = BigInteger.valueOf(2); - public static final BigInteger MODULUS_MINUS_TWO = MODULUS - .subtract(BIGINTEGER_TWO); - - public static String GENERATOR_TEXT = "2"; - public static BigInteger GENERATOR = new BigInteger(GENERATOR_TEXT, 10); - - public static final int AES_KEY_BYTE_LENGTH = 16; - public static final int SHA256_HMAC_KEY_BYTE_LENGTH = 32; - public static final int DH_PRIVATE_KEY_MINIMUM_BIT_LENGTH = 320; - public static final byte[] ZERO_CTR = new byte[] { 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00 }; - - public static final int DSA_PUB_TYPE = 0; - - public abstract KeyPair generateDHKeyPair() throws OtrCryptoException; - - public abstract DHPublicKey getDHPublicKey(byte[] mpiBytes) - throws OtrCryptoException; - - public abstract DHPublicKey getDHPublicKey(BigInteger mpi) - throws OtrCryptoException; - - public abstract byte[] sha256Hmac(byte[] b, byte[] key) - throws OtrCryptoException; - - public abstract byte[] sha256Hmac(byte[] b, byte[] key, int length) - throws OtrCryptoException; - - public abstract byte[] sha1Hmac(byte[] b, byte[] key, int length) - throws OtrCryptoException; - - public abstract byte[] sha256Hmac160(byte[] b, byte[] key) - throws OtrCryptoException; - - public abstract byte[] sha256Hash(byte[] b) throws OtrCryptoException; - - public abstract byte[] sha1Hash(byte[] b) throws OtrCryptoException; - - public abstract byte[] aesDecrypt(byte[] key, byte[] ctr, byte[] b) - throws OtrCryptoException; - - public abstract byte[] aesEncrypt(byte[] key, byte[] ctr, byte[] b) - throws OtrCryptoException; - - public abstract BigInteger generateSecret(PrivateKey privKey, - PublicKey pubKey) throws OtrCryptoException; - - public abstract byte[] sign(byte[] b, PrivateKey privatekey) - throws OtrCryptoException; - - public abstract boolean verify(byte[] b, PublicKey pubKey, byte[] rs) - throws OtrCryptoException; - - public abstract String getFingerprint(PublicKey pubKey) - throws OtrCryptoException; -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/crypto/OtrCryptoEngineImpl.java --- a/app/src/main/java/net/java/otr4j/crypto/OtrCryptoEngineImpl.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.crypto; - -import java.io.IOException; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; - -import javax.crypto.KeyAgreement; -import javax.crypto.interfaces.DHPrivateKey; -import javax.crypto.interfaces.DHPublicKey; -import javax.crypto.spec.DHPrivateKeySpec; -import javax.crypto.spec.DHPublicKeySpec; -import javax.crypto.spec.SecretKeySpec; - -import net.java.otr4j.io.SerializationUtils; - -import org.bouncycastle2.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle2.crypto.BufferedBlockCipher; -import org.bouncycastle2.crypto.engines.AESFastEngine; -import org.bouncycastle2.crypto.generators.DHKeyPairGenerator; -import org.bouncycastle2.crypto.modes.SICBlockCipher; -import org.bouncycastle2.crypto.params.DHKeyGenerationParameters; -import org.bouncycastle2.crypto.params.DHParameters; -import org.bouncycastle2.crypto.params.DHPrivateKeyParameters; -import org.bouncycastle2.crypto.params.DHPublicKeyParameters; -import org.bouncycastle2.crypto.params.DSAParameters; -import org.bouncycastle2.crypto.params.DSAPrivateKeyParameters; -import org.bouncycastle2.crypto.params.DSAPublicKeyParameters; -import org.bouncycastle2.crypto.params.KeyParameter; -import org.bouncycastle2.crypto.params.ParametersWithIV; -import org.bouncycastle2.crypto.signers.DSASigner; -import org.bouncycastle2.util.BigIntegers; - -/** - * - * @author George Politis - * - */ -public class OtrCryptoEngineImpl implements OtrCryptoEngine { - - public KeyPair generateDHKeyPair() throws OtrCryptoException { - - // Generate a AsymmetricCipherKeyPair using BC. - DHParameters dhParams = new DHParameters(MODULUS, GENERATOR, null, - DH_PRIVATE_KEY_MINIMUM_BIT_LENGTH); - DHKeyGenerationParameters params = new DHKeyGenerationParameters( - new SecureRandom(), dhParams); - DHKeyPairGenerator kpGen = new DHKeyPairGenerator(); - - kpGen.init(params); - AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); - - // Convert this AsymmetricCipherKeyPair to a standard JCE KeyPair. - DHPublicKeyParameters pub = (DHPublicKeyParameters) pair.getPublic(); - DHPrivateKeyParameters priv = (DHPrivateKeyParameters) pair - .getPrivate(); - - try { - KeyFactory keyFac = KeyFactory.getInstance("DH"); - - DHPublicKeySpec pubKeySpecs = new DHPublicKeySpec(pub.getY(), - MODULUS, GENERATOR); - DHPublicKey pubKey = (DHPublicKey) keyFac - .generatePublic(pubKeySpecs); - - DHParameters dhParameters = priv.getParameters(); - DHPrivateKeySpec privKeySpecs = new DHPrivateKeySpec(priv.getX(), - dhParameters.getP(), dhParameters.getG()); - DHPrivateKey privKey = (DHPrivateKey) keyFac - .generatePrivate(privKeySpecs); - - return new KeyPair(pubKey, privKey); - } catch (Exception e) { - throw new OtrCryptoException(e); - } - } - - public DHPublicKey getDHPublicKey(byte[] mpiBytes) - throws OtrCryptoException { - return getDHPublicKey(new BigInteger(mpiBytes)); - } - - public DHPublicKey getDHPublicKey(BigInteger mpi) throws OtrCryptoException { - DHPublicKeySpec pubKeySpecs = new DHPublicKeySpec(mpi, MODULUS, - GENERATOR); - try { - KeyFactory keyFac = KeyFactory.getInstance("DH"); - return (DHPublicKey) keyFac.generatePublic(pubKeySpecs); - } catch (Exception e) { - throw new OtrCryptoException(e); - } - } - - public byte[] sha256Hmac(byte[] b, byte[] key) throws OtrCryptoException { - return this.sha256Hmac(b, key, 0); - } - - public byte[] sha256Hmac(byte[] b, byte[] key, int length) - throws OtrCryptoException { - - SecretKeySpec keyspec = new SecretKeySpec(key, "HmacSHA256"); - javax.crypto.Mac mac; - try { - mac = javax.crypto.Mac.getInstance("HmacSHA256"); - } catch (NoSuchAlgorithmException e) { - throw new OtrCryptoException(e); - } - try { - mac.init(keyspec); - } catch (InvalidKeyException e) { - throw new OtrCryptoException(e); - } - - byte[] macBytes = mac.doFinal(b); - - if (length > 0) { - byte[] bytes = new byte[length]; - ByteBuffer buff = ByteBuffer.wrap(macBytes); - buff.get(bytes); - return bytes; - } else { - return macBytes; - } - } - - public byte[] sha1Hmac(byte[] b, byte[] key, int length) - throws OtrCryptoException { - - try { - SecretKeySpec keyspec = new SecretKeySpec(key, "HmacSHA1"); - javax.crypto.Mac mac = javax.crypto.Mac.getInstance("HmacSHA1"); - mac.init(keyspec); - - byte[] macBytes = mac.doFinal(b); - - if (length > 0) { - byte[] bytes = new byte[length]; - ByteBuffer buff = ByteBuffer.wrap(macBytes); - buff.get(bytes); - return bytes; - } else { - return macBytes; - } - } catch (Exception e) { - throw new OtrCryptoException(e); - } - } - - public byte[] sha256Hmac160(byte[] b, byte[] key) throws OtrCryptoException { - return sha256Hmac(b, key, 20); - } - - public byte[] sha256Hash(byte[] b) throws OtrCryptoException { - try { - MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); - sha256.update(b, 0, b.length); - return sha256.digest(); - } catch (Exception e) { - throw new OtrCryptoException(e); - } - } - - public byte[] sha1Hash(byte[] b) throws OtrCryptoException { - try { - MessageDigest sha256 = MessageDigest.getInstance("SHA-1"); - sha256.update(b, 0, b.length); - return sha256.digest(); - } catch (Exception e) { - throw new OtrCryptoException(e); - } - } - - public byte[] aesDecrypt(byte[] key, byte[] ctr, byte[] b) - throws OtrCryptoException { - - AESFastEngine aesDec = new AESFastEngine(); - SICBlockCipher sicAesDec = new SICBlockCipher(aesDec); - BufferedBlockCipher bufSicAesDec = new BufferedBlockCipher(sicAesDec); - - // Create initial counter value 0. - if (ctr == null) - ctr = ZERO_CTR; - bufSicAesDec.init(false, new ParametersWithIV(new KeyParameter(key), - ctr)); - byte[] aesOutLwDec = new byte[b.length]; - int done = bufSicAesDec.processBytes(b, 0, b.length, aesOutLwDec, 0); - try { - bufSicAesDec.doFinal(aesOutLwDec, done); - } catch (Exception e) { - throw new OtrCryptoException(e); - } - - return aesOutLwDec; - } - - public byte[] aesEncrypt(byte[] key, byte[] ctr, byte[] b) - throws OtrCryptoException { - - AESFastEngine aesEnc = new AESFastEngine(); - SICBlockCipher sicAesEnc = new SICBlockCipher(aesEnc); - BufferedBlockCipher bufSicAesEnc = new BufferedBlockCipher(sicAesEnc); - - // Create initial counter value 0. - if (ctr == null) - ctr = ZERO_CTR; - bufSicAesEnc.init(true, - new ParametersWithIV(new KeyParameter(key), ctr)); - byte[] aesOutLwEnc = new byte[b.length]; - int done = bufSicAesEnc.processBytes(b, 0, b.length, aesOutLwEnc, 0); - try { - bufSicAesEnc.doFinal(aesOutLwEnc, done); - } catch (Exception e) { - throw new OtrCryptoException(e); - } - return aesOutLwEnc; - } - - public BigInteger generateSecret(PrivateKey privKey, PublicKey pubKey) - throws OtrCryptoException { - try { - KeyAgreement ka = KeyAgreement.getInstance("DH"); - ka.init(privKey); - ka.doPhase(pubKey, true); - byte[] sb = ka.generateSecret(); - BigInteger s = new BigInteger(1, sb); - return s; - - } catch (Exception e) { - throw new OtrCryptoException(e); - } - } - - public byte[] sign(byte[] b, PrivateKey privatekey) - throws OtrCryptoException { - - if (!(privatekey instanceof DSAPrivateKey)) - throw new IllegalArgumentException(); - - DSAParams dsaParams = ((DSAPrivateKey) privatekey).getParams(); - DSAParameters bcDSAParameters = new DSAParameters(dsaParams.getP(), - dsaParams.getQ(), dsaParams.getG()); - - DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) privatekey; - DSAPrivateKeyParameters bcDSAPrivateKeyParms = new DSAPrivateKeyParameters( - dsaPrivateKey.getX(), bcDSAParameters); - - DSASigner dsaSigner = new DSASigner(); - dsaSigner.init(true, bcDSAPrivateKeyParms); - - BigInteger q = dsaParams.getQ(); - - // Ian: Note that if you can get the standard DSA implementation you're - // using to not hash its input, you should be able to pass it ((256-bit - // value) mod q), (rather than truncating the 256-bit value) and all - // should be well. - // ref: Interop problems with libotr - DSA signature - BigInteger bmpi = new BigInteger(1, b); - BigInteger[] rs = dsaSigner.generateSignature(BigIntegers - .asUnsignedByteArray(bmpi.mod(q))); - - int siglen = q.bitLength() / 4; - int rslen = siglen / 2; - byte[] rb = BigIntegers.asUnsignedByteArray(rs[0]); - byte[] sb = BigIntegers.asUnsignedByteArray(rs[1]); - - // Create the final signature array, padded with zeros if necessary. - byte[] sig = new byte[siglen]; - Boolean writeR = false; - Boolean writeS = false; - for (int i = 0; i < siglen; i++) { - if (i < rslen) { - if (!writeR) - writeR = rb.length >= rslen - i; - sig[i] = (writeR) ? rb[i] : (byte) 0x0; - } else { - int j = i - rslen; // Rebase. - if (!writeS) - writeS = sb.length >= rslen - j; - sig[i] = (writeS) ? sb[j] : (byte) 0x0; - } - } - return sig; - } - - public boolean verify(byte[] b, PublicKey pubKey, byte[] rs) - throws OtrCryptoException { - - if (!(pubKey instanceof DSAPublicKey)) - throw new IllegalArgumentException(); - - DSAParams dsaParams = ((DSAPublicKey) pubKey).getParams(); - int qlen = dsaParams.getQ().bitLength() / 8; - ByteBuffer buff = ByteBuffer.wrap(rs); - byte[] r = new byte[qlen]; - buff.get(r); - byte[] s = new byte[qlen]; - buff.get(s); - return verify(b, pubKey, r, s); - } - - private Boolean verify(byte[] b, PublicKey pubKey, byte[] r, byte[] s) - throws OtrCryptoException { - Boolean result = verify(b, pubKey, new BigInteger(1, r), - new BigInteger(1, s)); - return result; - } - - private Boolean verify(byte[] b, PublicKey pubKey, BigInteger r, - BigInteger s) throws OtrCryptoException { - - if (!(pubKey instanceof DSAPublicKey)) - throw new IllegalArgumentException(); - - DSAParams dsaParams = ((DSAPublicKey) pubKey).getParams(); - - BigInteger q = dsaParams.getQ(); - DSAParameters bcDSAParams = new DSAParameters(dsaParams.getP(), q, - dsaParams.getG()); - - DSAPublicKey dsaPrivateKey = (DSAPublicKey) pubKey; - DSAPublicKeyParameters dsaPrivParms = new DSAPublicKeyParameters( - dsaPrivateKey.getY(), bcDSAParams); - - // Ian: Note that if you can get the standard DSA implementation you're - // using to not hash its input, you should be able to pass it ((256-bit - // value) mod q), (rather than truncating the 256-bit value) and all - // should be well. - // ref: Interop problems with libotr - DSA signature - DSASigner dsaSigner = new DSASigner(); - dsaSigner.init(false, dsaPrivParms); - - BigInteger bmpi = new BigInteger(1, b); - Boolean result = dsaSigner.verifySignature(BigIntegers - .asUnsignedByteArray(bmpi.mod(q)), r, s); - return result; - } - - public String getFingerprint(PublicKey pubKey) throws OtrCryptoException { - byte[] b; - try { - byte[] bRemotePubKey = SerializationUtils.writePublicKey(pubKey); - - if (pubKey.getAlgorithm().equals("DSA")) { - byte[] trimmed = new byte[bRemotePubKey.length - 2]; - System.arraycopy(bRemotePubKey, 2, trimmed, 0, trimmed.length); - b = new OtrCryptoEngineImpl().sha1Hash(trimmed); - } else - b = new OtrCryptoEngineImpl().sha1Hash(bRemotePubKey); - } catch (IOException e) { - throw new OtrCryptoException(e); - } - return this.byteArrayToHexString(b); - } - - private String byteArrayToHexString(byte in[]) { - byte ch = 0x00; - int i = 0; - if (in == null || in.length <= 0) - return null; - String pseudo[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "A", "B", "C", "D", "E", "F" }; - StringBuffer out = new StringBuffer(in.length * 2); - while (i < in.length) { - ch = (byte) (in[i] & 0xF0); - ch = (byte) (ch >>> 4); - ch = (byte) (ch & 0x0F); - out.append(pseudo[(int) ch]); - ch = (byte) (in[i] & 0x0F); - out.append(pseudo[(int) ch]); - i++; - } - - String rslt = new String(out); - return rslt; - - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/crypto/OtrCryptoException.java --- a/app/src/main/java/net/java/otr4j/crypto/OtrCryptoException.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -package net.java.otr4j.crypto; - -import net.java.otr4j.OtrException; - -@SuppressWarnings("serial") -public class OtrCryptoException extends OtrException { - - public OtrCryptoException(Exception e) { - super(e); - } - -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/OtrInputStream.java --- a/app/src/main/java/net/java/otr4j/io/OtrInputStream.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -package net.java.otr4j.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPublicKey; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.InvalidKeySpecException; - -import javax.crypto.interfaces.DHPublicKey; - -import net.java.otr4j.crypto.OtrCryptoEngineImpl; -import net.java.otr4j.io.messages.SignatureX; - -public class OtrInputStream extends FilterInputStream implements - SerializationConstants { - - public OtrInputStream(InputStream in) { - super(in); - } - - private int readNumber(int length) throws IOException { - byte[] b = new byte[length]; - read(b); - - int value = 0; - for (int i = 0; i < b.length; i++) { - int shift = (b.length - 1 - i) * 8; - value += (b[i] & 0x000000FF) << shift; - } - - return value; - } - - public int readByte() throws IOException { - return readNumber(TYPE_LEN_BYTE); - } - - public int readInt() throws IOException { - return readNumber(TYPE_LEN_INT); - } - - public int readShort() throws IOException { - return readNumber(TYPE_LEN_SHORT); - } - - public byte[] readCtr() throws IOException { - byte[] b = new byte[TYPE_LEN_CTR]; - read(b); - return b; - } - - public byte[] readMac() throws IOException { - byte[] b = new byte[TYPE_LEN_MAC]; - read(b); - return b; - } - - public BigInteger readBigInt() throws IOException { - byte[] b = readData(); - return new BigInteger(1, b); - } - - public byte[] readData() throws IOException { - int dataLen = readNumber(DATA_LEN); - byte[] b = new byte[dataLen]; - read(b); - return b; - } - - public PublicKey readPublicKey() throws IOException { - int type = readShort(); - switch (type) { - case 0: - BigInteger p = readBigInt(); - BigInteger q = readBigInt(); - BigInteger g = readBigInt(); - BigInteger y = readBigInt(); - DSAPublicKeySpec keySpec = new DSAPublicKeySpec(y, p, q, g); - KeyFactory keyFactory; - try { - keyFactory = KeyFactory.getInstance("DSA"); - } catch (NoSuchAlgorithmException e) { - throw new IOException(); - } - try { - return keyFactory.generatePublic(keySpec); - } catch (InvalidKeySpecException e) { - throw new IOException(); - } - default: - throw new UnsupportedOperationException(); - } - } - - public DHPublicKey readDHPublicKey() throws IOException { - BigInteger gyMpi = readBigInt(); - try { - return new OtrCryptoEngineImpl().getDHPublicKey(gyMpi); - } catch (Exception ex) { - throw new IOException(); - } - } - - public byte[] readTlvData() throws IOException { - int len = readNumber(TYPE_LEN_BYTE); - - byte[] b = new byte[len]; - in.read(b); - return b; - } - - public byte[] readSignature(PublicKey pubKey) throws IOException { - if (!pubKey.getAlgorithm().equals("DSA")) - throw new UnsupportedOperationException(); - - DSAPublicKey dsaPubKey = (DSAPublicKey) pubKey; - DSAParams dsaParams = dsaPubKey.getParams(); - byte[] sig = new byte[dsaParams.getQ().bitLength() / 4]; - read(sig); - return sig; - } - - public SignatureX readMysteriousX() throws IOException { - PublicKey pubKey = readPublicKey(); - int dhKeyID = readInt(); - byte[] sig = readSignature(pubKey); - return new SignatureX(pubKey, dhKeyID, sig); - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/OtrOutputStream.java --- a/app/src/main/java/net/java/otr4j/io/OtrOutputStream.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -package net.java.otr4j.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.PublicKey; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPublicKey; - -import javax.crypto.interfaces.DHPublicKey; - -import net.java.otr4j.io.messages.SignatureM; -import net.java.otr4j.io.messages.MysteriousT; -import net.java.otr4j.io.messages.SignatureX; - -import org.bouncycastle2.util.BigIntegers; - -public class OtrOutputStream extends FilterOutputStream implements - SerializationConstants { - - public OtrOutputStream(OutputStream out) { - super(out); - } - - private void writeNumber(int value, int length) throws IOException { - byte[] b = new byte[length]; - for (int i = 0; i < length; i++) { - int offset = (b.length - 1 - i) * 8; - b[i] = (byte) ((value >>> offset) & 0xFF); - } - write(b); - } - - public void writeBigInt(BigInteger bi) throws IOException { - byte[] b = BigIntegers.asUnsignedByteArray(bi); - writeData(b); - } - - public void writeByte(int b) throws IOException { - writeNumber(b, TYPE_LEN_BYTE); - } - - public void writeData(byte[] b) throws IOException { - int len = (b == null || b.length < 0) ? 0 : b.length; - writeNumber(len, DATA_LEN); - if (len > 0) - write(b); - } - - public void writeInt(int i) throws IOException { - writeNumber(i, TYPE_LEN_INT); - - } - - public void writeShort(int s) throws IOException { - writeNumber(s, TYPE_LEN_SHORT); - - } - - public void writeMac(byte[] mac) throws IOException { - if (mac == null || mac.length != TYPE_LEN_MAC) - throw new IllegalArgumentException(); - - write(mac); - } - - public void writeCtr(byte[] ctr) throws IOException { - if (ctr == null || ctr.length < 1) - return; - - int i = 0; - while (i < TYPE_LEN_CTR && i < ctr.length) { - write(ctr[i]); - i++; - } - } - - public void writeDHPublicKey(DHPublicKey dhPublicKey) throws IOException { - byte[] b = BigIntegers.asUnsignedByteArray(dhPublicKey.getY()); - writeData(b); - } - - public void writePublicKey(PublicKey pubKey) throws IOException { - if (!(pubKey instanceof DSAPublicKey)) - throw new UnsupportedOperationException( - "Key types other than DSA are not supported at the moment."); - - DSAPublicKey dsaKey = (DSAPublicKey) pubKey; - - writeShort(0); - - DSAParams dsaParams = dsaKey.getParams(); - writeBigInt(dsaParams.getP()); - writeBigInt(dsaParams.getQ()); - writeBigInt(dsaParams.getG()); - writeBigInt(dsaKey.getY()); - - } - - public void writeTlvData(byte[] b) throws IOException { - int len = (b == null || b.length < 0) ? 0 : b.length; - writeNumber(len, TLV_LEN); - if (len > 0) - write(b); - } - - public void writeSignature(byte[] signature, PublicKey pubKey) - throws IOException { - if (!pubKey.getAlgorithm().equals("DSA")) - throw new UnsupportedOperationException(); - out.write(signature); - } - - public void writeMysteriousX(SignatureX x) throws IOException { - writePublicKey(x.longTermPublicKey); - writeInt(x.dhKeyID); - writeSignature(x.signature, x.longTermPublicKey); - } - - public void writeMysteriousX(SignatureM m) throws IOException { - writeBigInt(m.localPubKey.getY()); - writeBigInt(m.remotePubKey.getY()); - writePublicKey(m.localLongTermPubKey); - writeInt(m.keyPairID); - } - - public void writeMysteriousT(MysteriousT t) throws IOException { - writeShort(t.protocolVersion); - writeByte(t.messageType); - writeByte(t.flags); - - writeInt(t.senderKeyID); - writeInt(t.recipientKeyID); - writeDHPublicKey(t.nextDH); - writeCtr(t.ctr); - writeData(t.encryptedMessage); - - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/SerializationConstants.java --- a/app/src/main/java/net/java/otr4j/io/SerializationConstants.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io; - -/** - * - * @author George Politis - */ -public interface SerializationConstants { - - public static final String HEAD = "?OTR"; - public static final char HEAD_ENCODED = ':'; - public static final char HEAD_ERROR = ' '; - public static final char HEAD_QUERY_Q = '?'; - public static final char HEAD_QUERY_V = 'v'; - - public static final int TYPE_LEN_BYTE = 1; - public static final int TYPE_LEN_SHORT = 2; - public static final int TYPE_LEN_INT = 4; - public static final int TYPE_LEN_MAC = 20; - public static final int TYPE_LEN_CTR = 8; - - public static final int DATA_LEN = TYPE_LEN_INT; - public static final int TLV_LEN = TYPE_LEN_SHORT; -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/SerializationUtils.java --- a/app/src/main/java/net/java/otr4j/io/SerializationUtils.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,341 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.math.BigInteger; -import java.security.PublicKey; -import java.util.List; -import java.util.Vector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.crypto.interfaces.DHPublicKey; - -import org.bouncycastle2.util.encoders.Base64; - -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.DataMessage; -import net.java.otr4j.io.messages.ErrorMessage; -import net.java.otr4j.io.messages.MysteriousT; -import net.java.otr4j.io.messages.PlainTextMessage; -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 - */ -public class SerializationUtils { - // Mysterious X IO. - public static SignatureX toMysteriousX(byte[] b) throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream(b); - OtrInputStream ois = new OtrInputStream(in); - SignatureX x = ois.readMysteriousX(); - ois.close(); - return x; - } - - public static byte[] toByteArray(SignatureX x) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - OtrOutputStream oos = new OtrOutputStream(out); - oos.writeMysteriousX(x); - byte[] b = out.toByteArray(); - oos.close(); - return b; - } - - // Mysterious M IO. - public static byte[] toByteArray(SignatureM m) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - OtrOutputStream oos = new OtrOutputStream(out); - oos.writeMysteriousX(m); - byte[] b = out.toByteArray(); - oos.close(); - return b; - } - - // Mysterious T IO. - public static byte[] toByteArray(MysteriousT t) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - OtrOutputStream oos = new OtrOutputStream(out); - oos.writeMysteriousT(t); - byte[] b = out.toByteArray(); - oos.close(); - return b; - } - - // Basic IO. - public static byte[] writeData(byte[] b) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - OtrOutputStream oos = new OtrOutputStream(out); - oos.writeData(b); - byte[] otrb = out.toByteArray(); - oos.close(); - return otrb; - } - - // BigInteger IO. - public static byte[] writeMpi(BigInteger bigInt) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - OtrOutputStream oos = new OtrOutputStream(out); - oos.writeBigInt(bigInt); - byte[] b = out.toByteArray(); - oos.close(); - return b; - } - - public static BigInteger readMpi(byte[] b) throws IOException { - ByteArrayInputStream in = new ByteArrayInputStream(b); - OtrInputStream ois = new OtrInputStream(in); - BigInteger bigint = ois.readBigInt(); - ois.close(); - return bigint; - } - - // Public Key IO. - public static byte[] writePublicKey(PublicKey pubKey) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - OtrOutputStream oos = new OtrOutputStream(out); - oos.writePublicKey(pubKey); - byte[] b = out.toByteArray(); - oos.close(); - return b; - } - - // Message IO. - public static String toString(AbstractMessage m) throws IOException { - StringWriter writer = new StringWriter(); - writer.write(SerializationConstants.HEAD); - - switch (m.messageType) { - case AbstractMessage.MESSAGE_ERROR: - ErrorMessage error = (ErrorMessage) m; - writer.write(SerializationConstants.HEAD_ERROR); - writer.write(error.error); - break; - case AbstractMessage.MESSAGE_PLAINTEXT: - PlainTextMessage plaintxt = (PlainTextMessage) m; - writer.write(plaintxt.cleanText); - if (plaintxt.versions != null && plaintxt.versions.size() > 0) { - writer.write(" \\t \\t\\t\\t\\t \\t \\t \\t "); - for (int version : plaintxt.versions) { - if (version == 1) - writer.write(" \\t\\t \\t "); - - if (version == 2) - writer.write(" \\t \\t \\t "); - } - } - break; - case AbstractMessage.MESSAGE_QUERY: - QueryMessage query = (QueryMessage) m; - if (query.versions.size() == 1 && query.versions.get(0) == 1) { - writer.write(SerializationConstants.HEAD_QUERY_Q); - } else { - writer.write(SerializationConstants.HEAD_QUERY_V); - for (int version : query.versions) - writer.write(String.valueOf(version)); - - writer.write(SerializationConstants.HEAD_QUERY_Q); - } - break; - case AbstractEncodedMessage.MESSAGE_DHKEY: - case AbstractEncodedMessage.MESSAGE_REVEALSIG: - case AbstractEncodedMessage.MESSAGE_SIGNATURE: - case AbstractEncodedMessage.MESSAGE_DH_COMMIT: - case AbstractEncodedMessage.MESSAGE_DATA: - ByteArrayOutputStream o = new ByteArrayOutputStream(); - OtrOutputStream s = new OtrOutputStream(o); - - switch (m.messageType) { - case AbstractEncodedMessage.MESSAGE_DHKEY: - DHKeyMessage dhkey = (DHKeyMessage) m; - s.writeShort(dhkey.protocolVersion); - s.writeByte(dhkey.messageType); - s.writeDHPublicKey(dhkey.dhPublicKey); - break; - case AbstractEncodedMessage.MESSAGE_REVEALSIG: - RevealSignatureMessage revealsig = (RevealSignatureMessage) m; - s.writeShort(revealsig.protocolVersion); - s.writeByte(revealsig.messageType); - s.writeData(revealsig.revealedKey); - s.writeData(revealsig.xEncrypted); - s.writeMac(revealsig.xEncryptedMAC); - break; - case AbstractEncodedMessage.MESSAGE_SIGNATURE: - SignatureMessage sig = (SignatureMessage) m; - s.writeShort(sig.protocolVersion); - s.writeByte(sig.messageType); - s.writeData(sig.xEncrypted); - s.writeMac(sig.xEncryptedMAC); - break; - case AbstractEncodedMessage.MESSAGE_DH_COMMIT: - DHCommitMessage dhcommit = (DHCommitMessage) m; - s.writeShort(dhcommit.protocolVersion); - s.writeByte(dhcommit.messageType); - s.writeData(dhcommit.dhPublicKeyEncrypted); - s.writeData(dhcommit.dhPublicKeyHash); - break; - case AbstractEncodedMessage.MESSAGE_DATA: - DataMessage data = (DataMessage) m; - s.writeShort(data.protocolVersion); - s.writeByte(data.messageType); - s.writeByte(data.flags); - s.writeInt(data.senderKeyID); - s.writeInt(data.recipientKeyID); - s.writeDHPublicKey(data.nextDH); - s.writeCtr(data.ctr); - s.writeData(data.encryptedMessage); - s.writeMac(data.mac); - s.writeData(data.oldMACKeys); - break; - } - - writer.write(SerializationConstants.HEAD_ENCODED); - writer.write(new String(Base64.encode(o.toByteArray()))); - writer.write("."); - break; - default: - throw new IOException("Illegal message type."); - } - - return writer.toString(); - } - - static final Pattern patternWhitespace = Pattern - .compile("( \\t \\t\\t\\t\\t \\t \\t \\t )( \\t\\t \\t )?( \\t \\t \\t )?"); - - public static AbstractMessage toMessage(String s) throws IOException { - if (s == null || s.length() <= 1) - return null; - - if (s.indexOf(SerializationConstants.HEAD) != 0 - || s.length() <= SerializationConstants.HEAD.length()) { - // Try to detect whitespace tag. - final Matcher matcher = patternWhitespace.matcher(s); - - boolean v1 = false; - boolean v2 = false; - while (matcher.find()) { - if (!v1 && matcher.start(2) > -1) - v1 = true; - - if (!v2 && matcher.start(3) > -1) - v2 = true; - - if (v1 && v2) - break; - } - - String cleanText = matcher.replaceAll(""); - List versions; - if (v1 && v2) { - versions = new Vector(2); - versions.add(0, 1); - versions.add(0, 2); - } else if (v1) { - versions = new Vector(1); - versions.add(0, 1); - } else if (v2) { - versions = new Vector(1); - versions.add(2); - } else - versions = null; - - return new PlainTextMessage(versions, cleanText); - } else { - char contentType = s.charAt(SerializationConstants.HEAD.length()); - String content = s - .substring(SerializationConstants.HEAD.length() + 1); - switch (contentType) { - case SerializationConstants.HEAD_ENCODED: - ByteArrayInputStream bin = new ByteArrayInputStream(Base64 - .decode(content.getBytes())); - OtrInputStream otr = new OtrInputStream(bin); - // We have an encoded message. - int protocolVersion = otr.readShort(); - int messageType = otr.readByte(); - switch (messageType) { - case AbstractEncodedMessage.MESSAGE_DATA: - int flags = otr.readByte(); - int senderKeyID = otr.readInt(); - int recipientKeyID = otr.readInt(); - DHPublicKey nextDH = otr.readDHPublicKey(); - byte[] ctr = otr.readCtr(); - byte[] encryptedMessage = otr.readData(); - byte[] mac = otr.readMac(); - byte[] oldMacKeys = otr.readMac(); - return new DataMessage(protocolVersion, flags, senderKeyID, - recipientKeyID, nextDH, ctr, encryptedMessage, mac, - oldMacKeys); - case AbstractEncodedMessage.MESSAGE_DH_COMMIT: - byte[] dhPublicKeyEncrypted = otr.readData(); - byte[] dhPublicKeyHash = otr.readData(); - return new DHCommitMessage(protocolVersion, - dhPublicKeyHash, dhPublicKeyEncrypted); - case AbstractEncodedMessage.MESSAGE_DHKEY: - DHPublicKey dhPublicKey = otr.readDHPublicKey(); - return new DHKeyMessage(protocolVersion, dhPublicKey); - case AbstractEncodedMessage.MESSAGE_REVEALSIG: { - byte[] revealedKey = otr.readData(); - byte[] xEncrypted = otr.readData(); - byte[] xEncryptedMac = otr.readMac(); - return new RevealSignatureMessage(protocolVersion, - xEncrypted, xEncryptedMac, revealedKey); - } - case AbstractEncodedMessage.MESSAGE_SIGNATURE: { - byte[] xEncryted = otr.readData(); - byte[] xEncryptedMac = otr.readMac(); - return new SignatureMessage(protocolVersion, xEncryted, - xEncryptedMac); - } - default: - throw new IOException("Illegal message type."); - } - case SerializationConstants.HEAD_ERROR: - return new ErrorMessage(AbstractMessage.MESSAGE_ERROR, content); - case SerializationConstants.HEAD_QUERY_V: - case SerializationConstants.HEAD_QUERY_Q: - List versions = new Vector(); - String versionString = null; - if (SerializationConstants.HEAD_QUERY_Q == contentType) { - versions.add(1); - if (content.charAt(0) == 'v') { - versionString = content.substring(1, content - .indexOf('?')); - } - } else if (SerializationConstants.HEAD_QUERY_V == contentType) { - versionString = content.substring(0, content.indexOf('?')); - } - - if (versionString != null) { - StringReader sr = new StringReader(versionString); - int c; - while ((c = sr.read()) != -1) - if (!versions.contains(c)) - versions.add(Integer.parseInt(String - .valueOf((char) c))); - } - QueryMessage query = new QueryMessage(versions); - return query; - default: - throw new IOException("Uknown message type."); - } - } - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/AbstractEncodedMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/AbstractEncodedMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -/** - * - * @author George Politis - */ -public abstract class AbstractEncodedMessage extends AbstractMessage { - // Fields. - public int protocolVersion; - - // Ctor. - public AbstractEncodedMessage(int messageType, int protocolVersion) { - super(messageType); - this.protocolVersion = protocolVersion; - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + protocolVersion; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - AbstractEncodedMessage other = (AbstractEncodedMessage) obj; - if (protocolVersion != other.protocolVersion) - return false; - return true; - } - - // Encoded Message Types - public static final int MESSAGE_DH_COMMIT = 0x02; - public static final int MESSAGE_DATA = 0x03; - public static final int MESSAGE_DHKEY = 0x0a; - public static final int MESSAGE_REVEALSIG = 0x11; - public static final int MESSAGE_SIGNATURE = 0x12; -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/AbstractMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/AbstractMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -/** - * - * @author George Politis - */ -public abstract class AbstractMessage { - // Fields. - public int messageType; - - // Ctor. - public AbstractMessage(int messageType) { - this.messageType = messageType; - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + messageType; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - AbstractMessage other = (AbstractMessage) obj; - if (messageType != other.messageType) - return false; - return true; - } - - // Unencoded - public static final int MESSAGE_ERROR = 0xff; - public static final int MESSAGE_QUERY = 0x100; - public static final int MESSAGE_PLAINTEXT = 0x102; -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/DHCommitMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/DHCommitMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import java.util.Arrays; - -/** - * - * @author George Politis - */ -public class DHCommitMessage extends AbstractEncodedMessage { - - // Fields. - public byte[] dhPublicKeyEncrypted; - public byte[] dhPublicKeyHash; - - // Ctor. - public DHCommitMessage(int protocolVersion, byte[] dhPublicKeyHash, - byte[] dhPublicKeyEncrypted) { - super(MESSAGE_DH_COMMIT, protocolVersion); - this.dhPublicKeyEncrypted = dhPublicKeyEncrypted; - this.dhPublicKeyHash = dhPublicKeyHash; - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(dhPublicKeyEncrypted); - result = prime * result + Arrays.hashCode(dhPublicKeyHash); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - DHCommitMessage other = (DHCommitMessage) obj; - if (!Arrays.equals(dhPublicKeyEncrypted, other.dhPublicKeyEncrypted)) - return false; - if (!Arrays.equals(dhPublicKeyHash, other.dhPublicKeyHash)) - return false; - return true; - } - -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/DHKeyMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/DHKeyMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import javax.crypto.interfaces.DHPublicKey; - -/** - * - * @author George Politis - */ -public class DHKeyMessage extends AbstractEncodedMessage { - - // Fields. - public DHPublicKey dhPublicKey; - - // Ctor. - public DHKeyMessage(int protocolVersion, DHPublicKey dhPublicKey) { - super(MESSAGE_DHKEY, protocolVersion); - this.dhPublicKey = dhPublicKey; - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - // TODO: Needs work. - result = prime * result - + ((dhPublicKey == null) ? 0 : dhPublicKey.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - DHKeyMessage other = (DHKeyMessage) obj; - if (dhPublicKey == null) { - if (other.dhPublicKey != null) - return false; - } else if (dhPublicKey.getY().compareTo(other.dhPublicKey.getY()) != 0) - return false; - return true; - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/DataMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/DataMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import java.util.Arrays; - -import javax.crypto.interfaces.DHPublicKey; - -/** - * - * @author George Politis - */ -public class DataMessage extends AbstractEncodedMessage { - - // Fields. - public byte[] mac; - public byte[] oldMACKeys; - - public int flags; - public int senderKeyID; - public int recipientKeyID; - public DHPublicKey nextDH; - public byte[] ctr; - public byte[] encryptedMessage; - - // Ctor. - public DataMessage(int protocolVersion, int flags, int senderKeyID, - int recipientKeyID, DHPublicKey nextDH, byte[] ctr, - byte[] encryptedMessage, byte[] mac, byte[] oldMacKeys) { - super(MESSAGE_DATA, protocolVersion); - - this.flags = flags; - this.senderKeyID = senderKeyID; - this.recipientKeyID = recipientKeyID; - this.nextDH = nextDH; - this.ctr = ctr; - this.encryptedMessage = encryptedMessage; - this.mac = mac; - this.oldMACKeys = oldMacKeys; - } - - public DataMessage(MysteriousT t, byte[] mac, byte[] oldMacKeys) { - this(t.protocolVersion, t.flags, t.senderKeyID, t.recipientKeyID, - t.nextDH, t.ctr, t.encryptedMessage, mac, oldMacKeys); - } - - // Methods. - public MysteriousT getT() { - return new MysteriousT(protocolVersion, flags, senderKeyID, - recipientKeyID, nextDH, ctr, encryptedMessage); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(ctr); - result = prime * result + Arrays.hashCode(encryptedMessage); - result = prime * result + flags; - result = prime * result + Arrays.hashCode(mac); - // TODO: Needs work. - result = prime * result + ((nextDH == null) ? 0 : nextDH.hashCode()); - result = prime * result + Arrays.hashCode(oldMACKeys); - result = prime * result + recipientKeyID; - result = prime * result + senderKeyID; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - DataMessage other = (DataMessage) obj; - if (!Arrays.equals(ctr, other.ctr)) - return false; - if (!Arrays.equals(encryptedMessage, other.encryptedMessage)) - return false; - if (flags != other.flags) - return false; - if (!Arrays.equals(mac, other.mac)) - return false; - if (nextDH == null) { - if (other.nextDH != null) - return false; - } else if (!nextDH.equals(other.nextDH)) - return false; - if (!Arrays.equals(oldMACKeys, other.oldMACKeys)) - return false; - if (recipientKeyID != other.recipientKeyID) - return false; - if (senderKeyID != other.senderKeyID) - return false; - return true; - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/ErrorMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/ErrorMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -/** - * - * @author George Politis - */ -public class ErrorMessage extends AbstractMessage { - // Fields. - public String error; - - // Ctor. - public ErrorMessage(int messageType, String error) { - super(messageType); - this.error = error; - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((error == null) ? 0 : error.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - ErrorMessage other = (ErrorMessage) obj; - if (error == null) { - if (other.error != null) - return false; - } else if (!error.equals(other.error)) - return false; - return true; - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/MysteriousT.java --- a/app/src/main/java/net/java/otr4j/io/messages/MysteriousT.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -package net.java.otr4j.io.messages; - -import java.util.Arrays; - -import javax.crypto.interfaces.DHPublicKey; - -public class MysteriousT { - // Fields. - public int protocolVersion; - public int messageType; - public int flags; - public int senderKeyID; - public int recipientKeyID; - public DHPublicKey nextDH; - public byte[] ctr; - public byte[] encryptedMessage; - - // Ctor. - public MysteriousT(int protocolVersion, int flags, int senderKeyID, - int recipientKeyID, DHPublicKey nextDH, byte[] ctr, - byte[] encryptedMessage) { - - this.protocolVersion = protocolVersion; - this.messageType = AbstractEncodedMessage.MESSAGE_DATA; - this.flags = flags; - this.senderKeyID = senderKeyID; - this.recipientKeyID = recipientKeyID; - this.nextDH = nextDH; - this.ctr = ctr; - this.encryptedMessage = encryptedMessage; - } - - // Methods. - @Override - public int hashCode() { - // TODO: Needs work. - final int prime = 31; - int result = 1; - result = prime * result + Arrays.hashCode(ctr); - result = prime * result + Arrays.hashCode(encryptedMessage); - result = prime * result + flags; - result = prime * result + messageType; - result = prime * result + ((nextDH == null) ? 0 : nextDH.hashCode()); - result = prime * result + protocolVersion; - result = prime * result + recipientKeyID; - result = prime * result + senderKeyID; - return result; - } - - @Override - public boolean equals(Object obj) { - // TODO: Needs work. - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - MysteriousT other = (MysteriousT) obj; - if (!Arrays.equals(ctr, other.ctr)) - return false; - if (!Arrays.equals(encryptedMessage, other.encryptedMessage)) - return false; - if (flags != other.flags) - return false; - if (messageType != other.messageType) - return false; - if (nextDH == null) { - if (other.nextDH != null) - return false; - } else if (!nextDH.equals(other.nextDH)) - return false; - if (protocolVersion != other.protocolVersion) - return false; - if (recipientKeyID != other.recipientKeyID) - return false; - if (senderKeyID != other.senderKeyID) - return false; - return true; - } - -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/PlainTextMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/PlainTextMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import java.util.List; - -/** - * - * @author George Politis - */ -public class PlainTextMessage extends QueryMessage { - // Fields. - public String cleanText; - - // Ctor. - public PlainTextMessage(List versions, String cleanText) { - super(MESSAGE_PLAINTEXT, versions); - this.cleanText = cleanText; - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((cleanText == null) ? 0 : cleanText.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - PlainTextMessage other = (PlainTextMessage) obj; - if (cleanText == null) { - if (other.cleanText != null) - return false; - } else if (!cleanText.equals(other.cleanText)) - return false; - return true; - } - -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/QueryMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/QueryMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import java.util.List; - -/** - * - * @author George Politis - */ -public class QueryMessage extends AbstractMessage { - // Fields. - public List versions; - - // Ctor. - protected QueryMessage(int messageType, List versions) { - super(messageType); - this.versions = versions; - } - - public QueryMessage(List versions) { - this(MESSAGE_QUERY, versions); - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((versions == null) ? 0 : versions.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - QueryMessage other = (QueryMessage) obj; - if (versions == null) { - if (other.versions != null) - return false; - } else if (!versions.equals(other.versions)) - return false; - return true; - } - -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/RevealSignatureMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/RevealSignatureMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import java.util.Arrays; - -/** - * - * @author George Politis - */ -public class RevealSignatureMessage extends SignatureMessage { - // Fields. - public byte[] revealedKey; - - // Ctor. - public RevealSignatureMessage(int protocolVersion, byte[] xEncrypted, - byte[] xEncryptedMAC, byte[] revealedKey) { - super(MESSAGE_REVEALSIG, protocolVersion, xEncrypted, xEncryptedMAC); - - this.revealedKey = revealedKey; - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(revealedKey); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - RevealSignatureMessage other = (RevealSignatureMessage) obj; - if (!Arrays.equals(revealedKey, other.revealedKey)) - return false; - return true; - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/SignatureM.java --- a/app/src/main/java/net/java/otr4j/io/messages/SignatureM.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import java.security.PublicKey; - -import javax.crypto.interfaces.DHPublicKey; - -/** - * - * @author George Politis - */ -public class SignatureM { - // Fields. - public DHPublicKey localPubKey; - public DHPublicKey remotePubKey; - public PublicKey localLongTermPubKey; - public int keyPairID; - - // Ctor. - public SignatureM(DHPublicKey localPubKey, DHPublicKey remotePublicKey, - PublicKey localLongTermPublicKey, int keyPairID) { - - this.localPubKey = localPubKey; - this.remotePubKey = remotePublicKey; - this.localLongTermPubKey = localLongTermPublicKey; - this.keyPairID = keyPairID; - } - - // Methods. - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + keyPairID; - // TODO: Needs work. - result = prime - * result - + ((localLongTermPubKey == null) ? 0 : localLongTermPubKey - .hashCode()); - result = prime * result - + ((localPubKey == null) ? 0 : localPubKey.hashCode()); - result = prime * result - + ((remotePubKey == null) ? 0 : remotePubKey.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - // TODO: Needs work. - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - SignatureM other = (SignatureM) obj; - if (keyPairID != other.keyPairID) - return false; - if (localLongTermPubKey == null) { - if (other.localLongTermPubKey != null) - return false; - } else if (!localLongTermPubKey.equals(other.localLongTermPubKey)) - return false; - if (localPubKey == null) { - if (other.localPubKey != null) - return false; - } else if (!localPubKey.equals(other.localPubKey)) - return false; - if (remotePubKey == null) { - if (other.remotePubKey != null) - return false; - } else if (!remotePubKey.equals(other.remotePubKey)) - return false; - return true; - } - -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/SignatureMessage.java --- a/app/src/main/java/net/java/otr4j/io/messages/SignatureMessage.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import java.io.IOException; -import java.util.Arrays; - -import net.java.otr4j.OtrException; -import net.java.otr4j.crypto.OtrCryptoEngineImpl; -import net.java.otr4j.io.SerializationUtils; - -/** - * - * @author George Politis - */ -public class SignatureMessage extends AbstractEncodedMessage { - // Fields. - public byte[] xEncrypted; - public byte[] xEncryptedMAC; - - // Ctor. - protected SignatureMessage(int messageType, int protocolVersion, - byte[] xEncrypted, byte[] xEncryptedMAC) { - super(messageType, protocolVersion); - this.xEncrypted = xEncrypted; - this.xEncryptedMAC = xEncryptedMAC; - } - - public SignatureMessage(int protocolVersion, byte[] xEncrypted, - byte[] xEncryptedMAC) { - this(MESSAGE_SIGNATURE, protocolVersion, xEncrypted, xEncryptedMAC); - } - - // Memthods. - public byte[] decrypt(byte[] key) throws OtrException { - return new OtrCryptoEngineImpl().aesDecrypt(key, null, xEncrypted); - } - - public boolean verify(byte[] key) throws OtrException { - // Hash the key. - byte[] xbEncrypted; - try { - xbEncrypted = SerializationUtils.writeData(xEncrypted); - } catch (IOException e) { - throw new OtrException(e); - } - - byte[] xEncryptedMAC = new OtrCryptoEngineImpl().sha256Hmac160( - xbEncrypted, key); - // Verify signature. - return Arrays.equals(xEncryptedMAC, xEncryptedMAC); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(xEncrypted); - result = prime * result + Arrays.hashCode(xEncryptedMAC); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - SignatureMessage other = (SignatureMessage) obj; - if (!Arrays.equals(xEncrypted, other.xEncrypted)) - return false; - if (!Arrays.equals(xEncryptedMAC, other.xEncryptedMAC)) - return false; - return true; - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/io/messages/SignatureX.java --- a/app/src/main/java/net/java/otr4j/io/messages/SignatureX.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.io.messages; - -import java.security.PublicKey; -import java.util.Arrays; - -/** - * - * @author George Politis - */ -public class SignatureX { - // Fields. - public PublicKey longTermPublicKey; - public int dhKeyID; - public byte[] signature; - - // Ctor. - public SignatureX(PublicKey ourLongTermPublicKey, int ourKeyID, - byte[] signature) { - this.longTermPublicKey = ourLongTermPublicKey; - this.dhKeyID = ourKeyID; - this.signature = signature; - } - - // Methods. - @Override - public int hashCode() { - // TODO: Needs work. - final int prime = 31; - int result = 1; - result = prime * result + dhKeyID; - result = prime - * result - + ((longTermPublicKey == null) ? 0 : longTermPublicKey - .hashCode()); - result = prime * result + Arrays.hashCode(signature); - return result; - } - - @Override - public boolean equals(Object obj) { - // TODO: Needs work. - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - SignatureX other = (SignatureX) obj; - if (dhKeyID != other.dhKeyID) - return false; - if (longTermPublicKey == null) { - if (other.longTermPublicKey != null) - return false; - } else if (!longTermPublicKey.equals(other.longTermPublicKey)) - return false; - if (!Arrays.equals(signature, other.signature)) - return false; - return true; - } - -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/session/AuthContext.java --- a/app/src/main/java/net/java/otr4j/session/AuthContext.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * 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.security.KeyPair; -import java.security.PublicKey; - -import javax.crypto.interfaces.DHPublicKey; - -import net.java.otr4j.OtrException; -import net.java.otr4j.io.messages.AbstractMessage; - -/** - * - * @author George Politis - */ -interface AuthContext { - - public static final int NONE = 0; - public static final int AWAITING_DHKEY = 1; - public static final int AWAITING_REVEALSIG = 2; - public static final int AWAITING_SIG = 3; - public static final int V1_SETUP = 4; - public static final byte C_START = (byte) 0x01; - public static final byte M1_START = (byte) 0x02; - public static final byte M2_START = (byte) 0x03; - public static final byte M1p_START = (byte) 0x04; - public static final byte M2p_START = (byte) 0x05; - - public abstract void reset(); - - public abstract boolean getIsSecure(); - - public abstract DHPublicKey getRemoteDHPublicKey(); - - public abstract KeyPair getLocalDHKeyPair() throws OtrException; - - public abstract BigInteger getS() throws OtrException; - - public abstract void handleReceivingMessage(AbstractMessage m) - throws OtrException; - - public abstract void startV2Auth() throws OtrException; - - public abstract void respondV2Auth() throws OtrException; - - public abstract PublicKey getRemoteLongTermPublicKey(); - - public abstract KeyPair getLocalLongTermKeyPair(); -} \ No newline at end of file diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/session/AuthContextImpl.java --- a/app/src/main/java/net/java/otr4j/session/AuthContextImpl.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,766 +0,0 @@ -/* - * 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.util.Arrays; -import java.util.Random; -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.DHCommitMessage; -import net.java.otr4j.io.messages.DHKeyMessage; -import net.java.otr4j.io.messages.AbstractEncodedMessage; -import net.java.otr4j.io.messages.AbstractMessage; -import net.java.otr4j.io.messages.SignatureM; -import net.java.otr4j.io.messages.SignatureX; -import net.java.otr4j.io.messages.QueryMessage; -import net.java.otr4j.io.messages.RevealSignatureMessage; -import net.java.otr4j.io.messages.SignatureMessage; - -/** - * - * @author George Politis - */ -class AuthContextImpl implements AuthContext { - - public AuthContextImpl(Session session) { - this.setSession(session); - this.reset(); - } - - private Session session; - - private int authenticationState; - 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 int getProtocolVersion() { - return this.protocolVersion; - } - - private void setProtocolVersion(int protoVersion) { - this.protocolVersion = protoVersion; - } - - private static Logger logger = Logger.getLogger(AuthContextImpl.class - .getName()); - - class MessageFactory { - - private QueryMessage getQueryMessage() { - Vector versions = new Vector(); - 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 (r == null) { - logger.finest("Picking random key r."); - r = new byte[OtrCryptoEngine.AES_KEY_BYTE_LENGTH]; - new Random().nextBytes(r); - } - return r; - } - - private 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; - } - - 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.getAccountID() - + " received a signature message from " + sessionID.getUserID() - + " 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)) { - 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.getAccountID() - + " received a reveal signature message from " - + sessionID.getUserID() + " 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)) { - 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.getAccountID() - + " received a D-H key message from " + sessionID.getUserID() - + " 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.getAccountID() - + " received a D-H commit message from " - + sessionID.getUserID() + " 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; - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/session/Session.java --- a/app/src/main/java/net/java/otr4j/session/Session.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -package net.java.otr4j.session; - -import java.security.KeyPair; -import java.security.PublicKey; -import java.util.List; - -import net.java.otr4j.OtrEngineListener; -import net.java.otr4j.OtrException; -import net.java.otr4j.OtrPolicy; -import net.java.otr4j.io.messages.AbstractMessage; -import net.java.otr4j.session.SessionImpl.TLV; - -public interface Session { - - public abstract SessionStatus getSessionStatus(); - - public abstract SessionID getSessionID(); - - public abstract void injectMessage(AbstractMessage m) throws OtrException; - - public abstract KeyPair getLocalKeyPair(); - - public abstract OtrPolicy getSessionPolicy(); - - public abstract String transformReceiving(String content) - throws OtrException; - - public abstract String transformSending(String content, List tlvs) - throws OtrException; - - public abstract void startSession() throws OtrException; - - public abstract void endSession() throws OtrException; - - public abstract void refreshSession() throws OtrException; - - public abstract PublicKey getRemotePublicKey(); - - public abstract void addOtrEngineListener(OtrEngineListener l); - - public abstract void removeOtrEngineListener(OtrEngineListener l); -} \ No newline at end of file diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/session/SessionID.java --- a/app/src/main/java/net/java/otr4j/session/SessionID.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.session; - -/** - * - * @author George Politis - * - */ -public final class SessionID { - - public SessionID(String accountID, String userID, String protocolName) { - this.setAccountID(accountID); - this.setUserID(userID); - this.setProtocolName(protocolName); - } - - private String accountID; - private String userID; - private String protocolName; - public static final SessionID Empty = new SessionID(null, null, null); - - public void setAccountID(String accountID) { - this.accountID = accountID; - } - - public String getAccountID() { - return accountID; - } - - private void setUserID(String userID) { - this.userID = userID; - } - - public String getUserID() { - return userID; - } - - private void setProtocolName(String protocolName) { - this.protocolName = protocolName; - } - - public String getProtocolName() { - return protocolName; - } - - public String toString() { - return this.getAccountID() + "_" + this.getProtocolName() + "_" - + this.getUserID(); - } - - public boolean equals(Object obj) { - if (obj == this) - return true; - if (obj == null || obj.getClass() != this.getClass()) - return false; - - SessionID sessionID = (SessionID) obj; - - return this.toString().equals(sessionID.toString()); - } - - public int hashCode() { - return this.toString().hashCode(); - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/session/SessionImpl.java --- a/app/src/main/java/net/java/otr4j/session/SessionImpl.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,792 +0,0 @@ -/* - * 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.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.security.KeyPair; -import java.security.PublicKey; -import java.util.Arrays; -import java.util.List; -import java.util.Vector; -import java.util.logging.Logger; -import javax.crypto.interfaces.DHPublicKey; - -import net.java.otr4j.OtrEngineHost; -import net.java.otr4j.OtrEngineListener; -import net.java.otr4j.OtrException; -import net.java.otr4j.OtrPolicy; -import net.java.otr4j.crypto.OtrCryptoEngine; -import net.java.otr4j.crypto.OtrCryptoEngineImpl; -import net.java.otr4j.io.OtrInputStream; -import net.java.otr4j.io.OtrOutputStream; -import net.java.otr4j.io.SerializationConstants; -import net.java.otr4j.io.SerializationUtils; -import net.java.otr4j.io.messages.DataMessage; -import net.java.otr4j.io.messages.AbstractEncodedMessage; -import net.java.otr4j.io.messages.ErrorMessage; -import net.java.otr4j.io.messages.AbstractMessage; -import net.java.otr4j.io.messages.MysteriousT; -import net.java.otr4j.io.messages.PlainTextMessage; -import net.java.otr4j.io.messages.QueryMessage; - -/** - * - * @author George Politis - */ -public class SessionImpl implements Session { - - class TLV { - public TLV(int type, byte[] value) { - this.setType(type); - this.setValue(value); - } - - public void setType(int type) { - this.type = type; - } - - public int getType() { - return type; - } - - public void setValue(byte[] value) { - this.value = value; - } - - public byte[] getValue() { - return value; - } - - private int type; - private byte[] value; - } - - private SessionID sessionID; - private OtrEngineHost host; - private SessionStatus sessionStatus; - private AuthContext authContext; - private SessionKeys[][] sessionKeys; - private Vector oldMacKeys; - private static Logger logger = Logger - .getLogger(SessionImpl.class.getName()); - - public SessionImpl(SessionID sessionID, OtrEngineHost listener) { - - this.setSessionID(sessionID); - this.setHost(listener); - - // client application calls OtrEngine.getSessionStatus() - // -> create new session if it does not exist, end up here - // -> setSessionStatus() fires statusChangedEvent - // -> client application calls OtrEngine.getSessionStatus() - this.sessionStatus = SessionStatus.PLAINTEXT; - } - - private SessionKeys getEncryptionSessionKeys() { - logger.finest("Getting encryption keys"); - return getSessionKeysByIndex(SessionKeys.Previous, SessionKeys.Current); - } - - private SessionKeys getMostRecentSessionKeys() { - logger.finest("Getting most recent keys."); - return getSessionKeysByIndex(SessionKeys.Current, SessionKeys.Current); - } - - private SessionKeys getSessionKeysByID(int localKeyID, int remoteKeyID) { - logger - .finest("Searching for session keys with (localKeyID, remoteKeyID) = (" - + localKeyID + "," + remoteKeyID + ")"); - - for (int i = 0; i < getSessionKeys().length; i++) { - for (int j = 0; j < getSessionKeys()[i].length; j++) { - SessionKeys current = getSessionKeysByIndex(i, j); - if (current.getLocalKeyID() == localKeyID - && current.getRemoteKeyID() == remoteKeyID) { - logger.finest("Matching keys found."); - return current; - } - } - } - - return null; - } - - private SessionKeys getSessionKeysByIndex(int localKeyIndex, - int remoteKeyIndex) { - if (getSessionKeys()[localKeyIndex][remoteKeyIndex] == null) - getSessionKeys()[localKeyIndex][remoteKeyIndex] = new SessionKeysImpl( - localKeyIndex, remoteKeyIndex); - - return getSessionKeys()[localKeyIndex][remoteKeyIndex]; - } - - private void rotateRemoteSessionKeys(DHPublicKey pubKey) - throws OtrException { - - logger.finest("Rotating remote keys."); - SessionKeys sess1 = getSessionKeysByIndex(SessionKeys.Current, - SessionKeys.Previous); - if (sess1.getIsUsedReceivingMACKey()) { - logger - .finest("Detected used Receiving MAC key. Adding to old MAC keys to reveal it."); - getOldMacKeys().add(sess1.getReceivingMACKey()); - } - - SessionKeys sess2 = getSessionKeysByIndex(SessionKeys.Previous, - SessionKeys.Previous); - if (sess2.getIsUsedReceivingMACKey()) { - logger - .finest("Detected used Receiving MAC key. Adding to old MAC keys to reveal it."); - getOldMacKeys().add(sess2.getReceivingMACKey()); - } - - SessionKeys sess3 = getSessionKeysByIndex(SessionKeys.Current, - SessionKeys.Current); - sess1 - .setRemoteDHPublicKey(sess3.getRemoteKey(), sess3 - .getRemoteKeyID()); - - SessionKeys sess4 = getSessionKeysByIndex(SessionKeys.Previous, - SessionKeys.Current); - sess2 - .setRemoteDHPublicKey(sess4.getRemoteKey(), sess4 - .getRemoteKeyID()); - - sess3.setRemoteDHPublicKey(pubKey, sess3.getRemoteKeyID() + 1); - sess4.setRemoteDHPublicKey(pubKey, sess4.getRemoteKeyID() + 1); - } - - private void rotateLocalSessionKeys() throws OtrException { - - logger.finest("Rotating local keys."); - SessionKeys sess1 = getSessionKeysByIndex(SessionKeys.Previous, - SessionKeys.Current); - if (sess1.getIsUsedReceivingMACKey()) { - logger - .finest("Detected used Receiving MAC key. Adding to old MAC keys to reveal it."); - getOldMacKeys().add(sess1.getReceivingMACKey()); - } - - SessionKeys sess2 = getSessionKeysByIndex(SessionKeys.Previous, - SessionKeys.Previous); - if (sess2.getIsUsedReceivingMACKey()) { - logger - .finest("Detected used Receiving MAC key. Adding to old MAC keys to reveal it."); - getOldMacKeys().add(sess2.getReceivingMACKey()); - } - - SessionKeys sess3 = getSessionKeysByIndex(SessionKeys.Current, - SessionKeys.Current); - sess1.setLocalPair(sess3.getLocalPair(), sess3.getLocalKeyID()); - SessionKeys sess4 = getSessionKeysByIndex(SessionKeys.Current, - SessionKeys.Previous); - sess2.setLocalPair(sess4.getLocalPair(), sess4.getLocalKeyID()); - - KeyPair newPair = new OtrCryptoEngineImpl().generateDHKeyPair(); - sess3.setLocalPair(newPair, sess3.getLocalKeyID() + 1); - sess4.setLocalPair(newPair, sess4.getLocalKeyID() + 1); - } - - private byte[] collectOldMacKeys() { - logger.finest("Collecting old MAC keys to be revealed."); - int len = 0; - for (int i = 0; i < getOldMacKeys().size(); i++) - len += getOldMacKeys().get(i).length; - - ByteBuffer buff = ByteBuffer.allocate(len); - for (int i = 0; i < getOldMacKeys().size(); i++) - buff.put(getOldMacKeys().get(i)); - - getOldMacKeys().clear(); - return buff.array(); - } - - private void setSessionStatus(SessionStatus sessionStatus) - throws OtrException { - - if (sessionStatus == this.sessionStatus) - return; - - switch (sessionStatus) { - case ENCRYPTED: - AuthContext auth = this.getAuthContext(); - logger.finest("Setting most recent session keys from auth."); - for (int i = 0; i < this.getSessionKeys()[0].length; i++) { - SessionKeys current = getSessionKeysByIndex(0, i); - current.setLocalPair(auth.getLocalDHKeyPair(), 1); - current.setRemoteDHPublicKey(auth.getRemoteDHPublicKey(), 1); - current.setS(auth.getS()); - } - - KeyPair nextDH = new OtrCryptoEngineImpl().generateDHKeyPair(); - for (int i = 0; i < this.getSessionKeys()[1].length; i++) { - SessionKeys current = getSessionKeysByIndex(1, i); - current.setRemoteDHPublicKey(auth.getRemoteDHPublicKey(), 1); - current.setLocalPair(nextDH, 2); - } - - this.setRemotePublicKey(auth.getRemoteLongTermPublicKey()); - - auth.reset(); - break; - } - - this.sessionStatus = sessionStatus; - - for (OtrEngineListener l : this.listeners) - l.sessionStatusChanged(getSessionID()); - } - - /* - * (non-Javadoc) - * - * @see net.java.otr4j.session.ISession#getSessionStatus() - */ - - public SessionStatus getSessionStatus() { - return sessionStatus; - } - - private void setSessionID(SessionID sessionID) { - this.sessionID = sessionID; - } - - /* - * (non-Javadoc) - * - * @see net.java.otr4j.session.ISession#getSessionID() - */ - public SessionID getSessionID() { - return sessionID; - } - - private void setHost(OtrEngineHost host) { - this.host = host; - } - - private OtrEngineHost getHost() { - return host; - } - - private SessionKeys[][] getSessionKeys() { - if (sessionKeys == null) - sessionKeys = new SessionKeys[2][2]; - return sessionKeys; - } - - private AuthContext getAuthContext() { - if (authContext == null) - authContext = new AuthContextImpl(this); - return authContext; - } - - private Vector getOldMacKeys() { - if (oldMacKeys == null) - oldMacKeys = new Vector(); - return oldMacKeys; - } - - /* - * (non-Javadoc) - * - * @see - * net.java.otr4j.session.ISession#handleReceivingMessage(java.lang.String) - */ - public String transformReceiving(String msgText) throws OtrException { - OtrPolicy policy = getSessionPolicy(); - if (!policy.getAllowV1() && !policy.getAllowV2()) { - logger - .finest("Policy does not allow neither V1 not V2, ignoring message."); - return msgText; - } - - AbstractMessage m; - try { - m = SerializationUtils.toMessage(msgText); - } catch (IOException e) { - throw new OtrException(e); - } - - if (m == null) - return msgText; // Propably null or empty. - - switch (m.messageType) { - case AbstractEncodedMessage.MESSAGE_DATA: - return handleDataMessage((DataMessage) m); - case AbstractMessage.MESSAGE_ERROR: - handleErrorMessage((ErrorMessage) m); - return null; - case AbstractMessage.MESSAGE_PLAINTEXT: - return handlePlainTextMessage((PlainTextMessage) m); - case AbstractMessage.MESSAGE_QUERY: - handleQueryMessage((QueryMessage) m); - return null; - case AbstractEncodedMessage.MESSAGE_DH_COMMIT: - case AbstractEncodedMessage.MESSAGE_DHKEY: - case AbstractEncodedMessage.MESSAGE_REVEALSIG: - case AbstractEncodedMessage.MESSAGE_SIGNATURE: - AuthContext auth = this.getAuthContext(); - auth.handleReceivingMessage(m); - - if (auth.getIsSecure()) { - this.setSessionStatus(SessionStatus.ENCRYPTED); - logger.finest("Gone Secure."); - } - return null; - default: - throw new UnsupportedOperationException( - "Received an uknown message type."); - } - } - - private void handleQueryMessage(QueryMessage queryMessage) - throws OtrException { - logger.finest(getSessionID().getAccountID() - + " received a query message from " - + getSessionID().getUserID() + " throught " - + getSessionID().getProtocolName() + "."); - - setSessionStatus(SessionStatus.PLAINTEXT); - - OtrPolicy policy = getSessionPolicy(); - if (queryMessage.versions.contains(2) && policy.getAllowV2()) { - logger.finest("Query message with V2 support found."); - getAuthContext().respondV2Auth(); - } else if (queryMessage.versions.contains(1) && policy.getAllowV1()) { - throw new UnsupportedOperationException(); - } - } - - private void handleErrorMessage(ErrorMessage errorMessage) - throws OtrException { - logger.finest(getSessionID().getAccountID() - + " received an error message from " - + getSessionID().getUserID() + " throught " - + getSessionID().getUserID() + "."); - - getHost().showError(this.getSessionID(), errorMessage.error); - - OtrPolicy policy = getSessionPolicy(); - if (policy.getErrorStartAKE()) { - logger.finest("Error message starts AKE."); - Vector versions = new Vector(); - if (policy.getAllowV1()) - versions.add(1); - - if (policy.getAllowV2()) - versions.add(2); - - logger.finest("Sending Query"); - injectMessage(new QueryMessage(versions)); - } - } - - private String handleDataMessage(DataMessage data) throws OtrException { - logger.finest(getSessionID().getAccountID() - + " received a data message from " + getSessionID().getUserID() - + "."); - - switch (this.getSessionStatus()) { - case ENCRYPTED: - logger - .finest("Message state is ENCRYPTED. Trying to decrypt message."); - - // Find matching session keys. - int senderKeyID = data.senderKeyID; - int receipientKeyID = data.recipientKeyID; - SessionKeys matchingKeys = this.getSessionKeysByID(receipientKeyID, - senderKeyID); - - if (matchingKeys == null) { - logger.finest("No matching keys found."); - return null; - } - - // Verify received MAC with a locally calculated MAC. - logger - .finest("Transforming T to byte[] to calculate it's HmacSHA1."); - - byte[] serializedT; - try { - serializedT = SerializationUtils.toByteArray(data.getT()); - } catch (IOException e) { - throw new OtrException(e); - } - - OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl(); - - byte[] computedMAC = otrCryptoEngine.sha1Hmac(serializedT, - matchingKeys.getReceivingMACKey(), - SerializationConstants.TYPE_LEN_MAC); - - if (!Arrays.equals(computedMAC, data.mac)) { - logger.finest("MAC verification failed, ignoring message"); - return null; - } - - logger.finest("Computed HmacSHA1 value matches sent one."); - - // Mark this MAC key as old to be revealed. - matchingKeys.setIsUsedReceivingMACKey(true); - - matchingKeys.setReceivingCtr(data.ctr); - - byte[] dmc = otrCryptoEngine.aesDecrypt(matchingKeys - .getReceivingAESKey(), matchingKeys.getReceivingCtr(), - data.encryptedMessage); - String decryptedMsgContent; - try { - // Expect bytes to be text encoded in UTF-8. - decryptedMsgContent = new String(dmc, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new OtrException(e); - } - - logger.finest("Decrypted message: \"" + decryptedMsgContent + "\""); - - // Rotate keys if necessary. - SessionKeys mostRecent = this.getMostRecentSessionKeys(); - if (mostRecent.getLocalKeyID() == receipientKeyID) - this.rotateLocalSessionKeys(); - - if (mostRecent.getRemoteKeyID() == senderKeyID) - this.rotateRemoteSessionKeys(data.nextDH); - - // Handle TLVs - List tlvs = null; - int tlvIndex = decryptedMsgContent.indexOf((char) 0x0); - if (tlvIndex > -1) { - decryptedMsgContent = decryptedMsgContent - .substring(0, tlvIndex); - tlvIndex++; - byte[] tlvsb = new byte[dmc.length - tlvIndex]; - System.arraycopy(dmc, tlvIndex, tlvsb, 0, tlvsb.length); - - tlvs = new Vector(); - ByteArrayInputStream tin = new ByteArrayInputStream(tlvsb); - while (tin.available() > 0) { - int type; - byte[] tdata; - OtrInputStream eois = new OtrInputStream(tin); - try { - type = eois.readShort(); - tdata = eois.readTlvData(); - eois.close(); - } catch (IOException e) { - throw new OtrException(e); - } - - tlvs.add(new TLV(type, tdata)); - } - } - if (tlvs != null && tlvs.size() > 0) { - for (TLV tlv : tlvs) { - switch (tlv.getType()) { - case 1: - this.setSessionStatus(SessionStatus.FINISHED); - return null; - default: - return decryptedMsgContent; - } - } - } - - return decryptedMsgContent; - - case FINISHED: - case PLAINTEXT: - getHost().showWarning(this.getSessionID(), - "Unreadable encrypted message was received."); - - injectMessage(new ErrorMessage(AbstractMessage.MESSAGE_ERROR, - "You sent me an unreadable encrypted message..")); - break; - } - - return null; - } - - public void injectMessage(AbstractMessage m) throws OtrException { - String msg; - try { - msg = SerializationUtils.toString(m); - } catch (IOException e) { - throw new OtrException(e); - } - getHost().injectMessage(getSessionID(), msg); - } - - private String handlePlainTextMessage(PlainTextMessage plainTextMessage) - throws OtrException { - logger.finest(getSessionID().getAccountID() - + " received a plaintext message from " - + getSessionID().getUserID() + " throught " - + getSessionID().getProtocolName() + "."); - - OtrPolicy policy = getSessionPolicy(); - List versions = plainTextMessage.versions; - if (versions == null || versions.size() < 1) { - logger - .finest("Received plaintext message without the whitespace tag."); - switch (this.getSessionStatus()) { - case ENCRYPTED: - case FINISHED: - // Display the message to the user, but warn him that the - // message was received unencrypted. - getHost().showWarning(this.getSessionID(), - "The message was received unencrypted."); - return plainTextMessage.cleanText; - case PLAINTEXT: - // Simply display the message to the user. If - // REQUIRE_ENCRYPTION - // is set, warn him that the message was received - // unencrypted. - if (policy.getRequireEncryption()) { - getHost().showWarning(this.getSessionID(), - "The message was received unencrypted."); - } - return plainTextMessage.cleanText; - } - } else { - logger - .finest("Received plaintext message with the whitespace tag."); - switch (this.getSessionStatus()) { - case ENCRYPTED: - case FINISHED: - // Remove the whitespace tag and display the message to the - // user, but warn him that the message was received - // unencrypted. - getHost().showWarning(this.getSessionID(), - "The message was received unencrypted."); - case PLAINTEXT: - // Remove the whitespace tag and display the message to the - // user. If REQUIRE_ENCRYPTION is set, warn him that the - // message - // was received unencrypted. - if (policy.getRequireEncryption()) - getHost().showWarning(this.getSessionID(), - "The message was received unencrypted."); - } - - if (policy.getWhitespaceStartAKE()) { - logger.finest("WHITESPACE_START_AKE is set"); - - if (plainTextMessage.versions.contains(2) - && policy.getAllowV2()) { - logger.finest("V2 tag found."); - getAuthContext().respondV2Auth(); - } else if (plainTextMessage.versions.contains(1) - && policy.getAllowV1()) { - throw new UnsupportedOperationException(); - } - } - } - - return plainTextMessage.cleanText; - } - - // Retransmit last sent message. Spec document does not mention where or - // when that should happen, must check libotr code. - private String lastSentMessage; - - public String transformSending(String msgText, List tlvs) - throws OtrException { - - switch (this.getSessionStatus()) { - case PLAINTEXT: - if (getSessionPolicy().getRequireEncryption()) { - this.lastSentMessage = msgText; - this.startSession(); - } else - // TODO this does not precisly behave according to - // specification. - return msgText; - case ENCRYPTED: - this.lastSentMessage = msgText; - logger.finest(getSessionID().getAccountID() - + " sends an encrypted message to " - + getSessionID().getUserID() + " throught " - + getSessionID().getProtocolName() + "."); - - // Get encryption keys. - SessionKeys encryptionKeys = this.getEncryptionSessionKeys(); - int senderKeyID = encryptionKeys.getLocalKeyID(); - int receipientKeyID = encryptionKeys.getRemoteKeyID(); - - // Increment CTR. - encryptionKeys.incrementSendingCtr(); - byte[] ctr = encryptionKeys.getSendingCtr(); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - if (msgText != null && msgText.length() > 0) - try { - out.write(msgText.getBytes("UTF8")); - } catch (IOException e) { - throw new OtrException(e); - } - - // Append tlvs - if (tlvs != null && tlvs.size() > 0) { - out.write((byte) 0x00); - - OtrOutputStream eoos = new OtrOutputStream(out); - for (TLV tlv : tlvs) { - try { - eoos.writeShort(tlv.type); - eoos.writeTlvData(tlv.value); - } catch (IOException e) { - throw new OtrException(e); - } - } - } - - OtrCryptoEngine otrCryptoEngine = new OtrCryptoEngineImpl(); - - byte[] data = out.toByteArray(); - // Encrypt message. - logger - .finest("Encrypting message with keyids (localKeyID, remoteKeyID) = (" - + senderKeyID + ", " + receipientKeyID + ")"); - byte[] encryptedMsg = otrCryptoEngine.aesEncrypt(encryptionKeys - .getSendingAESKey(), ctr, data); - - // Get most recent keys to get the next D-H public key. - SessionKeys mostRecentKeys = this.getMostRecentSessionKeys(); - DHPublicKey nextDH = (DHPublicKey) mostRecentKeys.getLocalPair() - .getPublic(); - - // Calculate T. - MysteriousT t = new MysteriousT(2, 0, senderKeyID, receipientKeyID, - nextDH, ctr, encryptedMsg); - - // Calculate T hash. - byte[] sendingMACKey = encryptionKeys.getSendingMACKey(); - - logger - .finest("Transforming T to byte[] to calculate it's HmacSHA1."); - byte[] serializedT; - try { - serializedT = SerializationUtils.toByteArray(t); - } catch (IOException e) { - throw new OtrException(e); - } - - byte[] mac = otrCryptoEngine.sha1Hmac(serializedT, sendingMACKey, - SerializationConstants.TYPE_LEN_MAC); - - // Get old MAC keys to be revealed. - byte[] oldKeys = this.collectOldMacKeys(); - DataMessage m = new DataMessage(t, mac, oldKeys); - - try { - return SerializationUtils.toString(m); - } catch (IOException e) { - throw new OtrException(e); - } - case FINISHED: - this.lastSentMessage = msgText; - getHost() - .showError( - sessionID, - "Your message to " - + sessionID.getUserID() - + " was not sent. Either end your private conversation, or restart it."); - return null; - default: - logger.finest("Uknown message state, not processing."); - return msgText; - } - } - - /* - * (non-Javadoc) - * - * @see net.java.otr4j.session.ISession#startSession() - */ - public void startSession() throws OtrException { - if (this.getSessionStatus() == SessionStatus.ENCRYPTED) - return; - - if (!getSessionPolicy().getAllowV2()) - throw new UnsupportedOperationException(); - - this.getAuthContext().startV2Auth(); - } - - /* - * (non-Javadoc) - * - * @see net.java.otr4j.session.ISession#endSession() - */ - public void endSession() throws OtrException { - SessionStatus status = this.getSessionStatus(); - switch (status) { - case ENCRYPTED: - Vector tlvs = new Vector(); - tlvs.add(new TLV(1, null)); - - String msg = this.transformSending(null, tlvs); - getHost().injectMessage(getSessionID(), msg); - this.setSessionStatus(SessionStatus.PLAINTEXT); - break; - case FINISHED: - this.setSessionStatus(SessionStatus.PLAINTEXT); - break; - case PLAINTEXT: - return; - } - - } - - /* - * (non-Javadoc) - * - * @see net.java.otr4j.session.ISession#refreshSession() - */ - public void refreshSession() throws OtrException { - this.endSession(); - this.startSession(); - } - - private PublicKey remotePublicKey; - - private void setRemotePublicKey(PublicKey pubKey) { - this.remotePublicKey = pubKey; - } - - public PublicKey getRemotePublicKey() { - return remotePublicKey; - } - - private List listeners = new Vector(); - - public void addOtrEngineListener(OtrEngineListener l) { - synchronized (listeners) { - if (!listeners.contains(l)) - listeners.add(l); - } - } - - public void removeOtrEngineListener(OtrEngineListener l) { - synchronized (listeners) { - listeners.remove(l); - } - } - - public OtrPolicy getSessionPolicy() { - return getHost().getSessionPolicy(getSessionID()); - } - - public KeyPair getLocalKeyPair() { - return getHost().getKeyPair(this.getSessionID()); - } -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/session/SessionKeys.java --- a/app/src/main/java/net/java/otr4j/session/SessionKeys.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -package net.java.otr4j.session; - -import java.math.BigInteger; -import java.security.KeyPair; - -import javax.crypto.interfaces.DHPublicKey; - -import net.java.otr4j.OtrException; - -interface SessionKeys { - - public static final int Previous = 0; - public static final int Current = 1; - public static final byte HIGH_SEND_BYTE = (byte) 0x01; - public static final byte HIGH_RECEIVE_BYTE = (byte) 0x02; - public static final byte LOW_SEND_BYTE = (byte) 0x02; - public static final byte LOW_RECEIVE_BYTE = (byte) 0x01; - - public abstract void setLocalPair(KeyPair keyPair, int localPairKeyID); - - public abstract void setRemoteDHPublicKey(DHPublicKey pubKey, - int remoteKeyID); - - public abstract void incrementSendingCtr(); - - public abstract byte[] getSendingCtr(); - - public abstract byte[] getReceivingCtr(); - - public abstract void setReceivingCtr(byte[] ctr); - - public abstract byte[] getSendingAESKey() throws OtrException; - - public abstract byte[] getReceivingAESKey() throws OtrException; - - public abstract byte[] getSendingMACKey() throws OtrException; - - public abstract byte[] getReceivingMACKey() throws OtrException; - - public abstract void setS(BigInteger s); - - public abstract void setIsUsedReceivingMACKey(Boolean isUsedReceivingMACKey); - - public abstract Boolean getIsUsedReceivingMACKey(); - - public abstract int getLocalKeyID(); - - public abstract int getRemoteKeyID(); - - public abstract DHPublicKey getRemoteKey(); - - public abstract KeyPair getLocalPair(); - -} \ No newline at end of file diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/session/SessionKeysImpl.java --- a/app/src/main/java/net/java/otr4j/session/SessionKeysImpl.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * 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; -} diff -r 6ca974ea549b -r 9b965359eaea app/src/main/java/net/java/otr4j/session/SessionStatus.java --- a/app/src/main/java/net/java/otr4j/session/SessionStatus.java Sun Mar 15 18:57:24 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -/* - * otr4j, the open source java otr library. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package net.java.otr4j.session; - -/** - * - * @author George Politis - */ -public enum SessionStatus { - PLAINTEXT, - ENCRYPTED, - FINISHED -}