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