mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 20:42:06 +01:00
Temp
This commit is contained in:
parent
06dbb37a0e
commit
8e4013fff3
25 changed files with 422 additions and 185 deletions
|
@ -16,8 +16,6 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.openpgp;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
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.OpenPgpContact;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||
import org.jivesoftware.smackx.ox.bouncycastle.FileBasedPainlessOpenPgpStore;
|
||||
import org.jivesoftware.smackx.ox.bouncycastle.PainlessOpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
import org.jivesoftware.smackx.ox.listener.OxMessageListener;
|
||||
import org.jivesoftware.smackx.ox.store.filebased.FileBasedOpenPgpStore;
|
||||
import org.jivesoftware.smackx.ox.util.PubSubDelegate;
|
||||
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
|
@ -43,6 +40,7 @@ import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint;
|
|||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector;
|
||||
|
||||
public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgpIntegrationTest {
|
||||
|
@ -75,11 +73,13 @@ public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgp
|
|||
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!!!";
|
||||
|
||||
FileBasedPainlessOpenPgpStore aliceStore = new FileBasedPainlessOpenPgpStore(aliceStorePath, new UnprotectedKeysProtector());
|
||||
FileBasedPainlessOpenPgpStore bobStore = new FileBasedPainlessOpenPgpStore(bobStorePath, new UnprotectedKeysProtector());
|
||||
FileBasedOpenPgpStore aliceStore = new FileBasedOpenPgpStore(aliceStorePath);
|
||||
aliceStore.setKeyRingProtector(new UnprotectedKeysProtector());
|
||||
FileBasedOpenPgpStore bobStore = new FileBasedOpenPgpStore(bobStorePath);
|
||||
bobStore.setKeyRingProtector(new UnprotectedKeysProtector());
|
||||
|
||||
PainlessOpenPgpProvider aliceProvider = new PainlessOpenPgpProvider(alice, aliceStore);
|
||||
PainlessOpenPgpProvider bobProvider = new PainlessOpenPgpProvider(bob, bobStore);
|
||||
PainlessOpenPgpProvider aliceProvider = new PainlessOpenPgpProvider(aliceStore);
|
||||
PainlessOpenPgpProvider bobProvider = new PainlessOpenPgpProvider(bobStore);
|
||||
|
||||
OpenPgpManager aliceOpenPgp = OpenPgpManager.getInstanceFor(aliceConnection);
|
||||
OpenPgpManager bobOpenPgp = OpenPgpManager.getInstanceFor(bobConnection);
|
||||
|
@ -104,20 +104,13 @@ public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgp
|
|||
aliceFingerprint = aliceOpenPgp.generateAndImportKeyPair(alice);
|
||||
bobFingerprint = bobOpenPgp.generateAndImportKeyPair(bob);
|
||||
|
||||
aliceStore.setSigningKeyPairFingerprint(aliceFingerprint);
|
||||
bobStore.setSigningKeyPairFingerprint(bobFingerprint);
|
||||
|
||||
aliceOpenPgp.announceSupportAndPublish();
|
||||
bobOpenPgp.announceSupportAndPublish();
|
||||
|
||||
OpenPgpContact bobForAlice = aliceOpenPgp.getOpenPgpContact(bob.asEntityBareJidIfPossible());
|
||||
OpenPgpContact aliceForBob = bobOpenPgp.getOpenPgpContact(alice.asEntityBareJidIfPossible());
|
||||
|
||||
bobForAlice.updateKeys();
|
||||
aliceForBob.updateKeys();
|
||||
|
||||
assertTrue(bobForAlice.getActiveKeys().contains(bobFingerprint));
|
||||
assertTrue(aliceForBob.getActiveKeys().contains(aliceFingerprint));
|
||||
// TODO: Update keys
|
||||
|
||||
aliceInstantMessaging.sendOxMessage(bobForAlice, body);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.jivesoftware.smackx.openpgp;
|
|||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
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.StringUtils;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||
import org.jivesoftware.smackx.ox.bouncycastle.FileBasedPainlessOpenPgpStore;
|
||||
import org.jivesoftware.smackx.ox.bouncycastle.PainlessOpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpSelf;
|
||||
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.callback.backup.SecretKeyRestoreSelectionCallback;
|
||||
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
|
||||
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.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.pubsub.PubSubException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||
import org.igniterealtime.smack.inttest.TestNotPossibleException;
|
||||
|
@ -56,6 +59,7 @@ import org.junit.After;
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector;
|
||||
|
||||
public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegrationTest {
|
||||
|
@ -90,24 +94,29 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
|
|||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void test() throws SmackOpenPgpException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
|
||||
public void test() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
|
||||
NoSuchProviderException, IOException, InterruptedException, PubSubException.NotALeafNodeException,
|
||||
SmackException.NoResponseException, SmackException.NotConnectedException, XMPPException.XMPPErrorException,
|
||||
SmackException.NotLoggedInException, SmackException.FeatureNotSupportedException,
|
||||
MissingUserIdOnKeyException, NoBackupFoundException, InvalidBackupCodeException, PGPException {
|
||||
MissingUserIdOnKeyException, NoBackupFoundException, InvalidBackupCodeException, PGPException, MissingOpenPgpKeyPairException {
|
||||
|
||||
FileBasedPainlessOpenPgpStore beforeStore = new FileBasedPainlessOpenPgpStore(beforePath, new UnprotectedKeysProtector());
|
||||
PainlessOpenPgpProvider beforeProvider = new PainlessOpenPgpProvider(alice, beforeStore);
|
||||
OpenPgpStore beforeStore = new FileBasedOpenPgpStore(beforePath);
|
||||
beforeStore.setKeyRingProtector(new UnprotectedKeysProtector());
|
||||
PainlessOpenPgpProvider beforeProvider = new PainlessOpenPgpProvider(beforeStore);
|
||||
OpenPgpManager openPgpManager = OpenPgpManager.getInstanceFor(aliceConnection);
|
||||
openPgpManager.setOpenPgpProvider(beforeProvider);
|
||||
|
||||
assertNull(beforeStore.getSigningKeyPairFingerprint());
|
||||
OpenPgpSelf self = openPgpManager.getOpenPgpSelf();
|
||||
|
||||
assertNull(self.getSigningKeyFingerprint());
|
||||
|
||||
OpenPgpV4Fingerprint keyFingerprint = openPgpManager.generateAndImportKeyPair(alice);
|
||||
beforeStore.setSigningKeyPairFingerprint(keyFingerprint);
|
||||
assertEquals(keyFingerprint, beforeStore.getSigningKeyPairFingerprint());
|
||||
assertEquals(keyFingerprint, self.getSigningKeyFingerprint());
|
||||
|
||||
assertTrue(beforeStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
|
||||
assertTrue(self.getSecretKeys().contains(keyFingerprint.getKeyId()));
|
||||
|
||||
PGPSecretKeyRing beforeKeys = beforeStore.getSecretKeyRing(alice, keyFingerprint);
|
||||
assertNotNull(beforeKeys);
|
||||
|
||||
openPgpManager.backupSecretKeyToServer(new DisplayBackupCodeCallback() {
|
||||
@Override
|
||||
|
@ -121,12 +130,15 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
|
|||
}
|
||||
});
|
||||
|
||||
FileBasedPainlessOpenPgpStore afterStore = new FileBasedPainlessOpenPgpStore(afterPath, new UnprotectedKeysProtector());
|
||||
PainlessOpenPgpProvider afterProvider = new PainlessOpenPgpProvider(alice, afterStore);
|
||||
FileBasedOpenPgpStore afterStore = new FileBasedOpenPgpStore(afterPath);
|
||||
afterStore.setKeyRingProtector(new UnprotectedKeysProtector());
|
||||
PainlessOpenPgpProvider afterProvider = new PainlessOpenPgpProvider(afterStore);
|
||||
openPgpManager.setOpenPgpProvider(afterProvider);
|
||||
|
||||
assertNull(afterStore.getSigningKeyPairFingerprint());
|
||||
assertFalse(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
|
||||
self = openPgpManager.getOpenPgpSelf();
|
||||
|
||||
assertNull(self.getSigningKeyFingerprint());
|
||||
assertFalse(self.getSecretKeys().contains(keyFingerprint.getKeyId()));
|
||||
|
||||
OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(new AskForBackupCodeCallback() {
|
||||
@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());
|
||||
assertTrue(Arrays.equals(beforeStore.getSecretKeyRings(alice).getEncoded(), afterStore.getSecretKeyRings(alice).getEncoded()));
|
||||
PGPSecretKeyRing afterKeys = afterStore.getSecretKeyRing(alice, keyFingerprint);
|
||||
assertNotNull(afterKeys);
|
||||
assertTrue(Arrays.equals(beforeKeys.getEncoded(), afterKeys.getEncoded()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.jivesoftware.smackx.ox;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -34,13 +35,14 @@ import org.jivesoftware.smack.packet.Message;
|
|||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
||||
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.exception.MissingOpenPgpKeyPairException;
|
||||
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
|
||||
import org.jivesoftware.smackx.ox.listener.OxMessageListener;
|
||||
import org.jivesoftware.smackx.ox.listener.internal.SigncryptElementReceivedListener;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
/**
|
||||
* 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 final Set<OxMessageListener> oxMessageListeners = new HashSet<>();
|
||||
private final OpenPgpManager openPgpManager;
|
||||
|
||||
private OXInstantMessagingManager(final XMPPConnection connection) {
|
||||
super(connection);
|
||||
OpenPgpManager.getInstanceFor(connection).registerSigncryptReceivedListener(this);
|
||||
openPgpManager = OpenPgpManager.getInstanceFor(connection);
|
||||
openPgpManager.registerSigncryptReceivedListener(this);
|
||||
announceSupportForOxInstantMessaging();
|
||||
}
|
||||
|
||||
|
@ -153,15 +157,13 @@ public final class OXInstantMessagingManager extends Manager implements Signcryp
|
|||
* @param contact contact capable of OpenPGP for XMPP: Instant Messaging.
|
||||
* @param body message body.
|
||||
* @throws InterruptedException if the thread is interrupted
|
||||
* @throws MissingOpenPgpKeyPairException if we cannot access our signing key
|
||||
* @throws IOException IO is dangerous
|
||||
* @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
|
||||
*/
|
||||
public void sendOxMessage(OpenPgpContact contact, CharSequence body)
|
||||
throws InterruptedException, MissingOpenPgpKeyPairException, IOException,
|
||||
SmackException.NotConnectedException, SmackOpenPgpException, SmackException.NotLoggedInException {
|
||||
throws InterruptedException, IOException,
|
||||
SmackException.NotConnectedException, SmackException.NotLoggedInException, PGPException {
|
||||
Message message = new Message(contact.getJid());
|
||||
List<ExtensionElement> payload = new ArrayList<>();
|
||||
payload.add(new Message.Body(null, body.toString()));
|
||||
|
@ -172,7 +174,12 @@ public final class OXInstantMessagingManager extends Manager implements Signcryp
|
|||
StoreHint.set(message);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
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 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.bouncycastle.openpgp.PGPException;
|
||||
|
@ -35,14 +55,25 @@ public class OpenPgpContact {
|
|||
|
||||
public PGPPublicKeyRingCollection getAnnouncedPublicKeys() throws IOException, PGPException {
|
||||
PGPPublicKeyRingCollection anyKeys = getAnyPublicKeys();
|
||||
Set<OpenPgpV4Fingerprint> announced = store.getAnnouncedFingerprintsOf(jid).keySet();
|
||||
Map<OpenPgpV4Fingerprint, Date> announced = store.getAnnouncedFingerprintsOf(jid);
|
||||
|
||||
PGPPublicKeyRingCollection announcedKeysCollection = anyKeys;
|
||||
|
||||
BareJidUserId.PubRingSelectionStrategy userIdFilter = new BareJidUserId.PubRingSelectionStrategy();
|
||||
AnnouncedKeys.PubKeyRingSelectionStrategy announcedFilter = new AnnouncedKeys.PubKeyRingSelectionStrategy();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_NOTIFY;
|
||||
import static org.jivesoftware.smackx.ox.util.PubSubDelegate.publishPublicKey;
|
||||
|
||||
import java.io.IOException;
|
||||
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.crypto.OpenPgpProvider;
|
||||
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.PublicKeysListElement;
|
||||
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||
import org.jivesoftware.smackx.ox.element.SignElement;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
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.MissingUserIdOnKeyException;
|
||||
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.SignElementReceivedListener;
|
||||
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.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.pgpainless.pgpainless.PGPainless;
|
||||
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
public final class OpenPgpManager extends Manager {
|
||||
|
||||
|
@ -94,8 +102,6 @@ public final class OpenPgpManager extends Manager {
|
|||
*/
|
||||
private OpenPgpProvider provider;
|
||||
|
||||
private OpenPgpStore store;
|
||||
|
||||
private final Map<BareJid, OpenPgpContact> openPgpCapableContacts = new HashMap<>();
|
||||
|
||||
private final Set<SigncryptElementReceivedListener> signcryptElementReceivedListeners = new HashSet<>();
|
||||
|
@ -144,6 +150,10 @@ public final class OpenPgpManager extends Manager {
|
|||
this.provider = provider;
|
||||
}
|
||||
|
||||
OpenPgpProvider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get our OpenPGP self.
|
||||
*
|
||||
|
@ -151,8 +161,10 @@ public final class OpenPgpManager extends Manager {
|
|||
* @throws SmackException.NotLoggedInException if we are not logged in
|
||||
*/
|
||||
public OpenPgpSelf getOpenPgpSelf() throws SmackException.NotLoggedInException {
|
||||
throwIfNoProviderSet();
|
||||
|
||||
if (self == null) {
|
||||
self = new OpenPgpSelf(getJidOrThrow(), store);
|
||||
self = new OpenPgpSelf(getJidOrThrow(), provider.getStore());
|
||||
}
|
||||
|
||||
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 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 PubSubException.NotALeafNodeException if one of the PubSub nodes is not a {@link LeafNode}.
|
||||
* @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 InvalidAlgorithmParameterException if illegal algorithm parameters are used for key generation.
|
||||
* @throws SmackException.NotLoggedInException if we are not logged in.
|
||||
* @throws PGPException if something goes wrong during key loading/generating
|
||||
*/
|
||||
public void announceSupportAndPublish()
|
||||
throws NoSuchAlgorithmException, NoSuchProviderException, SmackOpenPgpException,
|
||||
InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
|
||||
throws NoSuchAlgorithmException, NoSuchProviderException, InterruptedException,
|
||||
PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
|
||||
SmackException.NotConnectedException, SmackException.NoResponseException, IOException,
|
||||
InvalidAlgorithmParameterException, SmackException.NotLoggedInException {
|
||||
InvalidAlgorithmParameterException, SmackException.NotLoggedInException, PGPException {
|
||||
throwIfNoProviderSet();
|
||||
throwIfNotAuthenticated();
|
||||
|
||||
BareJid ourJid = connection().getUser().asBareJid();
|
||||
OpenPgpV4Fingerprint primaryFingerprint = getOurFingerprint();
|
||||
|
||||
// OpenPgpV4Fingerprint primaryFingerprint = getOurFingerprint();
|
||||
|
||||
// if (primaryFingerprint == null) {
|
||||
// primaryFingerprint = generateAndImportKeyPair(ourJid);
|
||||
// }
|
||||
if (primaryFingerprint == null) {
|
||||
primaryFingerprint = generateAndImportKeyPair(getJidOrThrow());
|
||||
}
|
||||
|
||||
// Create <pubkey/> element
|
||||
PubkeyElement pubkeyElement;
|
||||
// try {
|
||||
// pubkeyElement = createPubkeyElement(ourJid, primaryFingerprint, new Date());
|
||||
// } catch (MissingOpenPgpPublicKeyException e) {
|
||||
// throw new AssertionError("Cannot publish our public key, since it is missing (MUST NOT happen!)");
|
||||
// }
|
||||
try {
|
||||
pubkeyElement = createPubkeyElement(getJidOrThrow(), primaryFingerprint, new Date());
|
||||
} catch (MissingOpenPgpPublicKeyException e) {
|
||||
throw new AssertionError("Cannot publish our public key, since it is missing (MUST NOT happen!)");
|
||||
}
|
||||
|
||||
// publish it
|
||||
// publishPublicKey(connection(), pubkeyElement, primaryFingerprint);
|
||||
publishPublicKey(connection(), pubkeyElement, primaryFingerprint);
|
||||
|
||||
// Subscribe to public key changes
|
||||
// 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 InvalidAlgorithmParameterException if the used algorithm parameters are invalid.
|
||||
* @throws NoSuchProviderException if we are missing a cryptographic provider.
|
||||
* @throws SmackOpenPgpException in case of an OpenPGP error.
|
||||
*/
|
||||
public OpenPgpV4Fingerprint generateAndImportKeyPair(BareJid ourJid)
|
||||
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException,
|
||||
SmackOpenPgpException, PGPException {
|
||||
PGPException, IOException {
|
||||
|
||||
throwIfNoProviderSet();
|
||||
OpenPgpStore store = provider.getStore();
|
||||
PGPSecretKeyRing keyPair = store.generateKeyRing(ourJid);
|
||||
// try {
|
||||
// provider.importSecretKey(ourJid, keyPair);
|
||||
// } catch (MissingUserIdOnKeyException e) {
|
||||
try {
|
||||
store.importSecretKey(ourJid, keyPair);
|
||||
} catch (MissingUserIdOnKeyException e) {
|
||||
// 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);
|
||||
}
|
||||
|
@ -251,7 +262,8 @@ public final class OpenPgpManager extends Manager {
|
|||
* @return {@link OpenPgpContact}.
|
||||
*/
|
||||
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.NoResponseException if the server doesn't respond.
|
||||
* @throws SmackException.NotLoggedInException if we are not logged in.
|
||||
* @throws SmackOpenPgpException in case of an OpenPGP exception.
|
||||
* @throws IOException IO is dangerous.
|
||||
* @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)
|
||||
throws InterruptedException, PubSubException.NotALeafNodeException,
|
||||
XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException,
|
||||
SmackException.NotLoggedInException, SmackOpenPgpException, IOException,
|
||||
SmackException.FeatureNotSupportedException {
|
||||
SmackException.NotLoggedInException, IOException,
|
||||
SmackException.FeatureNotSupportedException, PGPException, MissingOpenPgpKeyPairException {
|
||||
throwIfNoProviderSet();
|
||||
throwIfNotAuthenticated();
|
||||
|
||||
BareJid ownJid = connection().getUser().asBareJid();
|
||||
|
||||
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);
|
||||
// displayCodeCallback.displayBackupCode(backupCode);
|
||||
Set<OpenPgpV4Fingerprint> availableKeyPairs = new HashSet<>();
|
||||
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 SmackException.NotConnectedException if we are not connected.
|
||||
* @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 SmackException.NotLoggedInException if we are not logged in
|
||||
* @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
|
||||
*/
|
||||
public OpenPgpV4Fingerprint restoreSecretKeyServerBackup(AskForBackupCodeCallback codeCallback,
|
||||
SecretKeyRestoreSelectionCallback selectionCallback)
|
||||
SecretKeyRestoreSelectionCallback selectionCallback)
|
||||
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
|
||||
SmackException.NotConnectedException, SmackException.NoResponseException, SmackOpenPgpException,
|
||||
SmackException.NotConnectedException, SmackException.NoResponseException,
|
||||
InvalidBackupCodeException, SmackException.NotLoggedInException, IOException, MissingUserIdOnKeyException,
|
||||
NoBackupFoundException {
|
||||
NoBackupFoundException, PGPException {
|
||||
throwIfNoProviderSet();
|
||||
throwIfNotAuthenticated();
|
||||
SecretkeyElement backup = PubSubDelegate.fetchSecretKey(connection());
|
||||
|
@ -364,8 +381,9 @@ public final class OpenPgpManager extends Manager {
|
|||
|
||||
String backupCode = codeCallback.askForBackupCode();
|
||||
|
||||
OpenPgpV4Fingerprint fingerprint = SecretKeyBackupHelper.restoreSecretKeyBackup(provider, backup, backupCode);
|
||||
return fingerprint;
|
||||
PGPSecretKeyRing key = SecretKeyBackupHelper.restoreSecretKeyBackup(backup, backupCode);
|
||||
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) {
|
||||
/*
|
||||
OpenPgpContact openPgpContact = getOpenPgpContact(contact.asEntityBareJidIfPossible());
|
||||
|
||||
try {
|
||||
openPgpContact.updateKeys(listElement);
|
||||
} catch (SmackOpenPgpException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not read key ring of contact " + contact, e);
|
||||
PGPPublicKeyRingCollection contactsKeys = provider.getStore().getPublicKeysOf(contact);
|
||||
for (OpenPgpV4Fingerprint fingerprint : listElement.getMetadata().keySet()) {
|
||||
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 =
|
||||
new IncomingChatMessageListener() {
|
||||
@Override
|
||||
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
|
||||
/*
|
||||
OpenPgpElement element = message.getExtension(OpenPgpElement.ELEMENT, OpenPgpElement.NAMESPACE);
|
||||
if (element == null) {
|
||||
// Message does not contain an OpenPgpElement -> discard
|
||||
|
@ -419,13 +440,11 @@ public final class OpenPgpManager extends Manager {
|
|||
|
||||
OpenPgpContentElement contentElement = null;
|
||||
try {
|
||||
contentElement = contact.receive(element);
|
||||
} catch (SmackOpenPgpException e) {
|
||||
contentElement = provider.decryptAndOrVerify(element, self, contact).getOpenPgpContentElement();
|
||||
} catch (PGPException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not decrypt incoming OpenPGP encrypted message", e);
|
||||
} catch (XmlPullParserException | IOException 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) {
|
||||
|
@ -452,7 +471,6 @@ public final class OpenPgpManager extends Manager {
|
|||
else {
|
||||
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
|
||||
* "xmpp:juliet@capulet.lit" with the owners {@link BareJid}
|
||||
* @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)
|
||||
throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException {
|
||||
throws MissingUserIdOnKeyException, IOException, PGPException {
|
||||
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,
|
||||
OpenPgpV4Fingerprint fingerprint,
|
||||
Date date)
|
||||
throws MissingOpenPgpPublicKeyException {
|
||||
// byte[] keyBytes = provider.getStore().getPublicKeyRingBytes(owner, fingerprint);
|
||||
// return createPubkeyElement(keyBytes, date);
|
||||
return null;
|
||||
throws MissingOpenPgpPublicKeyException, IOException, PGPException {
|
||||
PGPPublicKeyRingCollection publicKeyRingCollection = provider.getStore().getPublicKeysOf(owner);
|
||||
if (publicKeyRingCollection != null) {
|
||||
PGPPublicKeyRing keys = publicKeyRingCollection.getPublicKeyRing(fingerprint.getKeyId());
|
||||
if (keys != null) {
|
||||
byte[] keyBytes = keys.getEncoded(true);
|
||||
return createPubkeyElement(keyBytes, date);
|
||||
}
|
||||
}
|
||||
throw new MissingOpenPgpPublicKeyException(owner, fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -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");
|
||||
* 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.SignElement;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
|
||||
public interface OpenPgpProvider {
|
||||
|
||||
OpenPgpStore getStore();
|
||||
|
||||
OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients)
|
||||
throws IOException, PGPException;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
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.SignElement;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
|
@ -25,6 +42,17 @@ import org.pgpainless.pgpainless.encryption_signing.EncryptionStream;
|
|||
|
||||
public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
||||
|
||||
private final OpenPgpStore store;
|
||||
|
||||
public PainlessOpenPgpProvider(OpenPgpStore store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpStore getStore() {
|
||||
return store;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients)
|
||||
throws IOException, PGPException {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
* 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.util.HashMap;
|
||||
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.bouncycastle.openpgp.PGPException;
|
||||
|
@ -37,12 +41,10 @@ import org.pgpainless.pgpainless.key.generation.type.length.RsaLength;
|
|||
|
||||
public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore {
|
||||
|
||||
public AbstractOpenPgpKeyStore() {
|
||||
private static final Logger LOGGER = Logger.getLogger(AbstractOpenPgpKeyStore.class.getName());
|
||||
|
||||
}
|
||||
|
||||
protected Map<BareJid, PGPPublicKeyRingCollection> publicKeys = new HashMap<>();
|
||||
protected Map<BareJid, PGPSecretKeyRingCollection> secretKeys = new HashMap<>();
|
||||
protected Map<BareJid, PGPPublicKeyRingCollection> publicKeyRingCollections = new HashMap<>();
|
||||
protected Map<BareJid, PGPSecretKeyRingCollection> secretKeyRingCollections = new HashMap<>();
|
||||
|
||||
protected abstract PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner) throws IOException, PGPException;
|
||||
|
||||
|
@ -54,11 +56,11 @@ public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore {
|
|||
|
||||
@Override
|
||||
public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException {
|
||||
PGPPublicKeyRingCollection keys = publicKeys.get(owner);
|
||||
PGPPublicKeyRingCollection keys = publicKeyRingCollections.get(owner);
|
||||
if (keys == null) {
|
||||
keys = readPublicKeysOf(owner);
|
||||
if (keys != null) {
|
||||
publicKeys.put(owner, keys);
|
||||
publicKeyRingCollections.put(owner, keys);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
|
@ -66,16 +68,53 @@ public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore {
|
|||
|
||||
@Override
|
||||
public PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException {
|
||||
PGPSecretKeyRingCollection keys = secretKeys.get(owner);
|
||||
PGPSecretKeyRingCollection keys = secretKeyRingCollections.get(owner);
|
||||
if (keys == null) {
|
||||
keys = readSecretKeysOf(owner);
|
||||
if (keys != null) {
|
||||
secretKeys.put(owner, keys);
|
||||
secretKeyRingCollections.put(owner, 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
|
||||
public PGPPublicKeyRing getPublicKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException {
|
||||
PGPPublicKeyRingCollection publicKeyRings = getPublicKeysOf(owner);
|
||||
|
|
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -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");
|
||||
* 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.smackx.ox.OpenPgpContact;
|
||||
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.OpenPgpMetadataStore;
|
||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
|
||||
|
@ -115,6 +116,16 @@ public abstract class AbstractOpenPgpStore extends Observable implements OpenPgp
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -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");
|
||||
* 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.NoSuchProviderException;
|
||||
|
||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
|
@ -42,4 +44,8 @@ public interface OpenPgpKeyStore {
|
|||
PGPSecretKeyRing getSecretKeyRing(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException, PGPException;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -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;
|
||||
|
||||
import org.jivesoftware.smackx.ox.OpenPgpContact;
|
||||
|
|
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -468,7 +468,8 @@ public class PubSubDelegate {
|
|||
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException |
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,17 +16,22 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.ox.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||
import org.jivesoftware.smackx.ox.crypto.OpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.pgpainless.pgpainless.PGPainless;
|
||||
import org.pgpainless.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||
import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
|
||||
public class SecretKeyBackupHelper {
|
||||
|
@ -62,45 +67,41 @@ public class SecretKeyBackupHelper {
|
|||
public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider,
|
||||
BareJid owner,
|
||||
Set<OpenPgpV4Fingerprint> fingerprints,
|
||||
String backupCode) throws SmackOpenPgpException, IOException {
|
||||
/*
|
||||
String backupCode) throws PGPException, IOException, MissingOpenPgpKeyPairException {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
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);
|
||||
} catch (MissingOpenPgpKeyPairException | IOException e) {
|
||||
throw new SmackOpenPgpException("Cannot backup secret key " + Long.toHexString(fingerprint.getKeyId()) + ".", e);
|
||||
}
|
||||
}
|
||||
return createSecretkeyElement(provider, buffer.toByteArray(), backupCode);
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
public static SecretkeyElement createSecretkeyElement(OpenPgpProvider provider,
|
||||
byte[] keys,
|
||||
String backupCode)
|
||||
throws SmackOpenPgpException, IOException {
|
||||
// byte[] encrypted = provider.symmetricallyEncryptWithPassword(keys, backupCode);
|
||||
// return new SecretkeyElement(Base64.encode(encrypted));
|
||||
return null;
|
||||
throws PGPException, IOException {
|
||||
byte[] encrypted = PGPainless.encryptWithPassword(keys, backupCode.toCharArray(), SymmetricKeyAlgorithm.AES_256);
|
||||
return new SecretkeyElement(Base64.encode(encrypted));
|
||||
}
|
||||
|
||||
public static OpenPgpV4Fingerprint restoreSecretKeyBackup(OpenPgpProvider provider, SecretkeyElement backup, String backupCode)
|
||||
throws InvalidBackupCodeException, IOException, MissingUserIdOnKeyException, SmackOpenPgpException {
|
||||
/*
|
||||
public static PGPSecretKeyRing restoreSecretKeyBackup(SecretkeyElement backup, String backupCode)
|
||||
throws InvalidBackupCodeException, IOException, PGPException {
|
||||
byte[] encrypted = Base64.decode(backup.getB64Data());
|
||||
|
||||
byte[] decrypted;
|
||||
try {
|
||||
decrypted = provider.symmetricallyDecryptWithPassword(encrypted, backupCode);
|
||||
} catch (IOException | SmackOpenPgpException e) {
|
||||
decrypted = PGPainless.decryptWithPassword(encrypted, backupCode.toCharArray());
|
||||
} catch (IOException | PGPException e) {
|
||||
throw new InvalidBackupCodeException("Could not decrypt secret key backup. Possibly wrong passphrase?", e);
|
||||
}
|
||||
|
||||
return provider.importSecretKey(decrypted);
|
||||
*/
|
||||
return null;
|
||||
return PGPainless.readKeyRing().secretKeyRing(decrypted);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue