From 88bc48e9b121685f11e3a36b13a7ce0d79b0044d Mon Sep 17 00:00:00 2001 From: Marin Date: Mon, 21 Oct 2013 15:24:19 +0300 Subject: [PATCH] Added support for SMP for the OTR plugin. --- lib/installer-exclude/otr4j.jar | Bin 74060 -> 86024 bytes resources/languages/resources.properties | 35 +- .../plugin/otr/CustomTextArea.java | 26 + .../otr/FingerprintAuthenticationPanel.java | 257 +++++++ .../otr/OtrBuddyAuthenticationDialog.java | 283 +++----- .../communicator/plugin/otr/ScOtrEngine.java | 32 + .../plugin/otr/ScOtrEngineImpl.java | 654 +++++++++++++++++- .../plugin/otr/ScOtrKeyManager.java | 2 + .../plugin/otr/ScOtrKeyManagerImpl.java | 20 + .../SecretQuestionAuthenticationPanel.java | 117 ++++ .../otr/SharedSecretAuthenticationPanel.java | 89 +++ .../communicator/plugin/otr/otr.manifest.mf | 2 + 12 files changed, 1311 insertions(+), 206 deletions(-) create mode 100644 src/net/java/sip/communicator/plugin/otr/CustomTextArea.java create mode 100644 src/net/java/sip/communicator/plugin/otr/FingerprintAuthenticationPanel.java create mode 100644 src/net/java/sip/communicator/plugin/otr/SecretQuestionAuthenticationPanel.java create mode 100644 src/net/java/sip/communicator/plugin/otr/SharedSecretAuthenticationPanel.java diff --git a/lib/installer-exclude/otr4j.jar b/lib/installer-exclude/otr4j.jar index 415a1dc450efd350e4baa2c9144b7738266e82bf..561ac47e21bd74553fc012ffd1f16f72625599cd 100644 GIT binary patch delta 59014 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 z%0D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 oesUbGsk%!|}jAeIQ`N&Mdh915+so;{X5v diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index 4db6e0ecf..740b879b4 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -1519,13 +1519,30 @@ plugin.otr.menu.CB_RESET=Reset plugin.otr.menu.OTR_TOOLTIP=Encrypt chats with OTR plugin.otr.authbuddydialog.HELP_URI=https://jitsi.org/GSOC2009/OTR plugin.otr.authbuddydialog.AUTHENTICATION_INFO=Authenticating a buddy helps \ -ensure that the person you are talking to is who he or she claims to be. \ -To verify the fingerprint, contact your buddy via some other authenticated \ +ensure that the person you are talking to is who he or she claims to be. +plugin.otr.authbuddydialog.AUTHENTICATION_METHOD=How would you like to authenticate? +plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_QUESTION=Question authentication +plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_SECRET=Shared secret authentication +plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_FINGERPRINT=Fingerprint authentication +plugin.otr.authbuddydialog.AUTHENTICATION_FINGERPRINT=To verify the fingerprint, contact your buddy via some other authenticated \ channel, such as the telephone or GPG-signed email. Each of you should tell \ your fingerprint to the other. If everything matches up, you should indicate \ in the following dialog that you *have* verified the fingerprint. plugin.otr.authbuddydialog.LOCAL_FINGERPRINT=Fingerprint for you, {0}: {1} plugin.otr.authbuddydialog.REMOTE_FINGERPRINT=Purported fingerprint for {0}: {1} +plugin.otr.authbuddydialog.AUTH_BY_QUESTION_INFO_INIT=To authenticate using a question, you should pick a question whose answer \ +is only known to you and your buddy. Your buddy will be asked this question and if the answers don't match then you may be talking \ +to an impostor. +plugin.otr.authbuddydialog.AUTH_BY_SECRET_INFO_INIT=To authenticate using a shared secret, you should pick a secret that is only known \ +to you and your buddy. Your buddy will then be asked to pick the secret too and if they don't match then you may be talking \ +to an impostor. +plugin.otr.authbuddydialog.AUTH_BY_SECRET_INFO_RESPOND=Your buddy is trying to determine if he or she is really talking to you and not an impostor. \ +Your buddy has asked you a question. If you want to authenticate, please enter the answer below. +plugin.otr.authbuddydialog.SHARED_SECRET=Enter your shared secret: +plugin.otr.authbuddydialog.QUESTION_RESPOND=Your buddy is asking you: +plugin.otr.authbuddydialog.QUESTION_INIT=Enter your question here: +plugin.otr.authbuddydialog.ANSWER=Enter your answer here (Case sensitive): +plugin.otr.authbuddydialog.AUTHENTICATION_FROM=Authentication from {0}. plugin.otr.authbuddydialog.CANCEL=Cancel plugin.otr.authbuddydialog.HELP=Help plugin.otr.authbuddydialog.TITLE=Authenticate Buddy @@ -1534,6 +1551,9 @@ plugin.otr.authbuddydialog.I_HAVE=I have plugin.otr.authbuddydialog.I_HAVE_NOT=I have not plugin.otr.authbuddydialog.VERIFY_ACTION=verified that this is in fact the correct fingerprint for {0}. plugin.otr.authbuddydialog.FINGERPRINT_CHECK=Please enter the fingerprint you recieved from {0}. +plugin.otr.smpprogressdialog.TITLE=Authentication Progress +plugin.otr.smpprogressdialog.AUTHENTICATION_SUCCESS=Authentication successful! +plugin.otr.smpprogressdialog.AUTHENTICATION_FAIL=Authentication failed! plugin.otr.configform.MY_PRIVATE_KEYS=My Private Keys plugin.otr.configform.KNOWN_FINGERPRINTS=Known Fingerprints plugin.otr.configform.CB_AUTO=Automatically initiate private messaging @@ -1556,6 +1576,17 @@ plugin.otr.activator.sessionfinished={0} has ended his/her private conversation plugin.otr.activator.sessionlost=Private conversation with {0} lost. plugin.otr.activator.historyon={0} is recording this conversation on your device. You can turn off chat history here. plugin.otr.activator.historyoff={0} is NOT recording this conversation. You can activate chat history here. +plugin.otr.activator.sessionfinishederror=Your message was not sent. Please end your private conversation with {0}. +plugin.otr.activator.smpaborted={0} has aborted the authentication process. +plugin.otr.activator.smperror=An error occurred in the authentication process. +plugin.otr.activator.unencryptedmsgreceived=The message was received unencrypted. +plugin.otr.activator.unreadablemsgreceived={0} sent you an unreadable encrypted message. +plugin.otr.activator.requireencryption=Your message was not sent. Private messaging is required. +plugin.otr.activator.unreadablemsgreply=You sent {0} an unreadable encrypted message. Please end your private conversation with {1} or refresh it. +plugin.otr.activator.fallbackmessage={0} is trying to initiate an encrypted \ +Off-The-Record conversation with you. However, your software does not support \ +Off-The-Record messaging. For more information see \ +http://en.wikipedia.org/wiki/Off-the-Record_Messaging # global proxy plugin plugin.globalproxy.GLOBAL_PROXY_CONFIG=Global Proxy diff --git a/src/net/java/sip/communicator/plugin/otr/CustomTextArea.java b/src/net/java/sip/communicator/plugin/otr/CustomTextArea.java new file mode 100644 index 000000000..00aa7d182 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/CustomTextArea.java @@ -0,0 +1,26 @@ +package net.java.sip.communicator.plugin.otr; + +import java.awt.*; + +import javax.swing.*; + +/** + * A special {@link JTextArea} for use in the OTR authentication panels. + * It is meant to be used for fingerprint representation and general + * information display. + * + * @author George Politis + */ + public class CustomTextArea + extends JTextArea + { + public CustomTextArea() + { + this.setBackground(new Color(0,0,0,0)); + this.setOpaque(false); + this.setColumns(20); + this.setEditable(false); + this.setLineWrap(true); + this.setWrapStyleWord(true); + } + } \ No newline at end of file diff --git a/src/net/java/sip/communicator/plugin/otr/FingerprintAuthenticationPanel.java b/src/net/java/sip/communicator/plugin/otr/FingerprintAuthenticationPanel.java new file mode 100644 index 000000000..70ef5d8f5 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/FingerprintAuthenticationPanel.java @@ -0,0 +1,257 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.otr; + +import java.awt.*; + +import javax.swing.*; +import javax.swing.event.*; + +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * @author George Politis + * @author Marin Dzhigarov + */ +@SuppressWarnings("serial") +public class FingerprintAuthenticationPanel + extends TransparentPanel + implements DocumentListener +{ + + /** + * The Contact that we are authenticating. + */ + private final Contact contact; + + private SIPCommTextField txtRemoteFingerprintComparison; + + /** + * Our fingerprint. + */ + private JTextArea txtLocalFingerprint; + + /** + * The purported fingerprint of the remote party. + */ + private JTextArea txtRemoteFingerprint; + + /** + * The "I have" / "I have not" combo box. + */ + private JComboBox cbAction; + + private ActionComboBoxItem actionIHave = + new ActionComboBoxItem(ActionComboBoxItemIndex.I_HAVE); + + private ActionComboBoxItem actionIHaveNot = + new ActionComboBoxItem(ActionComboBoxItemIndex.I_HAVE_NOT); + + private JTextArea txtAction; + + /** + * Creates an instance FingerprintAuthenticationPanel + * + * @param contact The contact that this panel refers to. + */ + FingerprintAuthenticationPanel(Contact contact) + { + this.contact = contact; + initComponents(); + loadContact(); + + } + + /** + * Initializes the {@link FingerprintAuthenticationPanel} components. + */ + private void initComponents() + { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setPreferredSize(new Dimension(350, 300)); + + JTextArea generalInformation = new CustomTextArea(); + generalInformation.setText(OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_FINGERPRINT")); + this.add(generalInformation); + + add(Box.createVerticalStrut(10)); + + txtLocalFingerprint = new CustomTextArea(); + this.add(txtLocalFingerprint); + + add(Box.createVerticalStrut(10)); + + txtRemoteFingerprint = new CustomTextArea(); + this.add(txtRemoteFingerprint); + + add(Box.createVerticalStrut(10)); + + // Action Panel (the panel that holds the I have/I have not dropdown) + JPanel pnlAction = new JPanel(new GridBagLayout()); + pnlAction.setBorder(BorderFactory.createEtchedBorder()); + this.add(pnlAction); + + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 5, 5); + c.weightx = 0.0; + + setCbAction(new JComboBox()); + getCbAction().addItem(actionIHave); + getCbAction().addItem(actionIHaveNot); + getCbAction().setSelectedItem(OtrActivator.scOtrKeyManager + .isVerified(contact) ? actionIHave : actionIHaveNot); + + pnlAction.add(getCbAction(), c); + + txtAction = new CustomTextArea(); + c.weightx = 1.0; + pnlAction.add(txtAction, c); + + txtRemoteFingerprintComparison = new SIPCommTextField( + OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.FINGERPRINT_CHECK", + new String[]{contact.getDisplayName()})); + txtRemoteFingerprintComparison.getDocument().addDocumentListener(this); + + c.gridwidth = 2; + c.gridy = 1; + pnlAction.add(txtRemoteFingerprintComparison, c); + c.gridwidth = 1; + c.gridy = 0; + } + + /** + * Sets up the {@link OtrBuddyAuthenticationDialog} components so that they + * reflect the {@link OtrBuddyAuthenticationDialog#contact} + */ + private void loadContact() + { + // Local fingerprint. + String account = + contact.getProtocolProvider().getAccountID().getDisplayName(); + String localFingerprint = + OtrActivator.scOtrKeyManager.getLocalFingerprint(contact + .getProtocolProvider().getAccountID()); + txtLocalFingerprint.setText(OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.LOCAL_FINGERPRINT", new String[] + { account, localFingerprint })); + + // Remote fingerprint. + String user = contact.getDisplayName(); + String remoteFingerprint = + OtrActivator.scOtrKeyManager.getRemoteFingerprint(contact); + txtRemoteFingerprint.setText(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.REMOTE_FINGERPRINT", + new String[] + { user, remoteFingerprint })); + + // Action + txtAction.setText(OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.VERIFY_ACTION", new String[] + { user })); + } + + public void removeUpdate(DocumentEvent e) + { + compareFingerprints(); + } + + public void insertUpdate(DocumentEvent e) + { + compareFingerprints(); + } + + public void changedUpdate(DocumentEvent e) + { + compareFingerprints(); + } + + public void compareFingerprints() + { + if(txtRemoteFingerprintComparison.getText() == null + || txtRemoteFingerprintComparison.getText().length() == 0) + { + txtRemoteFingerprintComparison.setBackground(Color.white); + return; + } + if(txtRemoteFingerprintComparison.getText().toLowerCase().contains( + OtrActivator.scOtrKeyManager + .getRemoteFingerprint(contact).toLowerCase())) + { + txtRemoteFingerprintComparison.setBackground(Color.green); + getCbAction().setSelectedItem(actionIHave); + } + else + { + txtRemoteFingerprintComparison.setBackground( + new Color(243, 72, 48)); + getCbAction().setSelectedItem(actionIHaveNot); + } + } + + public JComboBox getCbAction() + { + return cbAction; + } + + public void setCbAction(JComboBox cbAction) + { + this.cbAction = cbAction; + } + + /** + * A simple enumeration that is meant to be used with + * {@link ActionComboBoxItem} to distinguish them (like an ID). + * + * @author George Politis + */ + enum ActionComboBoxItemIndex + { + I_HAVE, I_HAVE_NOT + } + + /** + * A special {@link JComboBox} that is hosted in + * {@link OtrBuddyAuthenticationDialog#cbAction}. + * + * @author George Politis + */ + class ActionComboBoxItem + { + public ActionComboBoxItemIndex action; + + private String text; + + public ActionComboBoxItem(ActionComboBoxItemIndex actionIndex) + { + this.action = actionIndex; + switch (action) + { + case I_HAVE: + text = + OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.I_HAVE"); + break; + case I_HAVE_NOT: + text = + OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.I_HAVE_NOT"); + break; + } + } + + @Override + public String toString() + { + return text; + } + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java b/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java index 5d5e06c87..a78fb7a35 100644 --- a/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java +++ b/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java @@ -10,18 +10,18 @@ import java.awt.event.*; import javax.swing.*; -import javax.swing.event.*; -import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.plugin.otr.FingerprintAuthenticationPanel.ActionComboBoxItem; +import net.java.sip.communicator.service.protocol.*; /** * @author George Politis + * @author Marin Dzhigarov */ @SuppressWarnings("serial") public class OtrBuddyAuthenticationDialog extends SIPCommDialog - implements DocumentListener { private final Contact contact; @@ -37,121 +37,6 @@ public OtrBuddyAuthenticationDialog(Contact contact) this.contact = contact; initComponents(); - loadContact(); - } - - private SIPCommTextField txtRemoteFingerprintComparison; - - private JTextArea txtLocalFingerprint; - - private JTextArea txtRemoteFingerprint; - - private JComboBox cbAction; - ActionComboBoxItem actionIHave = - new ActionComboBoxItem(ActionComboBoxItemIndex.I_HAVE); - ActionComboBoxItem actionIHaveNot = - new ActionComboBoxItem(ActionComboBoxItemIndex.I_HAVE_NOT); - - private JTextArea txtAction; - - /** - * Sets up the {@link OtrBuddyAuthenticationDialog} components so that they - * reflect the {@link OtrBuddyAuthenticationDialog#contact} - */ - private void loadContact() - { - // Local fingerprint. - String account = - contact.getProtocolProvider().getAccountID().getDisplayName(); - String localFingerprint = - OtrActivator.scOtrKeyManager.getLocalFingerprint(contact - .getProtocolProvider().getAccountID()); - txtLocalFingerprint.setText(OtrActivator.resourceService.getI18NString( - "plugin.otr.authbuddydialog.LOCAL_FINGERPRINT", new String[] - { account, localFingerprint })); - - // Remote fingerprint. - String user = contact.getDisplayName(); - String remoteFingerprint = - OtrActivator.scOtrKeyManager.getRemoteFingerprint(contact); - txtRemoteFingerprint.setText(OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.REMOTE_FINGERPRINT", - new String[] - { user, remoteFingerprint })); - - // Action - txtAction.setText(OtrActivator.resourceService.getI18NString( - "plugin.otr.authbuddydialog.VERIFY_ACTION", new String[] - { user })); - } - - /** - * A special {@link JTextArea} for use in the - * {@link OtrBuddyAuthenticationDialog}. It is meant to be used for - * fingerprint representation and general information display. - * - * @author George Politis - */ - class CustomTextArea - extends JTextArea - { - public CustomTextArea() - { - this.setBackground(new Color(0,0,0,0)); - this.setOpaque(false); - this.setColumns(20); - this.setEditable(false); - this.setLineWrap(true); - this.setWrapStyleWord(true); - } - } - - /** - * A simple enumeration that is meant to be used with - * {@link ActionComboBoxItem} to distinguish them (like an ID). - * - * @author George Politis - */ - enum ActionComboBoxItemIndex - { - I_HAVE, I_HAVE_NOT - } - - /** - * A special {@link JComboBox} that is hosted in - * {@link OtrBuddyAuthenticationDialog#cbAction}. - * - * @author George Politis - */ - class ActionComboBoxItem - { - public ActionComboBoxItemIndex action; - - private String text; - - public ActionComboBoxItem(ActionComboBoxItemIndex actionIndex) - { - this.action = actionIndex; - switch (action) - { - case I_HAVE: - text = - OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.I_HAVE"); - break; - case I_HAVE_NOT: - text = - OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.I_HAVE_NOT"); - break; - } - } - - @Override - public String toString() - { - return text; - } } /** @@ -172,45 +57,60 @@ private void initComponents() .getI18NString("plugin.otr.authbuddydialog.AUTHENTICATION_INFO")); mainPanel.add(generalInformation); - txtLocalFingerprint = new CustomTextArea(); - mainPanel.add(txtLocalFingerprint); - - txtRemoteFingerprint = new CustomTextArea(); - mainPanel.add(txtRemoteFingerprint); - - // Action Panel (the panel that holds the I have/I have not dropdown) - JPanel pnlAction = new JPanel(new GridBagLayout()); - pnlAction.setBorder(BorderFactory.createEtchedBorder()); - mainPanel.add(pnlAction); + mainPanel.add(Box.createVerticalStrut(10)); + + // Add authentication method label and combo box. + final String am[] = new String[]{ + OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_QUESTION"), + OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_SECRET"), + OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_FINGERPRINT")}; + final JComboBox authenticationMethodComboBox = + new JComboBox(am); + JTextArea authMethodLabel = new CustomTextArea(); + authMethodLabel.setText( + OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_METHOD")); + mainPanel.add(authMethodLabel); + mainPanel.add(authenticationMethodComboBox); + mainPanel.add(Box.createVerticalStrut(10)); + + // Add authentication panels in a card layout so that the user can + // use the combo box to switch between authentication methods. + final JPanel authenticationPanel = + new TransparentPanel(new CardLayout()); + final FingerprintAuthenticationPanel fingerprintPanel = + new FingerprintAuthenticationPanel(contact); + final SecretQuestionAuthenticationPanel secretQuestionPanel = + new SecretQuestionAuthenticationPanel(); + final SharedSecretAuthenticationPanel sharedSecretPanel = + new SharedSecretAuthenticationPanel(); + authenticationPanel.add(secretQuestionPanel, am[0]); + authenticationPanel.add(sharedSecretPanel, am[1]); + authenticationPanel.add(fingerprintPanel, am[2]); + + authenticationMethodComboBox.addItemListener(new ItemListener() + { + @Override + public void itemStateChanged(ItemEvent e) + { + if (e.getStateChange() == ItemEvent.SELECTED) + { + CardLayout cl = + (CardLayout) (authenticationPanel.getLayout()); + cl.show(authenticationPanel, (String)e.getItem()); + } + } + }); + authenticationMethodComboBox.setSelectedIndex(0); + mainPanel.add(authenticationPanel); GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.HORIZONTAL; c.insets = new Insets(5, 5, 5, 5); - c.weightx = 0.0; - - cbAction = new JComboBox(); - cbAction.addItem(actionIHave); - cbAction.addItem(actionIHaveNot); - cbAction.setSelectedItem(OtrActivator.scOtrKeyManager - .isVerified(contact) ? actionIHave : actionIHaveNot); - - pnlAction.add(cbAction, c); - - txtAction = new CustomTextArea(); c.weightx = 1.0; - pnlAction.add(txtAction, c); - - txtRemoteFingerprintComparison = new SIPCommTextField( - OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.FINGERPRINT_CHECK", - new String[]{contact.getDisplayName()})); - txtRemoteFingerprintComparison.getDocument().addDocumentListener(this); - - c.gridwidth = 2; - c.gridy = 1; - pnlAction.add(txtRemoteFingerprintComparison, c); c.gridwidth = 1; - c.gridy = 0; // Buttons panel. JPanel buttonPanel = new TransparentPanel(new GridBagLayout()); @@ -254,19 +154,40 @@ public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) { - ActionComboBoxItem actionItem = - (ActionComboBoxItem) cbAction.getSelectedItem(); - switch (actionItem.action) + String authenticationMethod = + (String)authenticationMethodComboBox.getSelectedItem(); + if (authenticationMethod.equals(am[0])) { - case I_HAVE: - OtrActivator.scOtrKeyManager.verify(contact); - break; - case I_HAVE_NOT: - OtrActivator.scOtrKeyManager.unverify(contact); - break; + String secret = secretQuestionPanel.getSecret(); + String question = secretQuestionPanel.getQuestion(); + + OtrActivator.scOtrEngine.initSmp(contact, question, secret); + dispose(); } + else if (authenticationMethod.equals(am[1])) + { + String secret = secretQuestionPanel.getSecret(); + String question = null; - dispose(); + OtrActivator.scOtrEngine.initSmp(contact, question, secret); + dispose(); + } + else if (authenticationMethod.equals(am[2])) + { + ActionComboBoxItem actionItem = + (ActionComboBoxItem) fingerprintPanel. + getCbAction().getSelectedItem(); + switch (actionItem.action) + { + case I_HAVE: + OtrActivator.scOtrKeyManager.verify(contact); + break; + case I_HAVE_NOT: + OtrActivator.scOtrKeyManager.unverify(contact); + break; + } + dispose(); + } } }); buttonPanel.add(authenticateButton, c); @@ -275,42 +196,4 @@ public void actionPerformed(ActionEvent e) this.getContentPane().add(buttonPanel, BorderLayout.SOUTH); this.pack(); } - - public void removeUpdate(DocumentEvent e) - { - compareFingerprints(); - } - - public void insertUpdate(DocumentEvent e) - { - compareFingerprints(); - } - - public void changedUpdate(DocumentEvent e) - { - compareFingerprints(); - } - - public void compareFingerprints() - { - if(txtRemoteFingerprintComparison.getText() == null - || txtRemoteFingerprintComparison.getText().length() == 0) - { - txtRemoteFingerprintComparison.setBackground(Color.white); - return; - } - if(txtRemoteFingerprintComparison.getText().toLowerCase().contains( - OtrActivator.scOtrKeyManager - .getRemoteFingerprint(contact).toLowerCase())) - { - txtRemoteFingerprintComparison.setBackground(Color.green); - cbAction.setSelectedItem(actionIHave); - } - else - { - txtRemoteFingerprintComparison.setBackground( - new Color(243, 72, 48)); - cbAction.setSelectedItem(actionIHaveNot); - } - } } diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java b/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java index 1e7b5e8e8..3e8e6e520 100644 --- a/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java +++ b/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java @@ -20,6 +20,38 @@ public interface ScOtrEngine { // Proxy methods OtrEngine. + /** + * Initializes Smp negotiation. + * See {@link http://en.wikipedia.org/wiki/Socialist_Millionaire_Problem} + * + * @param contact The contact with whom we want to start the Smp negotiation + * @param question The question that is asked during the Smp negotiation + * @param secret The secret answer for the question. + */ + public abstract void initSmp( + Contact contact, String question, String secret); + + /** + * Responds to a question that is asked during the Smp negotiation process. + * See {@link http://en.wikipedia.org/wiki/Socialist_Millionaire_Problem} + * + * @param contact The contact for whom we want to respond to a question + * during the Smp negotiation process. + * @param question The question that is asked during the Smp negotiation. + * @param secret The secret answer for the question. + */ + public abstract void respondSmp( + Contact contact, String question, String secret); + + /** + * Aborts the Smp negotiation process. + * See {@link http://en.wikipedia.org/wiki/Socialist_Millionaire_Problem} + * + * @param contact The contact with whom we want to abort the + * Smp negotiation process. + */ + public abstract void abortSmp(Contact contact); + /** * Transforms an outgoing message. * diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java b/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java index f60ef331c..c465e94b4 100644 --- a/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java +++ b/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java @@ -6,13 +6,20 @@ */ package net.java.sip.communicator.plugin.otr; +import java.awt.*; +import java.awt.event.*; import java.net.*; import java.security.*; import java.util.*; +import java.util.List; +import java.util.concurrent.*; + +import javax.swing.*; +import javax.swing.plaf.basic.*; import net.java.otr4j.*; import net.java.otr4j.session.*; - +import net.java.sip.communicator.plugin.desktoputil.*; import net.java.sip.communicator.service.browserlauncher.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.gui.*; @@ -36,7 +43,7 @@ public class ScOtrEngineImpl class ScOtrEngineHost implements OtrEngineHost { - public KeyPair getKeyPair(SessionID sessionID) + public KeyPair getLocalKeyPair(SessionID sessionID) { AccountID accountID = OtrActivator.getAccountIDByUID(sessionID.getAccountID()); @@ -83,11 +90,242 @@ public void showWarning(SessionID sessionID, String warn) Chat.SYSTEM_MESSAGE, warn, OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); } + + @Override + public void unreadableMessageReceived(SessionID sessionID) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + String error = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.unreadablemsgreceived", + new String[] {contact.getDisplayName()}); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.ERROR_MESSAGE, error, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + } + + @Override + public void unencryptedMessageReceived(SessionID sessionID, String msg) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + String warn = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.unencryptedmsgreceived"); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.SYSTEM_MESSAGE, warn, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + } + + @Override + public void smpError(SessionID sessionID, int tlvType, boolean cheated) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + logger.debug("SMP error occurred" + + ". Contact: " + contact.getDisplayName() + + ". TLV type: " + tlvType + + ". Cheated: " + cheated); + + String error = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.smperror"); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.ERROR_MESSAGE, error, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.setProgressFail(); + progressDialog.setVisible(true); + } + + @Override + public void smpAborted(SessionID sessionID) throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + Session session = otrEngine.getSession(sessionID); + if (session.isSmpInProgress()) + { + String warn = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.smpaborted", + new String[] {contact.getDisplayName()}); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.SYSTEM_MESSAGE, warn, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.setProgressFail(); + progressDialog.setVisible(true); + } + } + + @Override + public void finishedSessionMessage(SessionID sessionID) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + String error = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.sessionfinishederror", + new String[] {contact.getDisplayName()}); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.ERROR_MESSAGE, error, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + } + + @Override + public void requireEncryptedMessage(SessionID sessionID, String msgText) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + String error = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.requireencryption", + new String[] {contact.getDisplayName()}); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.ERROR_MESSAGE, error, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + } + + @Override + public byte[] getLocalFingerprintRaw(SessionID sessionID) + { + AccountID accountID = + OtrActivator.getAccountIDByUID(sessionID.getAccountID()); + return + OtrActivator.scOtrKeyManager.getLocalFingerprintRaw(accountID); + } + + @Override + public void askForSecret(SessionID sessionID, String question) + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + SmpAuthenticateBuddyDialog dialog = + new SmpAuthenticateBuddyDialog(contact, question); + dialog.setVisible(true); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.init(); + progressDialog.setVisible(true); + } + + @Override + public void verify(SessionID sessionID, boolean approved) + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + OtrActivator.scOtrKeyManager.verify(contact); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.setProgressSuccess(); + progressDialog.setVisible(true); + } + + @Override + public void unverify(SessionID sessionID) + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + OtrActivator.scOtrKeyManager.unverify(contact); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.setProgressFail(); + progressDialog.setVisible(true); + } + + @Override + public String getReplyForUnreadableMessage(SessionID sessionID) + { + AccountID accountID = + OtrActivator.getAccountIDByUID(sessionID.getAccountID()); + + return OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.unreadablemsgreply", + new String[] {accountID.getDisplayName(), + accountID.getDisplayName()}); + } + + @Override + public String getFallbackMessage(SessionID sessionID) + { + AccountID accountID = + OtrActivator.getAccountIDByUID(sessionID.getAccountID()); + + return OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.fallbackmessage", + new String[] {accountID.getDisplayName()}); + } } private static final Map contactsMap = new Hashtable(); + private static final Map progressDialogMap = + new ConcurrentHashMap(); + public static Contact getContact(SessionID sessionID) { return contactsMap.get(new ScSessionID(sessionID)); @@ -145,11 +383,14 @@ public static SessionID getSessionID(Contact contact) */ private final Logger logger = Logger.getLogger(ScOtrEngineImpl.class); - private final OtrEngine otrEngine - = new OtrEngineImpl(new ScOtrEngineHost()); + final OtrEngineHost otrEngineHost = new ScOtrEngineHost(); + + private final OtrEngine otrEngine; public ScOtrEngineImpl() { + otrEngine = new OtrEngineImpl(otrEngineHost); + // Clears the map after previous instance // This is required because of OSGi restarts in the same VM on Android contactsMap.clear(); @@ -449,6 +690,9 @@ public void serviceChanged(ServiceEvent ev) logger.debug( "Unregistering a ProtocolProviderService, cleaning" + " OTR's ScSessionID to Contact map."); + logger.debug( + "Unregistering a ProtocolProviderService, cleaning" + + " OTR's Contact to SpmProgressDialog map."); } ProtocolProviderService provider @@ -464,6 +708,14 @@ public void serviceChanged(ServiceEvent ev) i.remove(); } } + + Iterator i = progressDialogMap.keySet().iterator(); + + while (i.hasNext()) + { + if (provider.equals(i.next().getProtocolProvider())) + i.remove(); + } } } @@ -545,4 +797,398 @@ public String transformSending(Contact contact, String msgText) return null; } } + + private Session getSession(Contact contact) + { + SessionID sessionID = getSessionID(contact); + return otrEngine.getSession(sessionID); + } + + @Override + public void initSmp(Contact contact, String question, String secret) + { + Session session = getSession(contact); + try + { + session.initSmp(question, secret); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.init(); + progressDialog.setVisible(true); + } + catch (OtrException e) + { + logger.error("Error initializing SMP session with contact " + + contact.getDisplayName(), e); + showError(session.getSessionID(), e.getMessage()); + } + } + + @Override + public void respondSmp(Contact contact, String question, String secret) + { + Session session = getSession(contact); + try + { + session.respondSmp(question, secret); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.incrementProgress(); + progressDialog.setVisible(true); + } + catch (OtrException e) + { + logger.error( + "Error occured when sending SMP response to contact " + + contact.getDisplayName(), e); + showError(session.getSessionID(), e.getMessage()); + } + } + + @Override + public void abortSmp(Contact contact) + { + Session session = getSession(contact); + try + { + session.abortSmp(); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.dispose(); + } + catch (OtrException e) + { + logger.error("Error aborting SMP session with contact " + + contact.getDisplayName(), e); + showError(session.getSessionID(), e.getMessage()); + } + + } + + /** + * The dialog that pops up when SMP negotiation starts. + * It contains a progress bar that indicates the status of the SMP + * authentication process. + */ + @SuppressWarnings("serial") + private class SmpProgressDialog + extends SIPCommDialog + { + private final JProgressBar progressBar = new JProgressBar(0, 100); + + private final Color successColor = new Color(86, 140, 2); + + private final Color failColor = new Color(204, 0, 0); + + private final JLabel iconLabel = new JLabel(); + + /** + * Instantiates SmpProgressDialog. + * + * @param contact The contact that this dialog is associated with. + */ + public SmpProgressDialog(Contact contact) + { + setTitle( + OtrActivator.resourceService.getI18NString( + "plugin.otr.smpprogressdialog.TITLE")); + + JPanel mainPanel = new TransparentPanel(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + mainPanel.setBorder( + BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPanel.setPreferredSize(new Dimension(300, 70)); + + String authFromText = + String.format( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_FROM", + new String[] {contact.getDisplayName()})); + + JPanel labelsPanel = new TransparentPanel(); + labelsPanel.setLayout(new BoxLayout(labelsPanel, BoxLayout.X_AXIS)); + + labelsPanel.add(iconLabel); + labelsPanel.add(Box.createRigidArea(new Dimension(5,0))); + labelsPanel.add(new JLabel(authFromText)); + + mainPanel.add(labelsPanel); + mainPanel.add(progressBar); + + init(); + + this.getContentPane().add(mainPanel); + this.pack(); + } + + /** + * Initializes the progress bar and sets it's progression to 1/3. + */ + public void init() + { + progressBar.setUI(new BasicProgressBarUI() { + private Rectangle r = new Rectangle(); + + @Override + protected void paintIndeterminate(Graphics g, JComponent c) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + r = getBox(r); + g.setColor(progressBar.getForeground()); + g.fillOval(r.x, r.y, r.width, r.height); + } + }); + progressBar.setValue(33); + progressBar.setForeground(successColor); + progressBar.setStringPainted(false); + iconLabel.setIcon( + OtrActivator.resourceService.getImage( + "plugin.otr.ENCRYPTED_UNVERIFIED_ICON_22x22")); + } + + /** + * Sets the progress bar to 2/3 of completion. + */ + public void incrementProgress() + { + progressBar.setValue(66); + } + + /** + * Sets the progress bar to green. + */ + public void setProgressSuccess() + { + progressBar.setValue(100); + progressBar.setForeground(successColor); + progressBar.setStringPainted(true); + progressBar.setString( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.smpprogressdialog.AUTHENTICATION_SUCCESS")); + iconLabel.setIcon( + OtrActivator.resourceService.getImage( + "plugin.otr.ENCRYPTED_ICON_22x22")); + } + + /** + * Sets the progress bar to red. + */ + public void setProgressFail() + { + progressBar.setValue(100); + progressBar.setForeground(failColor); + progressBar.setStringPainted(true); + progressBar.setString( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.smpprogressdialog.AUTHENTICATION_FAIL")); + } + } + + /** + * The dialog that pops up when the remote party send us SMP + * request. It contains detailed information for the user about + * the authentication process and allows him to authenticate. + * + */ + @SuppressWarnings("serial") + private class SmpAuthenticateBuddyDialog + extends SIPCommDialog + { + private final Contact contact; + + private final String question; + + SmpAuthenticateBuddyDialog(Contact contact, String question) + { + this.contact = contact; + this.question = question; + initComponents(); + } + + private void initComponents() + { + this.setTitle( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.TITLE")); + + // The main panel that contains all components. + JPanel mainPanel = new TransparentPanel(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + mainPanel.setBorder( + BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPanel.setPreferredSize(new Dimension(300, 350)); + + // Add "authentication from contact" to the main panel. + JTextArea authenticationFrom = new CustomTextArea(); + Font newFont = + new Font( + UIManager.getDefaults().getFont("TextArea.font"). + getFontName() + , Font.BOLD + , 14); + authenticationFrom.setFont(newFont); + String authFromText = + String.format( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_FROM", + new String[] {contact.getDisplayName()})); + authenticationFrom.setText(authFromText); + mainPanel.add(authenticationFrom); + + // Add "general info" text to the main panel. + JTextArea generalInfo = new CustomTextArea(); + generalInfo.setText(OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_INFO")); + mainPanel.add(generalInfo); + + // Add "authentication-by-secret" info text to the main panel. + JTextArea authBySecretInfo = new CustomTextArea(); + newFont = + new Font( + UIManager.getDefaults().getFont("TextArea.font"). + getFontName() + , Font.ITALIC + , 10); + authBySecretInfo.setText(OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTH_BY_SECRET_INFO_RESPOND")); + authBySecretInfo.setFont(newFont); + mainPanel.add(authBySecretInfo); + + // Create a panel to add question/answer related components + JPanel questionAnswerPanel = new JPanel(new GridBagLayout()); + questionAnswerPanel.setBorder(BorderFactory.createEtchedBorder()); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 0, 5); + c.weightx = 0; + + // Add question label. + JLabel questionLabel = + new JLabel( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.QUESTION_RESPOND")); + questionAnswerPanel.add(questionLabel, c); + + // Add the question. + c.insets = new Insets(0, 5, 5, 5); + c.gridy = 1; + JTextArea questionArea = + new CustomTextArea(); + newFont = + new Font( + UIManager.getDefaults().getFont("TextArea.font"). + getFontName() + , Font.BOLD + , UIManager.getDefaults().getFont("TextArea.font") + .getSize()); + questionArea.setFont(newFont); + questionArea.setText(question); + questionAnswerPanel.add(questionArea, c); + + // Add answer label. + c.insets = new Insets(5, 5, 5, 5); + c.gridy = 2; + JLabel answerLabel = + new JLabel(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.ANSWER")); + questionAnswerPanel.add(answerLabel, c); + + // Add the answer text field. + c.gridy = 3; + final JTextField answerTextBox = new JTextField(); + questionAnswerPanel.add(answerTextBox, c); + + // Add the question/answer panel to the main panel. + mainPanel.add(questionAnswerPanel); + + // Buttons panel. + JPanel buttonPanel = new TransparentPanel(new GridBagLayout()); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5)); + + JButton helpButton = + new JButton(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.HELP")); + helpButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + OtrActivator.scOtrEngine.launchHelp(); + } + }); + + c.gridwidth = 1; + c.gridy = 0; + c.gridx = 0; + c.weightx = 0; + c.insets = new Insets(5, 5, 5, 20); + buttonPanel.add(helpButton, c); + + JButton cancelButton = + new JButton(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.CANCEL")); + cancelButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + ScOtrEngineImpl.this.abortSmp(contact); + SmpAuthenticateBuddyDialog.this.dispose(); + } + }); + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 1; + buttonPanel.add(cancelButton, c); + + c.gridx = 2; + JButton authenticateButton = + new JButton(OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATE_BUDDY")); + authenticateButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + ScOtrEngineImpl.this.respondSmp( + contact, question, answerTextBox.getText()); + SmpAuthenticateBuddyDialog.this.dispose(); + } + }); + + buttonPanel.add(authenticateButton, c); + + this.getContentPane().add(mainPanel, BorderLayout.NORTH); + this.getContentPane().add(buttonPanel, BorderLayout.SOUTH); + this.pack(); + } + } } diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java index fef0f9f88..bc83cd7a5 100755 --- a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java +++ b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java @@ -32,6 +32,8 @@ public interface ScOtrKeyManager public abstract String getLocalFingerprint(AccountID account); + public abstract byte[] getLocalFingerprintRaw(AccountID account); + public abstract void savePublicKey(Contact contact, PublicKey pubKey); public abstract PublicKey loadPublicKey(Contact contact); diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java index c461ad0d3..37adc6325 100755 --- a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java +++ b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java @@ -131,6 +131,26 @@ public String getLocalFingerprint(AccountID account) } } + public byte[] getLocalFingerprintRaw(AccountID account) + { + KeyPair keyPair = loadKeyPair(account); + + if (keyPair == null) + return null; + + PublicKey pubKey = keyPair.getPublic(); + + try + { + return new OtrCryptoEngineImpl().getFingerprintRaw(pubKey); + } + catch (OtrCryptoException e) + { + e.printStackTrace(); + return null; + } + } + public void savePublicKey(Contact contact, PublicKey pubKey) { if (contact == null) diff --git a/src/net/java/sip/communicator/plugin/otr/SecretQuestionAuthenticationPanel.java b/src/net/java/sip/communicator/plugin/otr/SecretQuestionAuthenticationPanel.java new file mode 100644 index 000000000..7134d7da3 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/SecretQuestionAuthenticationPanel.java @@ -0,0 +1,117 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.otr; + +import java.awt.*; + +import javax.swing.*; + +import net.java.sip.communicator.plugin.desktoputil.*; + +/** + * @author Marin Dzhigarov + */ +@SuppressWarnings("serial") +public class SecretQuestionAuthenticationPanel + extends TransparentPanel +{ + /** + * The text field where the authentication initiator will type his question. + */ + private final JTextField question = new JTextField(); + + /** + * The text field where the authentication initiator will type his answer. + */ + private final JTextField answer = new JTextField(); + + + /** + * Creates an instance SecretQuestionAuthenticationPanel. + */ + SecretQuestionAuthenticationPanel() + { + initComponents(); + } + + /** + * Initializes the {@link SecretQuestionAuthenticationPanel} components. + */ + private void initComponents() + { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + JTextArea generalInformation = new CustomTextArea(); + generalInformation.setText( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTH_BY_QUESTION_INFO_INIT")); + this.add(generalInformation); + + this.add(Box.createVerticalStrut(10)); + + JPanel questionAnswerPanel = new JPanel(new GridBagLayout()); + questionAnswerPanel.setBorder(BorderFactory.createEtchedBorder()); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 0, 5); + c.weightx = 1; + + JLabel questionLabel = + new JLabel( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.QUESTION_INIT")); + questionAnswerPanel.add(questionLabel, c); + + c.gridy = 1; + c.insets = new Insets(0, 5, 5, 5); + questionAnswerPanel.add(question, c); + + c.gridy = 2; + c.insets = new Insets(5, 5, 0, 5); + JLabel answerLabel = + new JLabel( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.ANSWER")); + questionAnswerPanel.add(answerLabel, c); + + c.gridy = 3; + c.insets = new Insets(0, 5, 5, 5); + questionAnswerPanel.add(answer, c); + + this.add(questionAnswerPanel); + this.add(new Box.Filler( + new Dimension(300, 100), + new Dimension(300, 100), + new Dimension(300, 100))); + } + + /** + * Returns the secret answer text. + * + * @return The secret answer text. + */ + String getSecret() + { + return answer.getText(); + } + + /** + * Returns the secret question text. + * + * @return The secret question text. + */ + String getQuestion() + { + return question.getText(); + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/SharedSecretAuthenticationPanel.java b/src/net/java/sip/communicator/plugin/otr/SharedSecretAuthenticationPanel.java new file mode 100644 index 000000000..39769f23f --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/SharedSecretAuthenticationPanel.java @@ -0,0 +1,89 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.otr; + +import java.awt.*; + +import javax.swing.*; + +import net.java.sip.communicator.plugin.desktoputil.*; + +/** + * @author Marin Dzhigarov + * + */ +@SuppressWarnings("serial") +public class SharedSecretAuthenticationPanel + extends TransparentPanel +{ + /** + * The text field where the authentication initiator will type his answer. + */ + private final JTextField secret = new JTextField(); + + /** + * Creates an instance SecretQuestionAuthenticationPanel. + */ + SharedSecretAuthenticationPanel() + { + initComponents(); + } + + /** + * Initializes the {@link SecretQuestionAuthenticationPanel} components. + */ + private void initComponents() + { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + JTextArea generalInformation = new CustomTextArea(); + generalInformation.setText( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTH_BY_SECRET_INFO_INIT")); + this.add(generalInformation); + + this.add(Box.createVerticalStrut(10)); + + JPanel questionAnswerPanel = new JPanel(new GridBagLayout()); + questionAnswerPanel.setBorder(BorderFactory.createEtchedBorder()); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 0, 5); + c.weightx = 1; + + JLabel questionLabel = + new JLabel( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.SHARED_SECRET")); + questionAnswerPanel.add(questionLabel, c); + + c.gridy = 1; + c.insets = new Insets(0, 5, 5, 5); + questionAnswerPanel.add(secret, c); + + this.add(questionAnswerPanel); + this.add(new Box.Filler( + new Dimension(300, 150), + new Dimension(300, 150), + new Dimension(300, 150))); + } + + /** + * Returns the shared secret text. + * + * @return The shared secret text. + */ + String getSecret() + { + return secret.getText(); + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf b/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf index 3e74c53ff..71c607c4d 100644 --- a/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf +++ b/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf @@ -20,6 +20,8 @@ Import-Package: org.osgi.framework, javax.swing.table, javax.swing.text, javax.swing.event, + javax.swing.plaf, + javax.swing.plaf.basic, javax.crypto, javax.crypto.interfaces, javax.crypto.spec,