This commit is contained in:
Paul Schaub 2018-07-08 22:31:35 +02:00
parent 06dbb37a0e
commit 8e4013fff3
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
25 changed files with 422 additions and 185 deletions

View File

@ -16,8 +16,6 @@
*/ */
package org.jivesoftware.smackx.openpgp; package org.jivesoftware.smackx.openpgp;
import static junit.framework.TestCase.assertTrue;
import java.io.File; import java.io.File;
import java.util.logging.Level; import java.util.logging.Level;
@ -29,11 +27,10 @@ import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.ox.OXInstantMessagingManager; import org.jivesoftware.smackx.ox.OXInstantMessagingManager;
import org.jivesoftware.smackx.ox.OpenPgpContact; import org.jivesoftware.smackx.ox.OpenPgpContact;
import org.jivesoftware.smackx.ox.OpenPgpManager; import org.jivesoftware.smackx.ox.OpenPgpManager;
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
import org.jivesoftware.smackx.ox.bouncycastle.FileBasedPainlessOpenPgpStore;
import org.jivesoftware.smackx.ox.bouncycastle.PainlessOpenPgpProvider;
import org.jivesoftware.smackx.ox.element.SigncryptElement; import org.jivesoftware.smackx.ox.element.SigncryptElement;
import org.jivesoftware.smackx.ox.listener.OxMessageListener; import org.jivesoftware.smackx.ox.listener.OxMessageListener;
import org.jivesoftware.smackx.ox.store.filebased.FileBasedOpenPgpStore;
import org.jivesoftware.smackx.ox.util.PubSubDelegate; import org.jivesoftware.smackx.ox.util.PubSubDelegate;
import org.igniterealtime.smack.inttest.SmackIntegrationTest; import org.igniterealtime.smack.inttest.SmackIntegrationTest;
@ -43,6 +40,7 @@ import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector; import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector;
public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgpIntegrationTest { public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgpIntegrationTest {
@ -75,11 +73,13 @@ public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgp
final SimpleResultSyncPoint bobReceivedMessage = new SimpleResultSyncPoint(); final SimpleResultSyncPoint bobReceivedMessage = new SimpleResultSyncPoint();
final String body = "Writing integration tests is an annoying task, but it has to be done, so lets do it!!!"; final String body = "Writing integration tests is an annoying task, but it has to be done, so lets do it!!!";
FileBasedPainlessOpenPgpStore aliceStore = new FileBasedPainlessOpenPgpStore(aliceStorePath, new UnprotectedKeysProtector()); FileBasedOpenPgpStore aliceStore = new FileBasedOpenPgpStore(aliceStorePath);
FileBasedPainlessOpenPgpStore bobStore = new FileBasedPainlessOpenPgpStore(bobStorePath, new UnprotectedKeysProtector()); aliceStore.setKeyRingProtector(new UnprotectedKeysProtector());
FileBasedOpenPgpStore bobStore = new FileBasedOpenPgpStore(bobStorePath);
bobStore.setKeyRingProtector(new UnprotectedKeysProtector());
PainlessOpenPgpProvider aliceProvider = new PainlessOpenPgpProvider(alice, aliceStore); PainlessOpenPgpProvider aliceProvider = new PainlessOpenPgpProvider(aliceStore);
PainlessOpenPgpProvider bobProvider = new PainlessOpenPgpProvider(bob, bobStore); PainlessOpenPgpProvider bobProvider = new PainlessOpenPgpProvider(bobStore);
OpenPgpManager aliceOpenPgp = OpenPgpManager.getInstanceFor(aliceConnection); OpenPgpManager aliceOpenPgp = OpenPgpManager.getInstanceFor(aliceConnection);
OpenPgpManager bobOpenPgp = OpenPgpManager.getInstanceFor(bobConnection); OpenPgpManager bobOpenPgp = OpenPgpManager.getInstanceFor(bobConnection);
@ -104,20 +104,13 @@ public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgp
aliceFingerprint = aliceOpenPgp.generateAndImportKeyPair(alice); aliceFingerprint = aliceOpenPgp.generateAndImportKeyPair(alice);
bobFingerprint = bobOpenPgp.generateAndImportKeyPair(bob); bobFingerprint = bobOpenPgp.generateAndImportKeyPair(bob);
aliceStore.setSigningKeyPairFingerprint(aliceFingerprint);
bobStore.setSigningKeyPairFingerprint(bobFingerprint);
aliceOpenPgp.announceSupportAndPublish(); aliceOpenPgp.announceSupportAndPublish();
bobOpenPgp.announceSupportAndPublish(); bobOpenPgp.announceSupportAndPublish();
OpenPgpContact bobForAlice = aliceOpenPgp.getOpenPgpContact(bob.asEntityBareJidIfPossible()); OpenPgpContact bobForAlice = aliceOpenPgp.getOpenPgpContact(bob.asEntityBareJidIfPossible());
OpenPgpContact aliceForBob = bobOpenPgp.getOpenPgpContact(alice.asEntityBareJidIfPossible()); OpenPgpContact aliceForBob = bobOpenPgp.getOpenPgpContact(alice.asEntityBareJidIfPossible());
bobForAlice.updateKeys(); // TODO: Update keys
aliceForBob.updateKeys();
assertTrue(bobForAlice.getActiveKeys().contains(bobFingerprint));
assertTrue(aliceForBob.getActiveKeys().contains(aliceFingerprint));
aliceInstantMessaging.sendOxMessage(bobForAlice, body); aliceInstantMessaging.sendOxMessage(bobForAlice, body);

View File

@ -18,6 +18,7 @@ package org.jivesoftware.smackx.openpgp;
import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertNull; import static junit.framework.TestCase.assertNull;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
@ -34,21 +35,23 @@ import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.util.FileUtils; import org.jivesoftware.smack.util.FileUtils;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.ox.OpenPgpManager; import org.jivesoftware.smackx.ox.OpenPgpManager;
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; import org.jivesoftware.smackx.ox.OpenPgpSelf;
import org.jivesoftware.smackx.ox.bouncycastle.FileBasedPainlessOpenPgpStore;
import org.jivesoftware.smackx.ox.bouncycastle.PainlessOpenPgpProvider;
import org.jivesoftware.smackx.ox.callback.backup.AskForBackupCodeCallback; import org.jivesoftware.smackx.ox.callback.backup.AskForBackupCodeCallback;
import org.jivesoftware.smackx.ox.callback.backup.DisplayBackupCodeCallback; import org.jivesoftware.smackx.ox.callback.backup.DisplayBackupCodeCallback;
import org.jivesoftware.smackx.ox.callback.backup.SecretKeyBackupSelectionCallback; import org.jivesoftware.smackx.ox.callback.backup.SecretKeyBackupSelectionCallback;
import org.jivesoftware.smackx.ox.callback.backup.SecretKeyRestoreSelectionCallback; import org.jivesoftware.smackx.ox.callback.backup.SecretKeyRestoreSelectionCallback;
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException; import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException; import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
import org.jivesoftware.smackx.ox.exception.NoBackupFoundException; import org.jivesoftware.smackx.ox.exception.NoBackupFoundException;
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException; import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
import org.jivesoftware.smackx.ox.store.filebased.FileBasedOpenPgpStore;
import org.jivesoftware.smackx.ox.util.PubSubDelegate; import org.jivesoftware.smackx.ox.util.PubSubDelegate;
import org.jivesoftware.smackx.pubsub.PubSubException; import org.jivesoftware.smackx.pubsub.PubSubException;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.igniterealtime.smack.inttest.SmackIntegrationTest; import org.igniterealtime.smack.inttest.SmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment; import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
import org.igniterealtime.smack.inttest.TestNotPossibleException; import org.igniterealtime.smack.inttest.TestNotPossibleException;
@ -56,6 +59,7 @@ import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector; import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector;
public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegrationTest { public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegrationTest {
@ -90,24 +94,29 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
} }
@SmackIntegrationTest @SmackIntegrationTest
public void test() throws SmackOpenPgpException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, public void test() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
NoSuchProviderException, IOException, InterruptedException, PubSubException.NotALeafNodeException, NoSuchProviderException, IOException, InterruptedException, PubSubException.NotALeafNodeException,
SmackException.NoResponseException, SmackException.NotConnectedException, XMPPException.XMPPErrorException, SmackException.NoResponseException, SmackException.NotConnectedException, XMPPException.XMPPErrorException,
SmackException.NotLoggedInException, SmackException.FeatureNotSupportedException, SmackException.NotLoggedInException, SmackException.FeatureNotSupportedException,
MissingUserIdOnKeyException, NoBackupFoundException, InvalidBackupCodeException, PGPException { MissingUserIdOnKeyException, NoBackupFoundException, InvalidBackupCodeException, PGPException, MissingOpenPgpKeyPairException {
FileBasedPainlessOpenPgpStore beforeStore = new FileBasedPainlessOpenPgpStore(beforePath, new UnprotectedKeysProtector()); OpenPgpStore beforeStore = new FileBasedOpenPgpStore(beforePath);
PainlessOpenPgpProvider beforeProvider = new PainlessOpenPgpProvider(alice, beforeStore); beforeStore.setKeyRingProtector(new UnprotectedKeysProtector());
PainlessOpenPgpProvider beforeProvider = new PainlessOpenPgpProvider(beforeStore);
OpenPgpManager openPgpManager = OpenPgpManager.getInstanceFor(aliceConnection); OpenPgpManager openPgpManager = OpenPgpManager.getInstanceFor(aliceConnection);
openPgpManager.setOpenPgpProvider(beforeProvider); openPgpManager.setOpenPgpProvider(beforeProvider);
assertNull(beforeStore.getSigningKeyPairFingerprint()); OpenPgpSelf self = openPgpManager.getOpenPgpSelf();
assertNull(self.getSigningKeyFingerprint());
OpenPgpV4Fingerprint keyFingerprint = openPgpManager.generateAndImportKeyPair(alice); OpenPgpV4Fingerprint keyFingerprint = openPgpManager.generateAndImportKeyPair(alice);
beforeStore.setSigningKeyPairFingerprint(keyFingerprint); assertEquals(keyFingerprint, self.getSigningKeyFingerprint());
assertEquals(keyFingerprint, beforeStore.getSigningKeyPairFingerprint());
assertTrue(beforeStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint)); assertTrue(self.getSecretKeys().contains(keyFingerprint.getKeyId()));
PGPSecretKeyRing beforeKeys = beforeStore.getSecretKeyRing(alice, keyFingerprint);
assertNotNull(beforeKeys);
openPgpManager.backupSecretKeyToServer(new DisplayBackupCodeCallback() { openPgpManager.backupSecretKeyToServer(new DisplayBackupCodeCallback() {
@Override @Override
@ -121,12 +130,15 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
} }
}); });
FileBasedPainlessOpenPgpStore afterStore = new FileBasedPainlessOpenPgpStore(afterPath, new UnprotectedKeysProtector()); FileBasedOpenPgpStore afterStore = new FileBasedOpenPgpStore(afterPath);
PainlessOpenPgpProvider afterProvider = new PainlessOpenPgpProvider(alice, afterStore); afterStore.setKeyRingProtector(new UnprotectedKeysProtector());
PainlessOpenPgpProvider afterProvider = new PainlessOpenPgpProvider(afterStore);
openPgpManager.setOpenPgpProvider(afterProvider); openPgpManager.setOpenPgpProvider(afterProvider);
assertNull(afterStore.getSigningKeyPairFingerprint()); self = openPgpManager.getOpenPgpSelf();
assertFalse(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
assertNull(self.getSigningKeyFingerprint());
assertFalse(self.getSecretKeys().contains(keyFingerprint.getKeyId()));
OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(new AskForBackupCodeCallback() { OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(new AskForBackupCodeCallback() {
@Override @Override
@ -140,11 +152,12 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
} }
}); });
assertTrue(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint)); assertTrue(self.getSecretKeys().contains(keyFingerprint.getKeyId()));
afterStore.setSigningKeyPairFingerprint(fingerprint); assertEquals(keyFingerprint, self.getSigningKeyFingerprint());
assertEquals(keyFingerprint, afterStore.getSigningKeyPairFingerprint()); PGPSecretKeyRing afterKeys = afterStore.getSecretKeyRing(alice, keyFingerprint);
assertTrue(Arrays.equals(beforeStore.getSecretKeyRings(alice).getEncoded(), afterStore.getSecretKeyRings(alice).getEncoded())); assertNotNull(afterKeys);
assertTrue(Arrays.equals(beforeKeys.getEncoded(), afterKeys.getEncoded()));
} }
} }

