diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 246f05eb2..bbb104fe8 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -514,9 +514,6 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { // Check if not already connected throwAlreadyConnectedExceptionIfAppropriate(); - // Notify connection listeners that we are trying to connect - callConnectionConnectingListener(); - // Reset the connection state initState(); closingStreamReceived = false; @@ -1683,12 +1680,6 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { } } - protected void callConnectionConnectingListener() { - for (ConnectionListener listener : connectionListeners) { - listener.connecting(this); - } - } - protected void callConnectionConnectedListener() { for (ConnectionListener listener : connectionListeners) { listener.connected(this); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionListener.java b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionListener.java index 304c8c75a..3e85191b9 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionListener.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionListener.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software, 2020 Paul Schaub + * Copyright 2003-2007 Jive Software. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,16 +28,6 @@ package org.jivesoftware.smack; */ public interface ConnectionListener { - /** - * Notification that the connection is in the process of connecting. - * This method is called when {@link AbstractXMPPConnection#connect()} is executed. - * - * @param connection connection - * @since 4.4 - */ - default void connecting(XMPPConnection connection) { - } - /** * Notification that the connection has been successfully connected to the remote endpoint (e.g. the XMPP server). *

diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java index 77bc402c3..c966b2d34 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java @@ -270,12 +270,7 @@ public class StringUtils { /** * 24 upper case characters from the latin alphabet and numbers without '0' and 'O'. */ - public static final String UNAMBIGUOUS_NUMBERS_AND_LETTERS_STRING = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"; - - /** - * 24 upper case characters from the latin alphabet and numbers without '0' and 'O'. - */ - private static final char[] UNAMBIGUOUS_NUMBERS_AND_LETTERS = UNAMBIGUOUS_NUMBERS_AND_LETTERS_STRING.toCharArray(); + private static final char[] UNAMBIGUOUS_NUMBERS_AND_LETTER = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ".toCharArray(); /** * Returns a random String of numbers and letters (lower and upper case) @@ -299,14 +294,14 @@ public class StringUtils { // See also https://www.grc.com/haystack.htm final int REQUIRED_LENGTH = 10; - return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTERS, REQUIRED_LENGTH); + return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTER, REQUIRED_LENGTH); } public static String secureUniqueRandomString() { // 34^13 = 8.11e19 possible combinations, which is > 2^64. final int REQUIRED_LENGTH = 13; - return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTERS, REQUIRED_LENGTH); + return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTER, REQUIRED_LENGTH); } /** @@ -329,7 +324,7 @@ public class StringUtils { // See also https://www.grc.com/haystack.htm final int REQUIRED_LENGTH = 24; - return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTERS, REQUIRED_LENGTH); + return randomString(RandomUtil.SECURE_RANDOM.get(), UNAMBIGUOUS_NUMBERS_AND_LETTER, REQUIRED_LENGTH); } private static final int RANDOM_STRING_CHUNK_SIZE = 4; @@ -373,8 +368,8 @@ public class StringUtils { char[] randomChars = new char[length]; for (int i = 0; i < length; i++) { - int index = random.nextInt(UNAMBIGUOUS_NUMBERS_AND_LETTERS.length); - randomChars[i] = UNAMBIGUOUS_NUMBERS_AND_LETTERS[index]; + int index = random.nextInt(UNAMBIGUOUS_NUMBERS_AND_LETTER.length); + randomChars[i] = UNAMBIGUOUS_NUMBERS_AND_LETTER[index]; } return new String(randomChars); } diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/ox/OXSecretKeyBackupIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/ox/OXSecretKeyBackupIntegrationTest.java index 8031301ad..ba8d378bb 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/ox/OXSecretKeyBackupIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/ox/OXSecretKeyBackupIntegrationTest.java @@ -16,7 +16,6 @@ */ package org.jivesoftware.smackx.ox; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -27,11 +26,17 @@ import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.util.Arrays; +import java.util.Set; import java.util.logging.Level; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.util.StringUtils; + +import org.jivesoftware.smackx.ox.callback.backup.AskForBackupCodeCallback; +import org.jivesoftware.smackx.ox.callback.backup.DisplayBackupCodeCallback; +import org.jivesoftware.smackx.ox.callback.backup.SecretKeyBackupSelectionCallback; import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider; import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException; import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyException; @@ -59,6 +64,10 @@ public class OXSecretKeyBackupIntegrationTest extends AbstractOpenPgpIntegration private static final File beforePath = new File(tempDir, "ox_backup_" + sessionId); private static final File afterPath = new File(tempDir, "ox_restore_" + sessionId); + private String backupCode = null; + + private OpenPgpManager openPgpManager; + /** * This integration test tests the basic secret key backup and restore functionality as described * in XEP-0373 §5. @@ -114,7 +123,7 @@ public class OXSecretKeyBackupIntegrationTest extends AbstractOpenPgpIntegration OpenPgpStore beforeStore = new FileBasedOpenPgpStore(beforePath); beforeStore.setKeyRingProtector(new UnprotectedKeysProtector()); PainlessOpenPgpProvider beforeProvider = new PainlessOpenPgpProvider(beforeStore); - OpenPgpManager openPgpManager = OpenPgpManager.getInstanceFor(aliceConnection); + openPgpManager = OpenPgpManager.getInstanceFor(aliceConnection); openPgpManager.setOpenPgpProvider(beforeProvider); OpenPgpSelf self = openPgpManager.getOpenPgpSelf(); @@ -132,15 +141,29 @@ public class OXSecretKeyBackupIntegrationTest extends AbstractOpenPgpIntegration PGPPublicKeyRing beforePub = beforeStore.getPublicKeyRing(alice, keyFingerprint); assertNotNull(beforePub); - OpenPgpSecretKeyBackupPassphrase backupPassphrase = - openPgpManager.backupSecretKeyToServer(availableSecretKeys -> availableSecretKeys); + openPgpManager.backupSecretKeyToServer(new DisplayBackupCodeCallback() { + @Override + public void displayBackupCode(String backupCode) { + OXSecretKeyBackupIntegrationTest.this.backupCode = backupCode; + } + }, new SecretKeyBackupSelectionCallback() { + @Override + public Set selectKeysToBackup(Set availableSecretKeys) { + return availableSecretKeys; + } + }); FileBasedOpenPgpStore afterStore = new FileBasedOpenPgpStore(afterPath); afterStore.setKeyRingProtector(new UnprotectedKeysProtector()); PainlessOpenPgpProvider afterProvider = new PainlessOpenPgpProvider(afterStore); openPgpManager.setOpenPgpProvider(afterProvider); - OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(() -> backupPassphrase); + OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(new AskForBackupCodeCallback() { + @Override + public String askForBackupCode() { + return backupCode; + } + }); assertEquals(keyFingerprint, fingerprint); @@ -150,10 +173,10 @@ public class OXSecretKeyBackupIntegrationTest extends AbstractOpenPgpIntegration PGPSecretKeyRing afterSec = afterStore.getSecretKeyRing(alice, keyFingerprint); assertNotNull(afterSec); - assertArrayEquals(beforeSec.getEncoded(), afterSec.getEncoded()); + assertTrue(Arrays.equals(beforeSec.getEncoded(), afterSec.getEncoded())); PGPPublicKeyRing afterPub = afterStore.getPublicKeyRing(alice, keyFingerprint); assertNotNull(afterPub); - assertArrayEquals(beforePub.getEncoded(), afterPub.getEncoded()); + assertTrue(Arrays.equals(beforePub.getEncoded(), afterPub.getEncoded())); } } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java index 61c86b61f..ce49dbde6 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java @@ -1,6 +1,6 @@ /** * - * Copyright 2018-2020 Paul Schaub, 2017-2020 Florian Schmaus. + * Copyright 2017-2020 Florian Schmaus, 2018 Paul Schaub. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import static org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil.PEP_NODE_PUBLIC_ import static org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil.PEP_NODE_PUBLIC_KEYS_NOTIFY; import static org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil.publishPublicKey; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; @@ -42,8 +43,10 @@ import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.util.Async; import org.jivesoftware.smack.util.stringencoder.Base64; import org.jivesoftware.smack.xml.XmlPullParserException; + import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.ox.callback.backup.AskForBackupCodeCallback; +import org.jivesoftware.smackx.ox.callback.backup.DisplayBackupCodeCallback; import org.jivesoftware.smackx.ox.callback.backup.SecretKeyBackupSelectionCallback; import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider; import org.jivesoftware.smackx.ox.element.CryptElement; @@ -73,9 +76,12 @@ import org.jivesoftware.smackx.pubsub.PubSubException; import org.jivesoftware.smackx.pubsub.PubSubFeature; import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; +import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.EntityBareJid; import org.pgpainless.key.OpenPgpV4Fingerprint; @@ -383,9 +389,8 @@ public final class OpenPgpManager extends Manager { * * @see XEP-0373 §5 * + * @param displayCodeCallback callback, which will receive the backup password used to encrypt the secret key. * @param selectKeyCallback callback, which will receive the users choice of which keys will be backed up. - * @return secret key passphrase used to encrypt the backup. - * * @throws InterruptedException if the thread is interrupted. * @throws PubSubException.NotALeafNodeException if the private node is not a {@link LeafNode}. * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error. @@ -397,38 +402,8 @@ public final class OpenPgpManager extends Manager { * @throws PGPException PGP is brittle * @throws MissingOpenPgpKeyException in case we have no OpenPGP key pair to back up. */ - public OpenPgpSecretKeyBackupPassphrase backupSecretKeyToServer(SecretKeyBackupSelectionCallback selectKeyCallback) - throws InterruptedException, PubSubException.NotALeafNodeException, - XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, - SmackException.NotLoggedInException, IOException, - SmackException.FeatureNotSupportedException, PGPException, MissingOpenPgpKeyException { - OpenPgpSecretKeyBackupPassphrase passphrase = SecretKeyBackupHelper.generateBackupPassword(); - backupSecretKeyToServer(selectKeyCallback, passphrase); - return passphrase; - } - - /** - * Upload the encrypted secret key to a private PEP node. - * The backup is encrypted using the provided secret key passphrase. - * - * @see XEP-0373 §5 - * - * @param selectKeyCallback callback, which will receive the users choice of which keys will be backed up. @param selectKeyCallback - * @param passphrase secret key passphrase - * - * @throws InterruptedException if the thread is interrupted. - * @throws PubSubException.NotALeafNodeException if the private node is not a {@link LeafNode}. - * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error. - * @throws SmackException.NotConnectedException if we are not connected. - * @throws SmackException.NoResponseException if the server doesn't respond. - * @throws SmackException.NotLoggedInException if we are not logged in. - * @throws IOException IO is dangerous. - * @throws SmackException.FeatureNotSupportedException if the server doesn't support the PubSub whitelist access model. - * @throws PGPException PGP is brittle - * @throws MissingOpenPgpKeyException in case we have no OpenPGP key pair to back up. - */ - public void backupSecretKeyToServer(SecretKeyBackupSelectionCallback selectKeyCallback, - OpenPgpSecretKeyBackupPassphrase passphrase) + public void backupSecretKeyToServer(DisplayBackupCodeCallback displayCodeCallback, + SecretKeyBackupSelectionCallback selectKeyCallback) throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, SmackException.NotLoggedInException, IOException, @@ -438,6 +413,8 @@ public final class OpenPgpManager extends Manager { BareJid ownJid = connection().getUser().asBareJid(); + String backupCode = SecretKeyBackupHelper.generateBackupPassword(); + PGPSecretKeyRingCollection secretKeyRings = provider.getStore().getSecretKeysOf(ownJid); Set availableKeyPairs = new HashSet<>(); @@ -447,9 +424,10 @@ public final class OpenPgpManager extends Manager { Set selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs); - SecretkeyElement secretKey = SecretKeyBackupHelper.createSecretkeyElement(provider, ownJid, selectedKeyPairs, passphrase); + SecretkeyElement secretKey = SecretKeyBackupHelper.createSecretkeyElement(provider, ownJid, selectedKeyPairs, backupCode); OpenPgpPubSubUtil.depositSecretKey(connection(), secretKey); + displayCodeCallback.displayBackupCode(backupCode); } /** @@ -498,14 +476,19 @@ public final class OpenPgpManager extends Manager { throw new NoBackupFoundException(); } - OpenPgpSecretKeyBackupPassphrase backupCode = codeCallback.askForBackupCode(); + String backupCode = codeCallback.askForBackupCode(); PGPSecretKeyRing secretKeys = SecretKeyBackupHelper.restoreSecretKeyBackup(backup, backupCode); - OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(secretKeys); provider.getStore().importSecretKey(getJidOrThrow(), secretKeys); provider.getStore().importPublicKey(getJidOrThrow(), BCUtil.publicKeyRingFromSecretKeyRing(secretKeys)); - getOpenPgpSelf().trust(fingerprint); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(2048); + for (PGPSecretKey sk : secretKeys) { + PGPPublicKey pk = sk.getPublicKey(); + if (pk != null) pk.encode(buffer); + } + PGPPublicKeyRing publicKeys = new PGPPublicKeyRing(buffer.toByteArray(), new BcKeyFingerprintCalculator()); + provider.getStore().importPublicKey(getJidOrThrow(), publicKeys); return new OpenPgpV4Fingerprint(secretKeys); } @@ -568,7 +551,7 @@ public final class OpenPgpManager extends Manager { if (contentElement instanceof SigncryptElement) { for (SigncryptElementReceivedListener l : signcryptElementReceivedListeners) { l.signcryptElementReceived(contact, message, (SigncryptElement) contentElement, - decrypted.getMetadata()); + decrypted.getMetadata()); } return; } @@ -583,7 +566,7 @@ public final class OpenPgpManager extends Manager { if (contentElement instanceof CryptElement) { for (CryptElementReceivedListener l : cryptElementReceivedListeners) { l.cryptElementReceived(contact, message, (CryptElement) contentElement, - decrypted.getMetadata()); + decrypted.getMetadata()); } return; } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpSecretKeyBackupPassphrase.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpSecretKeyBackupPassphrase.java deleted file mode 100644 index cc96bbd4f..000000000 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpSecretKeyBackupPassphrase.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * - * Copyright 2020 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.ox; - -import static org.jivesoftware.smack.util.StringUtils.UNAMBIGUOUS_NUMBERS_AND_LETTERS_STRING; - -import java.util.regex.Pattern; - -/** - * Represents a secret key backup passphrase whose format is described in XEP-0373 §5.3. - * - * @see - * XEP-0373 §5.4 Encrypting the Secret Key Backup - */ -public class OpenPgpSecretKeyBackupPassphrase implements CharSequence { - - private static final Pattern PASSPHRASE_PATTERN = Pattern.compile( - "^([" + UNAMBIGUOUS_NUMBERS_AND_LETTERS_STRING + "]{4}-){5}" + - "[" + UNAMBIGUOUS_NUMBERS_AND_LETTERS_STRING + "]{4}$"); - - private final String passphrase; - - public OpenPgpSecretKeyBackupPassphrase(String passphrase) { - if (!PASSPHRASE_PATTERN.matcher(passphrase).matches()) { - throw new IllegalArgumentException("Passphrase must be 24 upper case letters and numbers from the english " + - "alphabet without 'O' and '0', divided into blocks of 4 and separated with dashes ('-')."); - } - this.passphrase = passphrase; - } - - @Override - public int length() { - return passphrase.length(); - } - - @Override - public char charAt(int i) { - return passphrase.charAt(i); - } - - @Override - public CharSequence subSequence(int i, int i1) { - return passphrase.subSequence(i, i1); - } - - @Override - public String toString() { - return passphrase; - } -} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/AskForBackupCodeCallback.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/AskForBackupCodeCallback.java index 5d7a214bc..4a6653012 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/AskForBackupCodeCallback.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/AskForBackupCodeCallback.java @@ -16,8 +16,6 @@ */ package org.jivesoftware.smackx.ox.callback.backup; -import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase; - public interface AskForBackupCodeCallback { /** @@ -29,5 +27,5 @@ public interface AskForBackupCodeCallback { * * @return backup code provided by the user. */ - OpenPgpSecretKeyBackupPassphrase askForBackupCode(); + String askForBackupCode(); } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/DisplayBackupCodeCallback.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/DisplayBackupCodeCallback.java new file mode 100644 index 000000000..bc41a92bb --- /dev/null +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/DisplayBackupCodeCallback.java @@ -0,0 +1,32 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.ox.callback.backup; + +public interface DisplayBackupCodeCallback { + + /** + * This method is used to provide a client access to the generated backup code. + * The client can then go ahead and display the code to the user. + * The backup code follows the format described in XEP-0373 §5.3 + * + * @see + * XEP-0373 §5.4 Encrypting the Secret Key Backup + * + * @param backupCode backup code + */ + void displayBackupCode(String backupCode); +} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/OpenPgpPubSubUtil.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/OpenPgpPubSubUtil.java index 0e418d80b..b36ca19f3 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/OpenPgpPubSubUtil.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/OpenPgpPubSubUtil.java @@ -111,7 +111,7 @@ public class OpenPgpPubSubUtil { * Publish the users OpenPGP public key to the public key node if necessary. * Also announce the key to other users by updating the metadata node. * - * @see XEP-0373 §4.1 + * @see XEP-0373 §4.1 * * @param pepManager The PEP manager. * @param pubkeyElement {@link PubkeyElement} containing the public key diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/SecretKeyBackupHelper.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/SecretKeyBackupHelper.java index 978f22eb4..59f0fd56e 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/SecretKeyBackupHelper.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/SecretKeyBackupHelper.java @@ -23,7 +23,6 @@ import java.util.Set; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.stringencoder.Base64; -import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase; import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider; import org.jivesoftware.smackx.ox.element.SecretkeyElement; import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException; @@ -52,8 +51,8 @@ public class SecretKeyBackupHelper { * * @return backup code */ - public static OpenPgpSecretKeyBackupPassphrase generateBackupPassword() { - return new OpenPgpSecretKeyBackupPassphrase(StringUtils.secureOfflineAttackSafeRandomString()); + public static String generateBackupPassword() { + return StringUtils.secureOfflineAttackSafeRandomString(); } /** @@ -74,7 +73,7 @@ public class SecretKeyBackupHelper { public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider, BareJid owner, Set fingerprints, - OpenPgpSecretKeyBackupPassphrase backupCode) + String backupCode) throws PGPException, IOException, MissingOpenPgpKeyException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); @@ -106,9 +105,9 @@ public class SecretKeyBackupHelper { * @throws IOException IO is dangerous */ public static SecretkeyElement createSecretkeyElement(byte[] keys, - OpenPgpSecretKeyBackupPassphrase backupCode) + String backupCode) throws PGPException, IOException { - byte[] encrypted = PGPainless.encryptWithPassword(keys, new Passphrase(backupCode.toString().toCharArray()), + byte[] encrypted = PGPainless.encryptWithPassword(keys, new Passphrase(backupCode.toCharArray()), SymmetricKeyAlgorithm.AES_256); return new SecretkeyElement(Base64.encode(encrypted)); } @@ -124,13 +123,13 @@ public class SecretKeyBackupHelper { * @throws IOException IO is dangerous. * @throws PGPException PGP is brittle. */ - public static PGPSecretKeyRing restoreSecretKeyBackup(SecretkeyElement backup, OpenPgpSecretKeyBackupPassphrase backupCode) + public static PGPSecretKeyRing restoreSecretKeyBackup(SecretkeyElement backup, String backupCode) throws InvalidBackupCodeException, IOException, PGPException { byte[] encrypted = Base64.decode(backup.getB64Data()); byte[] decrypted; try { - decrypted = PGPainless.decryptWithPassword(encrypted, new Passphrase(backupCode.toString().toCharArray())); + decrypted = PGPainless.decryptWithPassword(encrypted, new Passphrase(backupCode.toCharArray())); } catch (IOException | PGPException e) { throw new InvalidBackupCodeException("Could not decrypt secret key backup. Possibly wrong passphrase?", e); } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox_im/OXInstantMessagingManager.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox_im/OXInstantMessagingManager.java index c9fc021eb..4383a02b3 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox_im/OXInstantMessagingManager.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox_im/OXInstantMessagingManager.java @@ -264,7 +264,7 @@ public final class OXInstantMessagingManager extends Manager { * Add an OX-IM message element to a message. * * @param messageBuilder message - * @param recipients recipients of the message + * @param contacts recipients of the message * @param payload payload which will be encrypted and signed * * @return metadata about the messages encryption + signatures. @@ -273,9 +273,13 @@ public final class OXInstantMessagingManager extends Manager { * @throws PGPException in case something goes wrong during encryption * @throws IOException IO is dangerous (we need to read keys) */ - public OpenPgpMetadata addOxMessage(MessageBuilder messageBuilder, Set recipients, List payload) + public OpenPgpMetadata addOxMessage(MessageBuilder messageBuilder, Set contacts, List payload) throws SmackException.NotLoggedInException, IOException, PGPException { + HashSet recipients = new HashSet<>(contacts); + OpenPgpContact self = openPgpManager.getOpenPgpSelf(); + recipients.add(self); + OpenPgpElementAndMetadata openPgpElementAndMetadata = signAndEncrypt(recipients, payload); messageBuilder.addExtension(openPgpElementAndMetadata.getElement()); diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpSecretKeyBackupPassphraseTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpSecretKeyBackupPassphraseTest.java deleted file mode 100644 index 3c910a006..000000000 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpSecretKeyBackupPassphraseTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * - * Copyright 2020 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.ox; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThrows; - -import org.jivesoftware.smackx.ox.util.SecretKeyBackupHelper; - -import org.junit.jupiter.api.Test; - -public class OpenPgpSecretKeyBackupPassphraseTest { - - @Test - public void secretKeyPassphraseConstructorTest() { - OpenPgpSecretKeyBackupPassphrase valid = - new OpenPgpSecretKeyBackupPassphrase("TWNK-KD5Y-MT3T-E1GS-DRDB-KVTW"); - - assertNotNull(valid); - for (int i = 0; i < 50; i++) { - assertNotNull(SecretKeyBackupHelper.generateBackupPassword()); - } - - assertThrows(IllegalArgumentException.class, - () -> new OpenPgpSecretKeyBackupPassphrase("TWNKKD5YMT3TE1GSDRDBKVTW")); - - assertThrows(IllegalArgumentException.class, - () -> new OpenPgpSecretKeyBackupPassphrase("0123-4567-89AB-CDEF-GHIJ-KLMN")); - - assertThrows(IllegalArgumentException.class, - () -> new OpenPgpSecretKeyBackupPassphrase("CONT-AINS-ILLE-GALL-ETTE-RSO0")); - - assertThrows(IllegalArgumentException.class, - () -> new OpenPgpSecretKeyBackupPassphrase("TWNK-KD5Y-MT3T-E1GS-DRDB-")); - - assertThrows(IllegalArgumentException.class, - () -> new OpenPgpSecretKeyBackupPassphrase("TWNK-KD5Y-MT3T-E1GS-DRDB-KVTW-ADDD")); - - assertThrows(IllegalArgumentException.class, - () -> new OpenPgpSecretKeyBackupPassphrase("TWNK KD5Y MT3T E1GS DRDB KVTW")); - - } -} diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/SecretKeyBackupHelperTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/SecretKeyBackupHelperTest.java index ceaf50638..e7acc3201 100644 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/SecretKeyBackupHelperTest.java +++ b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/SecretKeyBackupHelperTest.java @@ -1,6 +1,6 @@ /** * - * Copyright 2018-2020 Paul Schaub. + * Copyright 2018 Paul Schaub. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,16 +18,17 @@ package org.jivesoftware.smackx.ox; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertArrayEquals; import java.io.File; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.util.Arrays; import java.util.Collections; import org.jivesoftware.smack.test.util.SmackTestSuite; + import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider; import org.jivesoftware.smackx.ox.element.SecretkeyElement; import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException; @@ -59,7 +60,7 @@ public class SecretKeyBackupHelperTest extends SmackTestSuite { public void backupPasswordGenerationTest() { final String alphabet = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"; - OpenPgpSecretKeyBackupPassphrase backupCode = SecretKeyBackupHelper.generateBackupPassword(); + String backupCode = SecretKeyBackupHelper.generateBackupPassword(); assertEquals(29, backupCode.length()); for (int i = 0; i < backupCode.length(); i++) { if ((i + 1) % 5 == 0) { @@ -85,13 +86,12 @@ public class SecretKeyBackupHelperTest extends SmackTestSuite { provider.getStore().importSecretKey(jid, keyRing.getSecretKeys()); // Create encrypted backup - OpenPgpSecretKeyBackupPassphrase backupCode = SecretKeyBackupHelper.generateBackupPassword(); - SecretkeyElement element = SecretKeyBackupHelper.createSecretkeyElement(provider, jid, - Collections.singleton(new OpenPgpV4Fingerprint(keyRing.getSecretKeys())), backupCode); + String backupCode = SecretKeyBackupHelper.generateBackupPassword(); + SecretkeyElement element = SecretKeyBackupHelper.createSecretkeyElement(provider, jid, Collections.singleton(new OpenPgpV4Fingerprint(keyRing.getSecretKeys())), backupCode); // Decrypt backup and compare PGPSecretKeyRing secretKeyRing = SecretKeyBackupHelper.restoreSecretKeyBackup(element, backupCode); - assertArrayEquals(keyRing.getSecretKeys().getEncoded(), secretKeyRing.getEncoded()); + assertTrue(Arrays.equals(keyRing.getSecretKeys().getEncoded(), secretKeyRing.getEncoded())); } @AfterClass