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;
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);

View File

@ -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()));
}
}

View File

@ -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);
}

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;
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);
}
}

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_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);
}
/**

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;
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");
* 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");
* 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;

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;
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 {

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");
* 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);

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");
* 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");
* 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
*/

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;
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");
* 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;
}

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");
* 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;
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");
* 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");
* 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");
* 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");
* 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");
* 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 |
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;
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);
}
}