View File

@ -18,6 +18,7 @@ package org.jivesoftware.smackx.ox;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -34,13 +35,14 @@ import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement; import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
import org.jivesoftware.smackx.hints.element.StoreHint; import org.jivesoftware.smackx.hints.element.StoreHint;
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
import org.jivesoftware.smackx.ox.element.SigncryptElement; import org.jivesoftware.smackx.ox.element.SigncryptElement;
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
import org.jivesoftware.smackx.ox.listener.OxMessageListener; import org.jivesoftware.smackx.ox.listener.OxMessageListener;
import org.jivesoftware.smackx.ox.listener.internal.SigncryptElementReceivedListener; import org.jivesoftware.smackx.ox.listener.internal.SigncryptElementReceivedListener;
import org.bouncycastle.openpgp.PGPException;
import org.jxmpp.jid.BareJid; import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.Jid;
/** /**
* Entry point of Smacks API for XEP-0374: OpenPGP for XMPP: Instant Messaging. * Entry point of Smacks API for XEP-0374: OpenPGP for XMPP: Instant Messaging.
@ -55,10 +57,12 @@ public final class OXInstantMessagingManager extends Manager implements Signcryp
private static final Map<XMPPConnection, OXInstantMessagingManager> INSTANCES = new WeakHashMap<>(); private static final Map<XMPPConnection, OXInstantMessagingManager> INSTANCES = new WeakHashMap<>();
private final Set<OxMessageListener> oxMessageListeners = new HashSet<>(); private final Set<OxMessageListener> oxMessageListeners = new HashSet<>();
private final OpenPgpManager openPgpManager;
private OXInstantMessagingManager(final XMPPConnection connection) { private OXInstantMessagingManager(final XMPPConnection connection) {
super(connection); super(connection);
OpenPgpManager.getInstanceFor(connection).registerSigncryptReceivedListener(this); openPgpManager = OpenPgpManager.getInstanceFor(connection);
openPgpManager.registerSigncryptReceivedListener(this);
announceSupportForOxInstantMessaging(); announceSupportForOxInstantMessaging();
} }
@ -153,15 +157,13 @@ public final class OXInstantMessagingManager extends Manager implements Signcryp
* @param contact contact capable of OpenPGP for XMPP: Instant Messaging. * @param contact contact capable of OpenPGP for XMPP: Instant Messaging.
* @param body message body. * @param body message body.
* @throws InterruptedException if the thread is interrupted * @throws InterruptedException if the thread is interrupted
* @throws MissingOpenPgpKeyPairException if we cannot access our signing key
* @throws IOException IO is dangerous * @throws IOException IO is dangerous
* @throws SmackException.NotConnectedException if we are not connected * @throws SmackException.NotConnectedException if we are not connected
* @throws SmackOpenPgpException in case of an OpenPGP error
* @throws SmackException.NotLoggedInException if we are not logged in * @throws SmackException.NotLoggedInException if we are not logged in
*/ */
public void sendOxMessage(OpenPgpContact contact, CharSequence body) public void sendOxMessage(OpenPgpContact contact, CharSequence body)
throws InterruptedException, MissingOpenPgpKeyPairException, IOException, throws InterruptedException, IOException,
SmackException.NotConnectedException, SmackOpenPgpException, SmackException.NotLoggedInException { SmackException.NotConnectedException, SmackException.NotLoggedInException, PGPException {
Message message = new Message(contact.getJid()); Message message = new Message(contact.getJid());
List<ExtensionElement> payload = new ArrayList<>(); List<ExtensionElement> payload = new ArrayList<>();
payload.add(new Message.Body(null, body.toString())); payload.add(new Message.Body(null, body.toString()));
@ -172,7 +174,12 @@ public final class OXInstantMessagingManager extends Manager implements Signcryp
StoreHint.set(message); StoreHint.set(message);
message.setBody("This message is encrypted using XEP-0374: OpenPGP for XMPP: Instant Messaging."); message.setBody("This message is encrypted using XEP-0374: OpenPGP for XMPP: Instant Messaging.");
//contact.addSignedEncryptedPayloadTo(message, payload); SigncryptElement signcryptElement = new SigncryptElement(Collections.<Jid>singleton(contact.jid), payload);
OpenPgpElement encrypted = openPgpManager.getProvider().signAndEncrypt(signcryptElement,
openPgpManager.getOpenPgpSelf(), Collections.singleton(contact));
message.addExtension(encrypted);
ChatManager.getInstanceFor(connection()).chatWith(contact.getJid().asEntityBareJidIfPossible()).send(message); ChatManager.getInstanceFor(connection()).chatWith(contact.getJid().asEntityBareJidIfPossible()).send(message);
} }

View File

@ -1,9 +1,29 @@
/**
*
* 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; package org.jivesoftware.smackx.ox;
import java.io.IOException; import java.io.IOException;
import java.util.Set; import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.jivesoftware.smackx.ox.selection_strategy.AnnouncedKeys;
import org.jivesoftware.smackx.ox.selection_strategy.BareJidUserId;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore; import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
@ -35,14 +55,25 @@ public class OpenPgpContact {
public PGPPublicKeyRingCollection getAnnouncedPublicKeys() throws IOException, PGPException { public PGPPublicKeyRingCollection getAnnouncedPublicKeys() throws IOException, PGPException {
PGPPublicKeyRingCollection anyKeys = getAnyPublicKeys(); PGPPublicKeyRingCollection anyKeys = getAnyPublicKeys();
Set<OpenPgpV4Fingerprint> announced = store.getAnnouncedFingerprintsOf(jid).keySet(); Map<OpenPgpV4Fingerprint, Date> announced = store.getAnnouncedFingerprintsOf(jid);
PGPPublicKeyRingCollection announcedKeysCollection = anyKeys; PGPPublicKeyRingCollection announcedKeysCollection = anyKeys;
BareJidUserId.PubRingSelectionStrategy userIdFilter = new BareJidUserId.PubRingSelectionStrategy();
AnnouncedKeys.PubKeyRingSelectionStrategy announcedFilter = new AnnouncedKeys.PubKeyRingSelectionStrategy();
for (PGPPublicKeyRing ring : anyKeys) { for (PGPPublicKeyRing ring : anyKeys) {
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(ring.getPublicKey()); if (!userIdFilter.accept(getJid(), ring)) {
LOGGER.log(Level.WARNING, "Ignore key " + Long.toHexString(ring.getPublicKey().getKeyID()) +
" as it lacks the user-id \"xmpp" + getJid().toString() + "\"");
announcedKeysCollection = PGPPublicKeyRingCollection.removePublicKeyRing(announcedKeysCollection, ring);
continue;
}
if (!announced.contains(fingerprint)) { if (!announcedFilter.accept(announced, ring)) {
LOGGER.log(Level.WARNING, "Ignore key " + Long.toHexString(ring.getPublicKey().getKeyID()) +
" as it is not announced by " + getJid().toString());
announcedKeysCollection = PGPPublicKeyRingCollection.removePublicKeyRing(announcedKeysCollection, ring); announcedKeysCollection = PGPPublicKeyRingCollection.removePublicKeyRing(announcedKeysCollection, ring);
} }
} }

View File

@ -18,6 +18,7 @@ package org.jivesoftware.smackx.ox;
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.PEP_NODE_PUBLIC_KEYS; import static org.jivesoftware.smackx.ox.util.PubSubDelegate.PEP_NODE_PUBLIC_KEYS;
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.PEP_NODE_PUBLIC_KEYS_NOTIFY; import static org.jivesoftware.smackx.ox.util.PubSubDelegate.PEP_NODE_PUBLIC_KEYS_NOTIFY;
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.publishPublicKey;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -50,16 +51,18 @@ import org.jivesoftware.smackx.ox.callback.backup.SecretKeyBackupSelectionCallba
import org.jivesoftware.smackx.ox.callback.backup.SecretKeyRestoreSelectionCallback; import org.jivesoftware.smackx.ox.callback.backup.SecretKeyRestoreSelectionCallback;
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider; import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
import org.jivesoftware.smackx.ox.element.CryptElement; import org.jivesoftware.smackx.ox.element.CryptElement;
import org.jivesoftware.smackx.ox.element.OpenPgpContentElement;
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
import org.jivesoftware.smackx.ox.element.PubkeyElement; import org.jivesoftware.smackx.ox.element.PubkeyElement;
import org.jivesoftware.smackx.ox.element.PublicKeysListElement; import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
import org.jivesoftware.smackx.ox.element.SecretkeyElement; import org.jivesoftware.smackx.ox.element.SecretkeyElement;
import org.jivesoftware.smackx.ox.element.SignElement; import org.jivesoftware.smackx.ox.element.SignElement;
import org.jivesoftware.smackx.ox.element.SigncryptElement; import org.jivesoftware.smackx.ox.element.SigncryptElement;
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException; import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException; import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException; import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
import org.jivesoftware.smackx.ox.exception.NoBackupFoundException; import org.jivesoftware.smackx.ox.exception.NoBackupFoundException;
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
import org.jivesoftware.smackx.ox.listener.internal.CryptElementReceivedListener; import org.jivesoftware.smackx.ox.listener.internal.CryptElementReceivedListener;
import org.jivesoftware.smackx.ox.listener.internal.SignElementReceivedListener; import org.jivesoftware.smackx.ox.listener.internal.SignElementReceivedListener;
import org.jivesoftware.smackx.ox.listener.internal.SigncryptElementReceivedListener; import org.jivesoftware.smackx.ox.listener.internal.SigncryptElementReceivedListener;
@ -75,10 +78,15 @@ import org.jivesoftware.smackx.pubsub.PubSubException;
import org.jivesoftware.smackx.pubsub.PubSubFeature; import org.jivesoftware.smackx.pubsub.PubSubFeature;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.jxmpp.jid.BareJid; import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityBareJid;
import org.pgpainless.pgpainless.PGPainless;
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
import org.xmlpull.v1.XmlPullParserException;
public final class OpenPgpManager extends Manager { public final class OpenPgpManager extends Manager {
@ -94,8 +102,6 @@ public final class OpenPgpManager extends Manager {
*/ */
private OpenPgpProvider provider; private OpenPgpProvider provider;
private OpenPgpStore store;
private final Map<BareJid, OpenPgpContact> openPgpCapableContacts = new HashMap<>(); private final Map<BareJid, OpenPgpContact> openPgpCapableContacts = new HashMap<>();
private final Set<SigncryptElementReceivedListener> signcryptElementReceivedListeners = new HashSet<>(); private final Set<SigncryptElementReceivedListener> signcryptElementReceivedListeners = new HashSet<>();
@ -144,6 +150,10 @@ public final class OpenPgpManager extends Manager {
this.provider = provider; this.provider = provider;
} }
OpenPgpProvider getProvider() {
return provider;
}
/** /**
* Get our OpenPGP self. * Get our OpenPGP self.
* *
@ -151,8 +161,10 @@ public final class OpenPgpManager extends Manager {
* @throws SmackException.NotLoggedInException if we are not logged in * @throws SmackException.NotLoggedInException if we are not logged in
*/ */
public OpenPgpSelf getOpenPgpSelf() throws SmackException.NotLoggedInException { public OpenPgpSelf getOpenPgpSelf() throws SmackException.NotLoggedInException {
throwIfNoProviderSet();
if (self == null) { if (self == null) {
self = new OpenPgpSelf(getJidOrThrow(), store); self = new OpenPgpSelf(getJidOrThrow(), provider.getStore());
} }
return self; return self;
@ -165,7 +177,6 @@ public final class OpenPgpManager extends Manager {
* *
* @throws NoSuchAlgorithmException if we are missing an algorithm to generate a fresh key pair. * @throws NoSuchAlgorithmException if we are missing an algorithm to generate a fresh key pair.
* @throws NoSuchProviderException if we are missing a suitable {@link java.security.Provider}. * @throws NoSuchProviderException if we are missing a suitable {@link java.security.Provider}.
* @throws SmackOpenPgpException if something bad happens during key generation/loading.
* @throws InterruptedException if the thread gets interrupted. * @throws InterruptedException if the thread gets interrupted.
* @throws PubSubException.NotALeafNodeException if one of the PubSub nodes is not a {@link LeafNode}. * @throws PubSubException.NotALeafNodeException if one of the PubSub nodes is not a {@link LeafNode}.
* @throws XMPPException.XMPPErrorException in case of an XMPP protocol error. * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error.
@ -174,33 +185,32 @@ public final class OpenPgpManager extends Manager {
* @throws IOException IO is dangerous. * @throws IOException IO is dangerous.
* @throws InvalidAlgorithmParameterException if illegal algorithm parameters are used for key generation. * @throws InvalidAlgorithmParameterException if illegal algorithm parameters are used for key generation.
* @throws SmackException.NotLoggedInException if we are not logged in. * @throws SmackException.NotLoggedInException if we are not logged in.
* @throws PGPException if something goes wrong during key loading/generating
*/ */
public void announceSupportAndPublish() public void announceSupportAndPublish()
throws NoSuchAlgorithmException, NoSuchProviderException, SmackOpenPgpException, throws NoSuchAlgorithmException, NoSuchProviderException, InterruptedException,
InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
SmackException.NotConnectedException, SmackException.NoResponseException, IOException, SmackException.NotConnectedException, SmackException.NoResponseException, IOException,
InvalidAlgorithmParameterException, SmackException.NotLoggedInException { InvalidAlgorithmParameterException, SmackException.NotLoggedInException, PGPException {
throwIfNoProviderSet(); throwIfNoProviderSet();
throwIfNotAuthenticated(); throwIfNotAuthenticated();
BareJid ourJid = connection().getUser().asBareJid(); OpenPgpV4Fingerprint primaryFingerprint = getOurFingerprint();
// OpenPgpV4Fingerprint primaryFingerprint = getOurFingerprint(); if (primaryFingerprint == null) {
primaryFingerprint = generateAndImportKeyPair(getJidOrThrow());
// if (primaryFingerprint == null) { }
// primaryFingerprint = generateAndImportKeyPair(ourJid);
// }
// Create <pubkey/> element // Create <pubkey/> element
PubkeyElement pubkeyElement; PubkeyElement pubkeyElement;
// try { try {
// pubkeyElement = createPubkeyElement(ourJid, primaryFingerprint, new Date()); pubkeyElement = createPubkeyElement(getJidOrThrow(), primaryFingerprint, new Date());
// } catch (MissingOpenPgpPublicKeyException e) { } catch (MissingOpenPgpPublicKeyException e) {
// throw new AssertionError("Cannot publish our public key, since it is missing (MUST NOT happen!)"); throw new AssertionError("Cannot publish our public key, since it is missing (MUST NOT happen!)");
// } }
// publish it // publish it
// publishPublicKey(connection(), pubkeyElement, primaryFingerprint); publishPublicKey(connection(), pubkeyElement, primaryFingerprint);
// Subscribe to public key changes // Subscribe to public key changes
// PEPManager.getInstanceFor(connection()).addPEPListener(metadataListener); // PEPManager.getInstanceFor(connection()).addPEPListener(metadataListener);
@ -216,19 +226,20 @@ public final class OpenPgpManager extends Manager {
* @throws NoSuchAlgorithmException if the JVM doesn't support one of the used algorithms. * @throws NoSuchAlgorithmException if the JVM doesn't support one of the used algorithms.
* @throws InvalidAlgorithmParameterException if the used algorithm parameters are invalid. * @throws InvalidAlgorithmParameterException if the used algorithm parameters are invalid.
* @throws NoSuchProviderException if we are missing a cryptographic provider. * @throws NoSuchProviderException if we are missing a cryptographic provider.
* @throws SmackOpenPgpException in case of an OpenPGP error.
*/ */
public OpenPgpV4Fingerprint generateAndImportKeyPair(BareJid ourJid) public OpenPgpV4Fingerprint generateAndImportKeyPair(BareJid ourJid)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException, throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException,
SmackOpenPgpException, PGPException { PGPException, IOException {
throwIfNoProviderSet();
OpenPgpStore store = provider.getStore();
PGPSecretKeyRing keyPair = store.generateKeyRing(ourJid); PGPSecretKeyRing keyPair = store.generateKeyRing(ourJid);
// try { try {
// provider.importSecretKey(ourJid, keyPair); store.importSecretKey(ourJid, keyPair);
// } catch (MissingUserIdOnKeyException e) { } catch (MissingUserIdOnKeyException e) {
// This should never throw, since we set our jid literally one line above this comment. // This should never throw, since we set our jid literally one line above this comment.
// throw new AssertionError(e); throw new AssertionError(e);
// } }
return new OpenPgpV4Fingerprint(keyPair); return new OpenPgpV4Fingerprint(keyPair);
} }
@ -251,7 +262,8 @@ public final class OpenPgpManager extends Manager {
* @return {@link OpenPgpContact}. * @return {@link OpenPgpContact}.
*/ */
public OpenPgpContact getOpenPgpContact(EntityBareJid jid) { public OpenPgpContact getOpenPgpContact(EntityBareJid jid) {
return store.getOpenPgpContact(jid); throwIfNoProviderSet();
return provider.getStore().getOpenPgpContact(jid);
} }
@ -288,7 +300,6 @@ public final class OpenPgpManager extends Manager {
* @throws SmackException.NotConnectedException if we are not connected. * @throws SmackException.NotConnectedException if we are not connected.
* @throws SmackException.NoResponseException if the server doesn't respond. * @throws SmackException.NoResponseException if the server doesn't respond.
* @throws SmackException.NotLoggedInException if we are not logged in. * @throws SmackException.NotLoggedInException if we are not logged in.
* @throws SmackOpenPgpException in case of an OpenPGP exception.
* @throws IOException IO is dangerous. * @throws IOException IO is dangerous.
* @throws SmackException.FeatureNotSupportedException if the server doesn't support the PubSub whitelist access model. * @throws SmackException.FeatureNotSupportedException if the server doesn't support the PubSub whitelist access model.
*/ */
@ -296,21 +307,28 @@ public final class OpenPgpManager extends Manager {
SecretKeyBackupSelectionCallback selectKeyCallback) SecretKeyBackupSelectionCallback selectKeyCallback)
throws InterruptedException, PubSubException.NotALeafNodeException, throws InterruptedException, PubSubException.NotALeafNodeException,
XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException,
SmackException.NotLoggedInException, SmackOpenPgpException, IOException, SmackException.NotLoggedInException, IOException,
SmackException.FeatureNotSupportedException { SmackException.FeatureNotSupportedException, PGPException, MissingOpenPgpKeyPairException {
throwIfNoProviderSet(); throwIfNoProviderSet();
throwIfNotAuthenticated(); throwIfNotAuthenticated();
BareJid ownJid = connection().getUser().asBareJid(); BareJid ownJid = connection().getUser().asBareJid();
String backupCode = SecretKeyBackupHelper.generateBackupPassword(); String backupCode = SecretKeyBackupHelper.generateBackupPassword();
// Set<OpenPgpV4Fingerprint> availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(ownJid);
// Set<OpenPgpV4Fingerprint> selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs);
// SecretkeyElement secretKey = SecretKeyBackupHelper.createSecretkeyElement(provider, ownJid, selectedKeyPairs, backupCode); PGPSecretKeyRingCollection secretKeyRings = provider.getStore().getSecretKeysOf(ownJid);
// PubSubDelegate.depositSecretKey(connection(), secretKey); Set<OpenPgpV4Fingerprint> availableKeyPairs = new HashSet<>();
// displayCodeCallback.displayBackupCode(backupCode); for (PGPSecretKeyRing ring : secretKeyRings) {
availableKeyPairs.add(new OpenPgpV4Fingerprint(ring));
}
Set<OpenPgpV4Fingerprint> selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs);
SecretkeyElement secretKey = SecretKeyBackupHelper.createSecretkeyElement(provider, ownJid, selectedKeyPairs, backupCode);
PubSubDelegate.depositSecretKey(connection(), secretKey);
displayCodeCallback.displayBackupCode(backupCode);
} }
/** /**
@ -342,7 +360,6 @@ public final class OpenPgpManager extends Manager {
* @throws XMPPException.XMPPErrorException in case of an XMPP protocol error. * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error.
* @throws SmackException.NotConnectedException if we are not connected. * @throws SmackException.NotConnectedException if we are not connected.
* @throws SmackException.NoResponseException if the server doesn't respond. * @throws SmackException.NoResponseException if the server doesn't respond.
* @throws SmackOpenPgpException if something goes wrong while restoring the secret key.
* @throws InvalidBackupCodeException if the user-provided backup code is invalid. * @throws InvalidBackupCodeException if the user-provided backup code is invalid.
* @throws SmackException.NotLoggedInException if we are not logged in * @throws SmackException.NotLoggedInException if we are not logged in
* @throws IOException IO is dangerous * @throws IOException IO is dangerous
@ -350,11 +367,11 @@ public final class OpenPgpManager extends Manager {
* @throws NoBackupFoundException if no secret key backup has been found * @throws NoBackupFoundException if no secret key backup has been found
*/ */
public OpenPgpV4Fingerprint restoreSecretKeyServerBackup(AskForBackupCodeCallback codeCallback, public OpenPgpV4Fingerprint restoreSecretKeyServerBackup(AskForBackupCodeCallback codeCallback,
SecretKeyRestoreSelectionCallback selectionCallback) SecretKeyRestoreSelectionCallback selectionCallback)
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
SmackException.NotConnectedException, SmackException.NoResponseException, SmackOpenPgpException, SmackException.NotConnectedException, SmackException.NoResponseException,
InvalidBackupCodeException, SmackException.NotLoggedInException, IOException, MissingUserIdOnKeyException, InvalidBackupCodeException, SmackException.NotLoggedInException, IOException, MissingUserIdOnKeyException,
NoBackupFoundException { NoBackupFoundException, PGPException {
throwIfNoProviderSet(); throwIfNoProviderSet();
throwIfNotAuthenticated(); throwIfNotAuthenticated();
SecretkeyElement backup = PubSubDelegate.fetchSecretKey(connection()); SecretkeyElement backup = PubSubDelegate.fetchSecretKey(connection());
@ -364,8 +381,9 @@ public final class OpenPgpManager extends Manager {
String backupCode = codeCallback.askForBackupCode(); String backupCode = codeCallback.askForBackupCode();
OpenPgpV4Fingerprint fingerprint = SecretKeyBackupHelper.restoreSecretKeyBackup(provider, backup, backupCode); PGPSecretKeyRing key = SecretKeyBackupHelper.restoreSecretKeyBackup(backup, backupCode);
return fingerprint; provider.getStore().importSecretKey(getJidOrThrow(), key);
return new OpenPgpV4Fingerprint(key);
} }
/** /**
@ -394,21 +412,24 @@ public final class OpenPgpManager extends Manager {
}; };
private void processPublicKeysListElement(BareJid contact, PublicKeysListElement listElement) { private void processPublicKeysListElement(BareJid contact, PublicKeysListElement listElement) {
/*
OpenPgpContact openPgpContact = getOpenPgpContact(contact.asEntityBareJidIfPossible());
try { try {
openPgpContact.updateKeys(listElement); PGPPublicKeyRingCollection contactsKeys = provider.getStore().getPublicKeysOf(contact);
} catch (SmackOpenPgpException e) { for (OpenPgpV4Fingerprint fingerprint : listElement.getMetadata().keySet()) {
LOGGER.log(Level.WARNING, "Could not read key ring of contact " + contact, e); PGPPublicKeyRing key = contactsKeys.getPublicKeyRing(fingerprint.getKeyId());
if (key == null) {
}
}
} catch (PGPException | IOException e) {
LOGGER.log(Level.WARNING, "Could not read public keys of " + contact, e);
} }
*/
} }
private final IncomingChatMessageListener incomingOpenPgpMessageListener = private final IncomingChatMessageListener incomingOpenPgpMessageListener =
new IncomingChatMessageListener() { new IncomingChatMessageListener() {
@Override @Override
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) { public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
/*
OpenPgpElement element = message.getExtension(OpenPgpElement.ELEMENT, OpenPgpElement.NAMESPACE); OpenPgpElement element = message.getExtension(OpenPgpElement.ELEMENT, OpenPgpElement.NAMESPACE);
if (element == null) { if (element == null) {
// Message does not contain an OpenPgpElement -> discard // Message does not contain an OpenPgpElement -> discard
@ -419,13 +440,11 @@ public final class OpenPgpManager extends Manager {
OpenPgpContentElement contentElement = null; OpenPgpContentElement contentElement = null;
try { try {
contentElement = contact.receive(element); contentElement = provider.decryptAndOrVerify(element, self, contact).getOpenPgpContentElement();
} catch (SmackOpenPgpException e) { } catch (PGPException e) {
LOGGER.log(Level.WARNING, "Could not decrypt incoming OpenPGP encrypted message", e); LOGGER.log(Level.WARNING, "Could not decrypt incoming OpenPGP encrypted message", e);
} catch (XmlPullParserException | IOException e) { } catch (XmlPullParserException | IOException e) {
LOGGER.log(Level.WARNING, "Invalid XML content of incoming OpenPGP encrypted message", e); LOGGER.log(Level.WARNING, "Invalid XML content of incoming OpenPGP encrypted message", e);
} catch (MissingOpenPgpKeyPairException e) {
LOGGER.log(Level.WARNING, "Could not decrypt incoming OpenPGP encrypted message due to missing secret key", e);
} }
if (contentElement instanceof SigncryptElement) { if (contentElement instanceof SigncryptElement) {
@ -452,7 +471,6 @@ public final class OpenPgpManager extends Manager {
else { else {
throw new AssertionError("Invalid element received: " + contentElement.getClass().getName()); throw new AssertionError("Invalid element received: " + contentElement.getClass().getName());
} }
*/
} }
}; };
@ -468,12 +486,12 @@ public final class OpenPgpManager extends Manager {
* @throws MissingUserIdOnKeyException if the key does not have an OpenPGP user-id of the form * @throws MissingUserIdOnKeyException if the key does not have an OpenPGP user-id of the form
* "xmpp:juliet@capulet.lit" with the owners {@link BareJid} * "xmpp:juliet@capulet.lit" with the owners {@link BareJid}
* @throws IOException row, row, row your byte gently down the {@link InputStream} * @throws IOException row, row, row your byte gently down the {@link InputStream}
* @throws SmackOpenPgpException if the key cannot be deserialized
*/ */
private void processPublicKey(PubkeyElement pubkeyElement, BareJid owner) private void processPublicKey(PubkeyElement pubkeyElement, BareJid owner)
throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException { throws MissingUserIdOnKeyException, IOException, PGPException {
byte[] base64 = pubkeyElement.getDataElement().getB64Data(); byte[] base64 = pubkeyElement.getDataElement().getB64Data();
// provider.importPublicKey(owner, Base64.decode(base64)); PGPPublicKeyRing keyRing = PGPainless.readKeyRing().publicKeyRing(Base64.decode(base64));
provider.getStore().importPublicKey(owner, keyRing);
} }
/** /**
@ -490,10 +508,16 @@ public final class OpenPgpManager extends Manager {
private PubkeyElement createPubkeyElement(BareJid owner, private PubkeyElement createPubkeyElement(BareJid owner,
OpenPgpV4Fingerprint fingerprint, OpenPgpV4Fingerprint fingerprint,
Date date) Date date)
throws MissingOpenPgpPublicKeyException { throws MissingOpenPgpPublicKeyException, IOException, PGPException {
// byte[] keyBytes = provider.getStore().getPublicKeyRingBytes(owner, fingerprint); PGPPublicKeyRingCollection publicKeyRingCollection = provider.getStore().getPublicKeysOf(owner);
// return createPubkeyElement(keyBytes, date); if (publicKeyRingCollection != null) {
return null; PGPPublicKeyRing keys = publicKeyRingCollection.getPublicKeyRing(fingerprint.getKeyId());
if (keys != null) {
byte[] keyBytes = keys.getEncoded(true);
return createPubkeyElement(keyBytes, date);
}
}
throw new MissingOpenPgpPublicKeyException(owner, fingerprint);
} }
/** /**

View File

@ -1,3 +1,19 @@
/**
*
* 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; package org.jivesoftware.smackx.ox;
import java.io.IOException; import java.io.IOException;

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,11 +26,14 @@ import org.jivesoftware.smackx.ox.element.CryptElement;
import org.jivesoftware.smackx.ox.element.OpenPgpElement; import org.jivesoftware.smackx.ox.element.OpenPgpElement;
import org.jivesoftware.smackx.ox.element.SignElement; import org.jivesoftware.smackx.ox.element.SignElement;
import org.jivesoftware.smackx.ox.element.SigncryptElement; import org.jivesoftware.smackx.ox.element.SigncryptElement;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
public interface OpenPgpProvider { public interface OpenPgpProvider {
OpenPgpStore getStore();
OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients) OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients)
throws IOException, PGPException; throws IOException, PGPException;

View File

@ -1,3 +1,19 @@
/**
*
* 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.crypto; package org.jivesoftware.smackx.ox.crypto;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -14,6 +30,7 @@ import org.jivesoftware.smackx.ox.element.CryptElement;
import org.jivesoftware.smackx.ox.element.OpenPgpElement; import org.jivesoftware.smackx.ox.element.OpenPgpElement;
import org.jivesoftware.smackx.ox.element.SignElement; import org.jivesoftware.smackx.ox.element.SignElement;
import org.jivesoftware.smackx.ox.element.SigncryptElement; import org.jivesoftware.smackx.ox.element.SigncryptElement;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
@ -25,6 +42,17 @@ import org.pgpainless.pgpainless.encryption_signing.EncryptionStream;
public class PainlessOpenPgpProvider implements OpenPgpProvider { public class PainlessOpenPgpProvider implements OpenPgpProvider {
private final OpenPgpStore store;
public PainlessOpenPgpProvider(OpenPgpStore store) {
this.store = store;
}
@Override
public OpenPgpStore getStore() {
return store;
}
@Override @Override
public OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients) public OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients)
throws IOException, PGPException { throws IOException, PGPException {

View File

@ -1,30 +0,0 @@
/**
*
* 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.exception;
public class SmackOpenPgpException extends Exception {
private static final long serialVersionUID = 1L;
public SmackOpenPgpException(Throwable cause) {
super(cause);
}
public SmackOpenPgpException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,62 @@
/**
*
* 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.selection_strategy;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy;
import org.pgpainless.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy;
public class AnnouncedKeys {
public static class PubKeyRingSelectionStrategy extends PublicKeyRingSelectionStrategy<Map<OpenPgpV4Fingerprint, Date>> {
private static final Logger LOGGER = Logger.getLogger(PubKeyRingSelectionStrategy.class.getName());
@Override
public boolean accept(Map<OpenPgpV4Fingerprint, Date> announcedKeys, PGPPublicKeyRing publicKeys) {
try {
return announcedKeys.keySet().contains(new OpenPgpV4Fingerprint(publicKeys));
} catch (PGPException e) {
LOGGER.log(Level.WARNING, "Key might be damaged.", e);
return false;
}
}
}
public static class SecKeyRingSelectionStrategy extends SecretKeyRingSelectionStrategy<Map<OpenPgpV4Fingerprint, Date>> {
private static final Logger LOGGER = Logger.getLogger(SecKeyRingSelectionStrategy.class.getName());
@Override
public boolean accept(Map<OpenPgpV4Fingerprint, Date> announcedKeys, PGPSecretKeyRing secretKeys) {
try {
return announcedKeys.keySet().contains(new OpenPgpV4Fingerprint(secretKeys));
} catch (PGPException e) {
LOGGER.log(Level.WARNING, "Key might be damaged.", e);
return false;
}
}
}
}

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,11 @@ import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
import org.jivesoftware.smackx.ox.selection_strategy.BareJidUserId;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpKeyStore; import org.jivesoftware.smackx.ox.store.definition.OpenPgpKeyStore;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
@ -37,12 +41,10 @@ import org.pgpainless.pgpainless.key.generation.type.length.RsaLength;
public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore { public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore {
public AbstractOpenPgpKeyStore() { private static final Logger LOGGER = Logger.getLogger(AbstractOpenPgpKeyStore.class.getName());
} protected Map<BareJid, PGPPublicKeyRingCollection> publicKeyRingCollections = new HashMap<>();
protected Map<BareJid, PGPSecretKeyRingCollection> secretKeyRingCollections = new HashMap<>();
protected Map<BareJid, PGPPublicKeyRingCollection> publicKeys = new HashMap<>();
protected Map<BareJid, PGPSecretKeyRingCollection> secretKeys = new HashMap<>();
protected abstract PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner) throws IOException, PGPException; protected abstract PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner) throws IOException, PGPException;
@ -54,11 +56,11 @@ public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore {
@Override @Override
public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException { public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException {
PGPPublicKeyRingCollection keys = publicKeys.get(owner); PGPPublicKeyRingCollection keys = publicKeyRingCollections.get(owner);
if (keys == null) { if (keys == null) {
keys = readPublicKeysOf(owner); keys = readPublicKeysOf(owner);
if (keys != null) { if (keys != null) {
publicKeys.put(owner, keys); publicKeyRingCollections.put(owner, keys);
} }
} }
return keys; return keys;
@ -66,16 +68,53 @@ public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore {
@Override @Override
public PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException { public PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException {
PGPSecretKeyRingCollection keys = secretKeys.get(owner); PGPSecretKeyRingCollection keys = secretKeyRingCollections.get(owner);
if (keys == null) { if (keys == null) {
keys = readSecretKeysOf(owner); keys = readSecretKeysOf(owner);
if (keys != null) { if (keys != null) {
secretKeys.put(owner, keys); secretKeyRingCollections.put(owner, keys);
} }
} }
return keys; return keys;
} }
@Override
public void importSecretKey(BareJid owner, PGPSecretKeyRing secretKeys)
throws IOException, PGPException, MissingUserIdOnKeyException {
if (!new BareJidUserId.SecRingSelectionStrategy().accept(owner, secretKeys)) {
throw new MissingUserIdOnKeyException(owner, secretKeys.getPublicKey().getKeyID());
}
PGPSecretKeyRingCollection secretKeyRings = getSecretKeysOf(owner);
try {
secretKeyRings = PGPSecretKeyRingCollection.addSecretKeyRing(secretKeyRings, secretKeys);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.INFO, "Skipping secret key ring " + Long.toHexString(secretKeys.getPublicKey().getKeyID()) +
" as it is already in the key ring of " + owner.toString());
}
this.secretKeyRingCollections.put(owner, secretKeyRings);
writeSecretKeysOf(owner, secretKeyRings);
}
@Override
public void importPublicKey(BareJid owner, PGPPublicKeyRing publicKeys) throws IOException, PGPException, MissingUserIdOnKeyException {
if (!new BareJidUserId.PubRingSelectionStrategy().accept(owner, publicKeys)) {
throw new MissingUserIdOnKeyException(owner, publicKeys.getPublicKey().getKeyID());
}
PGPPublicKeyRingCollection publicKeyRings = getPublicKeysOf(owner);
try {
publicKeyRings = PGPPublicKeyRingCollection.addPublicKeyRing(publicKeyRings, publicKeys);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.INFO, "Skipping public key ring " + Long.toHexString(publicKeys.getPublicKey().getKeyID()) +
" as it is already in the key ring of " + owner.toString());
}
this.publicKeyRingCollections.put(owner, publicKeyRings);
writePublicKeysOf(owner, publicKeyRings);
}
@Override @Override
public PGPPublicKeyRing getPublicKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException { public PGPPublicKeyRing getPublicKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException {
PGPPublicKeyRingCollection publicKeyRings = getPublicKeysOf(owner); PGPPublicKeyRingCollection publicKeyRings = getPublicKeysOf(owner);

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import java.util.Observable;
import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smackx.ox.OpenPgpContact; import org.jivesoftware.smackx.ox.OpenPgpContact;
import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback; import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback;
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpKeyStore; import org.jivesoftware.smackx.ox.store.definition.OpenPgpKeyStore;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpMetadataStore; import org.jivesoftware.smackx.ox.store.definition.OpenPgpMetadataStore;
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore; import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
@ -115,6 +116,16 @@ public abstract class AbstractOpenPgpStore extends Observable implements OpenPgp
return keyStore.generateKeyRing(owner); return keyStore.generateKeyRing(owner);
} }
@Override
public void importSecretKey(BareJid owner, PGPSecretKeyRing secretKeys) throws IOException, PGPException, MissingUserIdOnKeyException {
keyStore.importSecretKey(owner, secretKeys);
}
@Override
public void importPublicKey(BareJid owner, PGPPublicKeyRing publicKeys) throws IOException, PGPException, MissingUserIdOnKeyException {
keyStore.importPublicKey(owner, publicKeys);
}
/* /*
OpenPgpMetadataStore OpenPgpMetadataStore
*/ */

View File

@ -1,3 +1,19 @@
/**
*
* 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.store.abstr; package org.jivesoftware.smackx.ox.store.abstr;
import java.io.IOException; import java.io.IOException;

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,6 +21,8 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
@ -42,4 +44,8 @@ public interface OpenPgpKeyStore {
PGPSecretKeyRing getSecretKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException; PGPSecretKeyRing getSecretKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException;
PGPSecretKeyRing generateKeyRing(BareJid owner) throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException; PGPSecretKeyRing generateKeyRing(BareJid owner) throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException;
void importSecretKey(BareJid owner, PGPSecretKeyRing secretKeys) throws IOException, PGPException, MissingUserIdOnKeyException;
void importPublicKey(BareJid owner, PGPPublicKeyRing publicKeys) throws IOException, PGPException, MissingUserIdOnKeyException;
} }

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,3 +1,19 @@
/**
*
* 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.store.definition; package org.jivesoftware.smackx.ox.store.definition;
import org.jivesoftware.smackx.ox.OpenPgpContact; import org.jivesoftware.smackx.ox.OpenPgpContact;

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2017 Florian Schmaus, 2018 Paul Schaub. * Copyright 2018 Paul Schaub.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -468,7 +468,8 @@ public class PubSubDelegate {
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException |
NoSuchFieldException e) { NoSuchFieldException e) {
throw new AssertionError("Using reflections to create a LeafNode and put it into PubSubManagers nodeMap failed.", e); LOGGER.log(Level.SEVERE, "Using reflections to create a LeafNode and put it into PubSubManagers nodeMap failed.", e);
throw new AssertionError(e);
} }
} }
} }

View File

@ -16,17 +16,22 @@
*/ */
package org.jivesoftware.smackx.ox.util; package org.jivesoftware.smackx.ox.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Set; import java.util.Set;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider; import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
import org.jivesoftware.smackx.ox.element.SecretkeyElement; import org.jivesoftware.smackx.ox.element.SecretkeyElement;
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException; import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException; import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.jxmpp.jid.BareJid; import org.jxmpp.jid.BareJid;
import org.pgpainless.pgpainless.PGPainless;
import org.pgpainless.pgpainless.algorithm.SymmetricKeyAlgorithm;
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
public class SecretKeyBackupHelper { public class SecretKeyBackupHelper {
@ -62,45 +67,41 @@ public class SecretKeyBackupHelper {
public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider, public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider,
BareJid owner, BareJid owner,
Set<OpenPgpV4Fingerprint> fingerprints, Set<OpenPgpV4Fingerprint> fingerprints,
String backupCode) throws SmackOpenPgpException, IOException { String backupCode) throws PGPException, IOException, MissingOpenPgpKeyPairException {
/*
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream();
for (OpenPgpV4Fingerprint fingerprint : fingerprints) { for (OpenPgpV4Fingerprint fingerprint : fingerprints) {
try {
byte[] bytes = provider.getStore().getSecretKeyRingBytes(owner, fingerprint); PGPSecretKeyRing key = provider.getStore().getSecretKeyRing(owner, fingerprint);
if (key == null) {
throw new MissingOpenPgpKeyPairException(owner, fingerprint);
}
byte[] bytes = key.getEncoded();
buffer.write(bytes); buffer.write(bytes);
} catch (MissingOpenPgpKeyPairException | IOException e) {
throw new SmackOpenPgpException("Cannot backup secret key " + Long.toHexString(fingerprint.getKeyId()) + ".", e);
}
} }
return createSecretkeyElement(provider, buffer.toByteArray(), backupCode); return createSecretkeyElement(provider, buffer.toByteArray(), backupCode);
*/
return null;
} }
public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider, public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider,
byte[] keys, byte[] keys,
String backupCode) String backupCode)
throws SmackOpenPgpException, IOException { throws PGPException, IOException {
// byte[] encrypted = provider.symmetricallyEncryptWithPassword(keys, backupCode); byte[] encrypted = PGPainless.encryptWithPassword(keys, backupCode.toCharArray(), SymmetricKeyAlgorithm.AES_256);
// return new SecretkeyElement(Base64.encode(encrypted)); return new SecretkeyElement(Base64.encode(encrypted));
return null;
} }
public static OpenPgpV4Fingerprint restoreSecretKeyBackup(OpenPgpProvider provider, SecretkeyElement backup, String backupCode) public static PGPSecretKeyRing restoreSecretKeyBackup(SecretkeyElement backup, String backupCode)
throws InvalidBackupCodeException, IOException, MissingUserIdOnKeyException, SmackOpenPgpException { throws InvalidBackupCodeException, IOException, PGPException {
/*
byte[] encrypted = Base64.decode(backup.getB64Data()); byte[] encrypted = Base64.decode(backup.getB64Data());
byte[] decrypted; byte[] decrypted;
try { try {
decrypted = provider.symmetricallyDecryptWithPassword(encrypted, backupCode); decrypted = PGPainless.decryptWithPassword(encrypted, backupCode.toCharArray());
} catch (IOException | SmackOpenPgpException e) { } catch (IOException | PGPException e) {
throw new InvalidBackupCodeException("Could not decrypt secret key backup. Possibly wrong passphrase?", e); throw new InvalidBackupCodeException("Could not decrypt secret key backup. Possibly wrong passphrase?", e);
} }
return provider.importSecretKey(decrypted); return PGPainless.readKeyRing().secretKeyRing(decrypted);
*/
return null;
} }
} }