diff --git a/build.gradle b/build.gradle index 53f928569..ee9f7dba9 100644 --- a/build.gradle +++ b/build.gradle @@ -79,6 +79,7 @@ allprojects { ':smack-experimental', ':smack-omemo', ':smack-omemo-signal', + ':smack-openpgp', ].collect{ project(it) } androidBootClasspathProjects = [ ':smack-android', diff --git a/settings.gradle b/settings.gradle index ee70118ed..1e1fdb155 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,6 +27,5 @@ include 'smack-core', 'smack-omemo-signal', 'smack-omemo-signal-integration-test', 'smack-repl', - 'smack-openpgp', - 'smack-openpgp-bouncycastle' + 'smack-openpgp' diff --git a/smack-integration-test/build.gradle b/smack-integration-test/build.gradle index 85c2b673c..23c50bf7d 100644 --- a/smack-integration-test/build.gradle +++ b/smack-integration-test/build.gradle @@ -13,7 +13,6 @@ dependencies { compile project(':smack-experimental') compile project(':smack-omemo') compile project(':smack-openpgp') - compile project(':smack-openpgp-bouncycastle') compile project(':smack-debug') compile project(path: ":smack-omemo", configuration: "testRuntime") compile 'org.reflections:reflections:0.9.9-RC1' diff --git a/smack-openpgp-bouncycastle/build.gradle b/smack-openpgp-bouncycastle/build.gradle deleted file mode 100644 index c57c0bbcc..000000000 --- a/smack-openpgp-bouncycastle/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ -description = """\ -Smack API for OpenPGP using Bouncycastle.""" - -// Note that the test dependencies (junit, …) are inferred from the -// sourceSet.test of the core subproject -dependencies { - compile project(':smack-core') - compile project(':smack-openpgp') - compile 'org.pgpainless:pgpainless:0.1-SNAPSHOT' - testCompile project(path: ":smack-core", configuration: "testRuntime") - testCompile project(path: ":smack-core", configuration: "archives") - testCompile project(path: ":smack-openpgp", configuration: "testRuntime") -} diff --git a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/AbstractPainlessOpenPgpStore.java b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/AbstractPainlessOpenPgpStore.java deleted file mode 100644 index 8ef4c3a9d..000000000 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/AbstractPainlessOpenPgpStore.java +++ /dev/null @@ -1,108 +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.bouncycastle; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; -import org.jxmpp.jid.BareJid; -import org.pgpainless.pgpainless.key.protection.SecretKeyRingProtector; - -public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpStore { - - private final BcKeyFingerprintCalculator fingerprintCalculator = new BcKeyFingerprintCalculator(); - - private final Map publicKeyRings = new HashMap<>(); - private final Map secretKeyRings = new HashMap<>(); - private OpenPgpV4Fingerprint primaryKeyFingerprint = null; - private final SecretKeyRingProtector secretKeyRingProtector; - - @Override - public OpenPgpV4Fingerprint getSigningKeyPairFingerprint() { - return primaryKeyFingerprint; - } - - @Override - public void setSigningKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint) { - this.primaryKeyFingerprint = fingerprint; - } - - @Override - public SecretKeyRingProtector getSecretKeyProtector() { - return secretKeyRingProtector; - } - - public AbstractPainlessOpenPgpStore(SecretKeyRingProtector secretKeyRingProtector) { - this.secretKeyRingProtector = secretKeyRingProtector; - } - - @Override - public PGPPublicKeyRingCollection getPublicKeyRings(BareJid owner) throws IOException, PGPException { - PGPPublicKeyRingCollection keyRing = publicKeyRings.get(owner); - if (keyRing != null) { - return keyRing; - } - - byte[] bytes = loadPublicKeyRingBytes(owner); - if (bytes == null) { - return null; - } - keyRing = new PGPPublicKeyRingCollection(bytes, fingerprintCalculator); - - publicKeyRings.put(owner, keyRing); - - return keyRing; - } - - @Override - public PGPSecretKeyRingCollection getSecretKeyRings(BareJid owner) throws IOException, PGPException { - PGPSecretKeyRingCollection keyRing = secretKeyRings.get(owner); - if (keyRing != null) { - return keyRing; - } - - byte[] bytes = loadSecretKeyRingBytes(owner); - if (bytes == null) { - return null; - } - keyRing = new PGPSecretKeyRingCollection(bytes, fingerprintCalculator); - - secretKeyRings.put(owner, keyRing); - - return keyRing; - } - - @Override - public void storePublicKeyRing(BareJid owner, PGPPublicKeyRingCollection publicKeys) throws IOException { - publicKeyRings.put(owner, publicKeys); - storePublicKeyRingBytes(owner, publicKeys.getEncoded()); - } - - @Override - public void storeSecretKeyRing(BareJid owner, PGPSecretKeyRingCollection secretKeys) throws IOException { - secretKeyRings.put(owner, secretKeys); - storeSecretKeyRingBytes(owner, secretKeys.getEncoded()); - } - -} diff --git a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStore.java b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStore.java deleted file mode 100644 index d00b26e82..000000000 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStore.java +++ /dev/null @@ -1,440 +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.bouncycastle; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.jivesoftware.smack.util.MultiMap; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException; -import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException; -import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException; - -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.bouncycastle.util.io.Streams; -import org.jxmpp.jid.BareJid; -import org.jxmpp.jid.impl.JidCreate; -import org.jxmpp.util.XmppDateTime; -import org.pgpainless.pgpainless.key.protection.SecretKeyRingProtector; - -public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore { - - private static final Logger LOGGER = Logger.getLogger(FileBasedPainlessOpenPgpStore.class.getName()); - - private final File basePath; - - public FileBasedPainlessOpenPgpStore(File base, SecretKeyRingProtector secretKeyRingProtector) { - super(secretKeyRingProtector); - this.basePath = base; - } - - @Override - public byte[] loadPublicKeyRingBytes(BareJid owner) { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - FileInputStream inputStream = null; - byte[] bytes = null; - try { - inputStream = new FileInputStream(getContactsPubringFile(owner, false)); - Streams.pipeAll(inputStream, buffer); - inputStream.close(); - bytes = buffer.toByteArray(); - } catch (FileNotFoundException e) { - LOGGER.log(Level.FINE, "Pubring of user " + owner.toString() + " does not exist."); - return null; - } catch (IOException e) { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException ee) { - LOGGER.log(Level.WARNING, "Could not close InputStream:", ee); - } - } - } - - return bytes; - } - - @Override - public byte[] loadSecretKeyRingBytes(BareJid owner) { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - FileInputStream inputStream = null; - byte[] bytes = null; - try { - inputStream = new FileInputStream(getContactsSecringFile(owner, false)); - Streams.pipeAll(inputStream, buffer); - inputStream.close(); - bytes = buffer.toByteArray(); - } catch (FileNotFoundException e) { - LOGGER.log(Level.FINE, "Secring of user " + owner.toString() + " does not exist."); - return null; - } catch (IOException e) { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException ee) { - LOGGER.log(Level.WARNING, "Could not close InputStream:", ee); - } - } - } - - return bytes; - } - - @Override - public void storePublicKeyRingBytes(BareJid owner, byte[] bytes) { - FileOutputStream outputStream = null; - try { - outputStream = new FileOutputStream(getContactsPubringFile(owner, true)); - outputStream.write(bytes); - outputStream.close(); - } catch (FileNotFoundException e) { - throw new AssertionError("File does not exist, even though it MUST exist at this point.", e); - } catch (IOException e) { - if (outputStream != null) { - try { - outputStream.close(); - } catch (IOException ee) { - LOGGER.log(Level.WARNING, "Could not close OutputStream:", ee); - } - } - } - } - - @Override - public void storeSecretKeyRingBytes(BareJid owner, byte[] bytes) { - FileOutputStream outputStream = null; - try { - outputStream = new FileOutputStream(getContactsSecringFile(owner, true)); - outputStream.write(bytes); - outputStream.close(); - } catch (FileNotFoundException e) { - throw new AssertionError("File does not exist, even though it MUST exist at this point.", e); - } catch (IOException e) { - if (outputStream != null) { - try { - outputStream.close(); - } catch (IOException ee) { - LOGGER.log(Level.WARNING, "Could not close OutputStream:", ee); - } - } - } - } - - @Override - public Set getAvailableKeyPairFingerprints(BareJid owner) throws SmackOpenPgpException { - Set fingerprints = new HashSet<>(); - try { - PGPSecretKeyRingCollection secretKeys = getSecretKeyRings(owner); - for (PGPSecretKeyRing s : secretKeys != null ? secretKeys : Collections.emptySet()) { - fingerprints.add(PainlessOpenPgpProvider.getFingerprint(s.getPublicKey())); - } - } catch (IOException | PGPException e) { - throw new SmackOpenPgpException("Could not get available key pair fingerprints.", e); - } - - return fingerprints; - } - - @Override - public Map getAvailableKeysFingerprints(BareJid contact) throws SmackOpenPgpException { - Map availableFingerprints = new HashMap<>(); - try { - PGPPublicKeyRingCollection publicKeys = getPublicKeyRings(contact); - Set fingerprints = new HashSet<>(); - for (PGPPublicKeyRing ring : publicKeys != null ? publicKeys : Collections.emptySet()) { - OpenPgpV4Fingerprint fingerprint = PainlessOpenPgpProvider.getFingerprint(ring.getPublicKey()); - fingerprints.add(fingerprint); - } - - Map announced = getAnnouncedKeysFingerprints(contact); - for (OpenPgpV4Fingerprint fingerprint : fingerprints) { - if (announced.containsKey(fingerprint)) { - availableFingerprints.put(fingerprint, announced.get(fingerprint)); - } - } - - } catch (PGPException | IOException e) { - throw new SmackOpenPgpException("Could not read public keys of contact " + contact.toString(), e); - } - return availableFingerprints; - } - - @Override - public Map getAnnouncedKeysFingerprints(BareJid contact) { - try { - File file = getContactsPubkeyAnnouncementFile(contact, false); - return loadFingerprintsAndDates(file); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Could not read announced fingerprints of contact " + contact, e); - } - return new HashMap<>(); - } - - @Override - public void setAnnouncedKeysFingerprints(BareJid contact, Map fingerprints) { - try { - File file = getContactsPubkeyAnnouncementFile(contact, true); - writeFingerprintsAndDates(fingerprints, file); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Could not write announced fingerprints of " + contact.toString(), e); - } - } - - @Override - public Map getPubkeysLastRevisions(BareJid owner) { - try { - return loadFingerprintsAndDates(getContactsPubkeyRevisionInfoFile(owner, false)); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Could not read revision dates of pubkeys of " + owner.toString(), e); - return new HashMap<>(); - } - } - - private static Map loadFingerprintsAndDates(File file) throws IOException { - Map revisionDates = new HashMap<>(); - BufferedReader reader = null; - try { - reader = Files.newBufferedReader(file.toPath(), Charset.forName("UTF-8")); - int lineNr = 0; - String line; - while ((line = reader.readLine()) != null) { - lineNr++; - line = line.trim(); - if (line.isEmpty()) { - continue; - } - - String[] split = line.split(" "); - if (split.length != 2) { - continue; - } - - try { - OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(split[0]); - Date date = XmppDateTime.parseXEP0082Date(split[1]); - revisionDates.put(fingerprint, date); - } catch (Exception e) { - LOGGER.log(Level.WARNING, "Encountered illegal line in file " + - file.getAbsolutePath() + ": " + lineNr, e); - } - } - reader.close(); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Could not read fingerprints and dates from file " + file.getAbsolutePath(), e); - if (reader != null) { - reader.close(); - } - } - return revisionDates; - } - - private static void writeFingerprintsAndDates(Map fingerprints, File file) throws IOException { - BufferedWriter writer = null; - try { - writer = Files.newBufferedWriter(file.toPath(), Charset.forName("UTF-8")); - for (OpenPgpV4Fingerprint fingerprint : fingerprints.keySet()) { - Date date = fingerprints.get(fingerprint); - String line = fingerprint.toString() + " " + (date != null ? XmppDateTime.formatXEP0082Date(date) : XmppDateTime.formatXEP0082Date(new Date())); - writer.write(line); - } - writer.close(); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Could not write fingerprints and dates to file " + file.getAbsolutePath()); - if (writer != null) { - writer.close(); - } - } - } - - @Override - public void setPubkeysLastRevision(BareJid owner, Map revisionDates) { - try { - File file = getContactsPubkeyRevisionInfoFile(owner, true); - writeFingerprintsAndDates(revisionDates, file); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Could not write last pubkey revisions of " + owner, e); - } - } - - @Override - public MultiMap getAllContactsTrustedFingerprints() { - MultiMap trustedFingerprints = new MultiMap<>(); - try { - File contactsDir = getContactsPath(false); - if (!contactsDir.exists()) { - LOGGER.log(Level.FINE, "Contacts directory does not exists yet."); - return trustedFingerprints; - } - - File[] subDirectories = contactsDir.listFiles(directoryFilter); - if (subDirectories == null) { - return trustedFingerprints; - } - - for (File contact : subDirectories) { - BareJid jid = JidCreate.bareFrom(contact.getName()); - try { - PGPPublicKeyRingCollection publicKeyRings = getPublicKeyRings(jid); - for (PGPPublicKeyRing ring : publicKeyRings) { - OpenPgpV4Fingerprint fingerprint = PainlessOpenPgpProvider.getFingerprint(ring.getPublicKey()); - trustedFingerprints.put(jid, fingerprint); - } - } catch (PGPException e) { - LOGGER.log(Level.WARNING, "Could not read public key ring of " + jid, e); - } - } - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Could not read contacts directory", e); - } - return trustedFingerprints; - } - - @Override - public byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) - throws MissingOpenPgpPublicKeyException { - try { - PGPPublicKeyRingCollection publicKeyRings = getPublicKeyRings(owner); - PGPPublicKeyRing ring = publicKeyRings.getPublicKeyRing(fingerprint.getKeyId()); - if (ring != null) { - return ring.getEncoded(true); - } else { - throw new MissingOpenPgpPublicKeyException(owner, fingerprint); - } - } catch (IOException | PGPException e) { - throw new MissingOpenPgpPublicKeyException(owner, fingerprint, e); - } - } - - @Override - public byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) - throws MissingOpenPgpKeyPairException { - try { - PGPSecretKeyRingCollection secretKeyRings = getSecretKeyRings(owner); - PGPSecretKeyRing ring = secretKeyRings.getSecretKeyRing(fingerprint.getKeyId()); - if (ring != null) { - return ring.getEncoded(); - } else { - throw new MissingOpenPgpKeyPairException(owner, fingerprint); - } - } catch (IOException | PGPException e) { - throw new MissingOpenPgpKeyPairException(owner, fingerprint, e); - } - } - - /* - #################################################################################################################### - File System Hierarchy - #################################################################################################################### - */ - - private File getStorePath(boolean create) - throws IOException { - if (create && !basePath.exists()) { - createDirectoryOrThrow(basePath); - } - return basePath; - } - - private File getContactsPath(boolean create) throws IOException { - File path = new File(getStorePath(create), "contacts"); - if (create && !path.exists()) { - createDirectoryOrThrow(path); - } - return path; - } - - private File getContactsPath(BareJid owner, boolean create) throws IOException { - File path = new File(getContactsPath(create), owner.toString()); - if (create && !path.exists()) { - createDirectoryOrThrow(path); - } - return path; - } - - private File getContactsPubringFile(BareJid owner, boolean create) throws IOException { - File file = new File(getContactsPath(owner, create), "pubring.pkr"); - if (create && !file.exists()) { - createFileOrThrow(file); - } - return file; - } - - private File getContactsSecringFile(BareJid owner, boolean create) throws IOException { - File file = new File(getContactsPath(owner, create), "secring.skr"); - if (create && !file.exists()) { - createFileOrThrow(file); - } - return file; - } - - private File getContactsPubkeyRevisionInfoFile(BareJid owner, boolean create) throws IOException { - File file = new File(getContactsPath(owner, create), "revisionDates.lst"); - if (create && !file.exists()) { - createFileOrThrow(file); - } - return file; - } - - private File getContactsPubkeyAnnouncementFile(BareJid owner, boolean create) throws IOException { - File file = new File(getContactsPath(owner, create), "announcedKeys.lst"); - if (create && !file.exists()) { - createFileOrThrow(file); - } - return file; - } - - private static void createDirectoryOrThrow(File dir) throws IOException { - if (!dir.mkdirs()) { - throw new IOException("Could not create directory \"" + dir.getAbsolutePath() + "\""); - } - } - - private static void createFileOrThrow(File file) throws IOException { - if (!file.createNewFile()) { - throw new IOException("Could not create file \"" + file.getAbsolutePath() + "\""); - } - } - - private static final FileFilter directoryFilter = new FileFilter() { - @Override - public boolean accept(File file) { - return file != null && file.isDirectory(); - } - }; -} diff --git a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/PainlessOpenPgpProvider.java b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/PainlessOpenPgpProvider.java deleted file mode 100644 index 445211ebf..000000000 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/PainlessOpenPgpProvider.java +++ /dev/null @@ -1,452 +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.bouncycastle; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.jivesoftware.smack.util.MultiMap; -import org.jivesoftware.smackx.ox.OpenPgpProvider; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.callback.backup.SmackMissingOpenPgpPublicKeyCallback; -import org.jivesoftware.smackx.ox.element.CryptElement; -import org.jivesoftware.smackx.ox.element.SignElement; -import org.jivesoftware.smackx.ox.element.SigncryptElement; -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.SmackOpenPgpException; -import org.jivesoftware.smackx.ox.selection_strategy.BareJidUserId; -import org.jivesoftware.smackx.ox.util.DecryptedBytesAndMetadata; -import org.jivesoftware.smackx.ox.util.KeyBytesAndFingerprint; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; -import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.io.Streams; -import org.jxmpp.jid.BareJid; -import org.pgpainless.pgpainless.PGPainless; -import org.pgpainless.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.pgpainless.decryption_verification.DecryptionStream; -import org.pgpainless.pgpainless.decryption_verification.PainlessResult; -import org.pgpainless.pgpainless.key.generation.type.length.RsaLength; -import org.pgpainless.pgpainless.key.protection.SecretKeyRingProtector; -import org.pgpainless.pgpainless.util.BCUtil; - -public class PainlessOpenPgpProvider implements OpenPgpProvider { - - private static final Logger LOGGER = Logger.getLogger(PainlessOpenPgpProvider.class.getName()); - - private final PainlessOpenPgpStore store; - private final BareJid owner; - - public PainlessOpenPgpProvider(BareJid owner, PainlessOpenPgpStore store) { - this.owner = owner; - this.store = store; - } - - @Override - public byte[] signAndEncrypt(SigncryptElement element, - OpenPgpV4Fingerprint signingKey, - MultiMap encryptionKeys) - throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException, SmackOpenPgpException, - IOException { - - PGPSecretKeyRing secretKeyRing; - SecretKeyRingProtector protector = getStore().getSecretKeyProtector(); - - try { - secretKeyRing = getStore() - .getSecretKeyRings(owner) - .getSecretKeyRing( - signingKey.getKeyId()); - } catch (PGPException e) { - LOGGER.log(Level.INFO, "Could not get secret key with id " + Long.toHexString(signingKey.getKeyId()), e); - throw new MissingOpenPgpKeyPairException(owner, signingKey, e); - } - - MultiMap publicKeyRingMultiMap = new MultiMap<>(); - for (BareJid jid : encryptionKeys.keySet()) { - try { - PGPPublicKeyRingCollection publicKeyRings = getStore().getPublicKeyRings(jid); - for (OpenPgpV4Fingerprint f : encryptionKeys.getAll(jid)) { - PGPPublicKeyRing ring = publicKeyRings.getPublicKeyRing(f.getKeyId()); - if (ring != null) { - publicKeyRingMultiMap.put(jid, ring); - } - } - } catch (PGPException e) { - LOGGER.log(Level.INFO, "Could get public keys of " + jid.toString()); - throw new MissingOpenPgpPublicKeyException(owner, encryptionKeys.getFirst(jid)); - } - } - - return signAndEncryptImpl(element, secretKeyRing, protector, publicKeyRingMultiMap); - } - - byte[] signAndEncryptImpl(SigncryptElement element, - PGPSecretKeyRing signingKey, - SecretKeyRingProtector secretKeyRingProtector, - MultiMap encryptionKeys) - throws SmackOpenPgpException, IOException { - InputStream fromPlain = element.toInputStream(); - ByteArrayOutputStream encryptedBytes = new ByteArrayOutputStream(); - - OutputStream toEncrypted; - try { - toEncrypted = PGPainless.createEncryptor() - .onOutputStream(encryptedBytes) - .toRecipients(new ArrayList<>(encryptionKeys.values()).toArray(new PGPPublicKeyRing[] {})) - .usingSecureAlgorithms() - .signWith(secretKeyRingProtector, signingKey) - .noArmor(); - } catch (PGPException | IOException e) { - throw new SmackOpenPgpException(e); - } - - Streams.pipeAll(fromPlain, toEncrypted); - toEncrypted.flush(); - toEncrypted.close(); - - encryptedBytes.close(); - - return encryptedBytes.toByteArray(); - } - - @Override - public byte[] sign(SignElement element, OpenPgpV4Fingerprint signingKeyFingerprint) - throws MissingOpenPgpKeyPairException, IOException, SmackOpenPgpException { - PGPSecretKeyRing signingKeyRing; - try { - signingKeyRing = store.getSecretKeyRings(owner).getSecretKeyRing(signingKeyFingerprint.getKeyId()); - } catch (PGPException e) { - throw new MissingOpenPgpKeyPairException(owner, signingKeyFingerprint, e); - } - - return signImpl(element, signingKeyRing, store.getSecretKeyProtector()); - } - - byte[] signImpl(SignElement element, PGPSecretKeyRing signingKey, SecretKeyRingProtector secretKeyRingProtector) - throws IOException, SmackOpenPgpException { - ByteArrayOutputStream toSigned = new ByteArrayOutputStream(); - OutputStream signer; - try { - signer = PGPainless.createEncryptor().onOutputStream(toSigned) - .doNotEncrypt() - .signWith(secretKeyRingProtector, signingKey) - .noArmor(); - } catch (PGPException e) { - throw new SmackOpenPgpException(e); - } - - InputStream fromPlain = element.toInputStream(); - Streams.pipeAll(fromPlain, signer); - - fromPlain.close(); - signer.close(); - - return toSigned.toByteArray(); - } - - @Override - public byte[] encrypt(CryptElement element, MultiMap encryptionKeyFingerprints) - throws IOException, SmackOpenPgpException { - PGPPublicKeyRing[] allRecipientsKeys = getEncryptionKeys(encryptionKeyFingerprints); - return encryptImpl(element, allRecipientsKeys); - } - - byte[] encryptImpl(CryptElement element, PGPPublicKeyRing[] encryptionKeys) - throws IOException, SmackOpenPgpException { - InputStream fromPlain = element.toInputStream(); - ByteArrayOutputStream encrypted = new ByteArrayOutputStream(); - OutputStream encryptor; - try { - encryptor = PGPainless.createEncryptor() - .onOutputStream(encrypted) - .toRecipients(encryptionKeys) - .usingSecureAlgorithms() - .doNotSign() - .noArmor(); - } catch (PGPException e) { - throw new SmackOpenPgpException(e); - } - - Streams.pipeAll(fromPlain, encryptor); - fromPlain.close(); - encryptor.close(); - - return encrypted.toByteArray(); - } - - @Override - public DecryptedBytesAndMetadata decrypt(byte[] bytes, BareJid sender, final SmackMissingOpenPgpPublicKeyCallback missingPublicKeyCallback) - throws MissingOpenPgpKeyPairException, SmackOpenPgpException { - - PGPSecretKeyRingCollection secretKeyRings; - try { - secretKeyRings = getStore().getSecretKeyRings(owner); - } catch (PGPException | IOException e) { - LOGGER.log(Level.INFO, "Could not get secret keys of user " + owner); - throw new MissingOpenPgpKeyPairException(owner, getStore().getSigningKeyPairFingerprint()); - } - - SecretKeyRingProtector protector = getStore().getSecretKeyProtector(); - - List trustedFingerprints = getStore().getAllContactsTrustedFingerprints().getAll(sender); - Set trustedKeyIds = new HashSet<>(); - for (OpenPgpV4Fingerprint fingerprint : trustedFingerprints) { - trustedKeyIds.add(fingerprint.getKeyId()); - } - - PGPPublicKeyRingCollection publicKeyRings; - try { - publicKeyRings = getStore().getPublicKeyRings(sender); - } catch (PGPException | IOException e) { - LOGGER.log(Level.INFO, "Could not get public keys of sender " + sender.toString(), e); - if (missingPublicKeyCallback != null) { - // TODO: Handle missing key - } - throw new SmackOpenPgpException(e); - } - - Iterator iterator = publicKeyRings.getKeyRings(); - Set trustedKeys = new HashSet<>(); - while (iterator.hasNext()) { - PGPPublicKeyRing ring = iterator.next(); - if (trustedKeyIds.contains(ring.getPublicKey().getKeyID())) { - trustedKeys.add(ring); - } - } - - try { - return decryptImpl(bytes, secretKeyRings, protector, trustedKeys); - } catch (IOException e) { - throw new SmackOpenPgpException(e); - } - } - - DecryptedBytesAndMetadata decryptImpl(byte[] bytes, PGPSecretKeyRingCollection decryptionKeys, - SecretKeyRingProtector protector, - Set verificationKeys) - throws SmackOpenPgpException, IOException { - - InputStream encryptedBytes = new ByteArrayInputStream(bytes); - ByteArrayOutputStream toPlain = new ByteArrayOutputStream(); - DecryptionStream fromEncrypted; - try { - fromEncrypted = PGPainless.createDecryptor() - .onInputStream(encryptedBytes) - .decryptWith(protector, decryptionKeys) - .verifyWith(verificationKeys) - .ignoreMissingPublicKeys() - .build(); - } catch (IOException | PGPException e) { - throw new SmackOpenPgpException(e); - } - - Streams.pipeAll(fromEncrypted, toPlain); - - fromEncrypted.close(); - toPlain.flush(); - toPlain.close(); - - PainlessResult result = fromEncrypted.getResult(); - return new DecryptedBytesAndMetadata(toPlain.toByteArray(), - result.getVerifiedSignatureKeyIds(), - result.getDecryptionKeyId()); - } - - @Override - public byte[] symmetricallyEncryptWithPassword(byte[] bytes, String password) - throws SmackOpenPgpException, IOException { - try { - return PGPainless.encryptWithPassword(bytes, password.toCharArray(), SymmetricKeyAlgorithm.AES_256); - } catch (PGPException e) { - throw new SmackOpenPgpException(e); - } - } - - @Override - public byte[] symmetricallyDecryptWithPassword(byte[] bytes, String password) - throws SmackOpenPgpException, IOException { - try { - return PGPainless.decryptWithPassword(bytes, password.toCharArray()); - } catch (PGPException e) { - throw new SmackOpenPgpException(e); - } - } - - @Override - public PainlessOpenPgpStore getStore() { - return store; - } - - private PGPPublicKeyRing[] getEncryptionKeys(MultiMap encryptionKeys) - throws IOException, SmackOpenPgpException { - Set allRecipientsKeys = new HashSet<>(); - - for (BareJid recipient : encryptionKeys.keySet()) { - PGPPublicKeyRingCollection recipientsKeyRings; - try { - recipientsKeyRings = store.getPublicKeyRings(recipient); - for (OpenPgpV4Fingerprint fingerprint : encryptionKeys.getAll(recipient)) { - PGPPublicKeyRing ring = recipientsKeyRings.getPublicKeyRing(fingerprint.getKeyId()); - if (ring != null) allRecipientsKeys.add(ring); - } - } catch (PGPException e) { - throw new SmackOpenPgpException(e); - } - } - - PGPPublicKeyRing[] allEncryptionKeys = new PGPPublicKeyRing[allRecipientsKeys.size()]; - Iterator iterator = allRecipientsKeys.iterator(); - for (int i = 0; i < allEncryptionKeys.length; i++) { - allEncryptionKeys[i] = iterator.next(); - } - - return allEncryptionKeys; - } - - private PGPSecretKeyRing getSigningKey(OpenPgpV4Fingerprint signingKey) - throws IOException, MissingOpenPgpKeyPairException { - PGPSecretKeyRing signingKeyRing; - try { - signingKeyRing = store.getSecretKeyRings(owner).getSecretKeyRing(signingKey.getKeyId()); - } catch (PGPException e) { - throw new MissingOpenPgpKeyPairException(owner, signingKey, e); - } - return signingKeyRing; - } - - @Override - public KeyBytesAndFingerprint generateOpenPgpKeyPair(BareJid owner) - throws SmackOpenPgpException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, - NoSuchProviderException, IOException { - PGPSecretKeyRing secretKey; - try { - secretKey = PGPainless.generateKeyRing().simpleRsaKeyRing("xmpp:" + owner.toString(), RsaLength._4096); - } catch (PGPException e) { - throw new SmackOpenPgpException("Could not generate OpenPGP Key Pair.", e); - } - - return new KeyBytesAndFingerprint(secretKey.getEncoded(), getFingerprint(secretKey.getPublicKey())); - } - - @Override - public OpenPgpV4Fingerprint importPublicKey(BareJid owner, byte[] bytes) - throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException { - PGPPublicKeyRing publicKeys = new PGPPublicKeyRing(bytes, new BcKeyFingerprintCalculator()); - // LOGGER.log(Level.INFO, "Importing key " + Long.toHexString(publicKeys.getPublicKey().getKeyID())); - return importPublicKey(owner, publicKeys); - } - - public OpenPgpV4Fingerprint importPublicKey(BareJid owner, PGPPublicKeyRing ring) - throws SmackOpenPgpException, IOException, MissingUserIdOnKeyException { - if (!new BareJidUserId.PubRingSelectionStrategy().accept(owner, ring)) { - throw new MissingUserIdOnKeyException(owner, ring.getPublicKey().getKeyID()); - } - try { - PGPPublicKeyRingCollection publicKeyRings = getStore().getPublicKeyRings(owner); - if (publicKeyRings == null) { - publicKeyRings = new PGPPublicKeyRingCollection(Collections.singleton(ring)); - } else { - try { - publicKeyRings = PGPPublicKeyRingCollection.addPublicKeyRing(publicKeyRings, ring); - } catch (IllegalArgumentException e) { - LOGGER.log(Level.INFO, "Skip key " + Long.toHexString(ring.getPublicKey().getKeyID()) + - " as it is already in the public key ring."); - } - } - getStore().storePublicKeyRing(owner, publicKeyRings); - } catch (PGPException e) { - throw new SmackOpenPgpException(e); - } - return getFingerprint(ring.getPublicKey()); - } - - @Override - public OpenPgpV4Fingerprint importSecretKey(BareJid owner, byte[] bytes) - throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException { - PGPSecretKeyRing importSecretKeys; - try { - importSecretKeys = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator()); - } catch (PGPException | IOException e) { - throw new SmackOpenPgpException("Could not deserialize PGP secret key of " + owner.toString(), e); - } - - if (!new BareJidUserId.SecRingSelectionStrategy().accept(owner, importSecretKeys)) { - throw new MissingUserIdOnKeyException(owner, importSecretKeys.getPublicKey().getKeyID()); - } - - PGPSecretKeyRingCollection secretKeyRings; - try { - secretKeyRings = getStore().getSecretKeyRings(owner); - } catch (PGPException | IOException e) { - throw new SmackOpenPgpException("Could not load secret key ring of " + owner.toString(), e); - } - if (secretKeyRings == null) { - try { - secretKeyRings = new PGPSecretKeyRingCollection(Collections.singleton(importSecretKeys)); - } catch (IOException | PGPException e) { - throw new SmackOpenPgpException("Could not create SecretKeyRingCollection from SecretKeyRing.", e); - } - } else { - try { - secretKeyRings = PGPSecretKeyRingCollection.addSecretKeyRing(secretKeyRings, importSecretKeys); - } catch (IllegalArgumentException e) { - LOGGER.log(Level.INFO, "Skip key " + Long.toHexString(importSecretKeys.getPublicKey().getKeyID()) + - " as it is already part of the key ring."); - } - } - getStore().storeSecretKeyRing(owner, secretKeyRings); - - PGPPublicKeyRing publicKeys = BCUtil.publicKeyRingFromSecretKeyRing(importSecretKeys); - importPublicKey(owner, publicKeys); - - return getFingerprint(publicKeys.getPublicKey()); - } - - @Override - public OpenPgpV4Fingerprint importSecretKey(byte[] bytes) - throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException { - return importSecretKey(owner, bytes); - } - - public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) { - byte[] hex = Hex.encode(publicKey.getFingerprint()); - return new OpenPgpV4Fingerprint(hex); - } -} diff --git a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/PainlessOpenPgpStore.java b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/PainlessOpenPgpStore.java deleted file mode 100644 index 2810d8675..000000000 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/PainlessOpenPgpStore.java +++ /dev/null @@ -1,48 +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.bouncycastle; - -import java.io.IOException; - -import org.jivesoftware.smackx.ox.OpenPgpStore; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.jxmpp.jid.BareJid; -import org.pgpainless.pgpainless.key.protection.SecretKeyRingProtector; - -public interface PainlessOpenPgpStore extends OpenPgpStore { - - PGPPublicKeyRingCollection getPublicKeyRings(BareJid owner) throws IOException, PGPException; - - PGPSecretKeyRingCollection getSecretKeyRings(BareJid owner) throws IOException, PGPException; - - void storePublicKeyRing(BareJid owner, PGPPublicKeyRingCollection publicKeys) throws IOException; - - void storeSecretKeyRing(BareJid owner, PGPSecretKeyRingCollection secretKeys) throws IOException; - - byte[] loadPublicKeyRingBytes(BareJid owner); - - byte[] loadSecretKeyRingBytes(BareJid owner); - - void storePublicKeyRingBytes(BareJid owner, byte[] bytes); - - void storeSecretKeyRingBytes(BareJid owner, byte[] bytes); - - SecretKeyRingProtector getSecretKeyProtector(); -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BackupRestoreTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BackupRestoreTest.java deleted file mode 100644 index c9af1dd52..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BackupRestoreTest.java +++ /dev/null @@ -1,86 +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.bouncycastle; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Arrays; -import java.util.Collections; - -import org.jivesoftware.smack.util.FileUtils; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.element.SecretkeyElement; -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.SmackOpenPgpException; -import org.jivesoftware.smackx.ox.util.KeyBytesAndFingerprint; -import org.jivesoftware.smackx.ox.util.SecretKeyBackupHelper; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.jxmpp.jid.BareJid; -import org.jxmpp.jid.JidTestUtil; -import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector; - -public class BackupRestoreTest extends OxTestSuite { - - private static final File backupPath = FileUtils.getTempDir("ox-backup"); - private static final File restorePath = FileUtils.getTempDir("ox-restore"); - private static final BareJid owner = JidTestUtil.BARE_JID_1; - - - @BeforeClass - @AfterClass - public static void deletePaths() { - FileUtils.deleteDirectory(backupPath); - FileUtils.deleteDirectory(restorePath); - } - - @Test - public void test() - throws NoSuchAlgorithmException, IOException, InvalidAlgorithmParameterException, NoSuchProviderException, - SmackOpenPgpException, MissingUserIdOnKeyException, InvalidBackupCodeException, - MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException { - FileBasedPainlessOpenPgpStore backupStore = new FileBasedPainlessOpenPgpStore(backupPath, new UnprotectedKeysProtector()); - FileBasedPainlessOpenPgpStore restoreStore = new FileBasedPainlessOpenPgpStore(restorePath, new UnprotectedKeysProtector()); - - PainlessOpenPgpProvider backupProvider = new PainlessOpenPgpProvider(owner, backupStore); - PainlessOpenPgpProvider restoreProvider = new PainlessOpenPgpProvider(owner, restoreStore); - - KeyBytesAndFingerprint key = backupProvider.generateOpenPgpKeyPair(owner); - backupProvider.importSecretKey(key.getBytes()); - - final String backupCode = SecretKeyBackupHelper.generateBackupPassword(); - SecretkeyElement backup = SecretKeyBackupHelper.createSecretkeyElement(backupProvider, owner, Collections.singleton(key.getFingerprint()), backupCode); - - OpenPgpV4Fingerprint fingerprint = SecretKeyBackupHelper.restoreSecretKeyBackup(restoreProvider, backup, backupCode); - - assertEquals(key.getFingerprint(), fingerprint); - - assertTrue(Arrays.equals(backupStore.getSecretKeyRingBytes(owner, fingerprint), restoreStore.getSecretKeyRingBytes(owner, fingerprint))); - assertTrue(Arrays.equals(backupStore.getPublicKeyRingBytes(owner, fingerprint), restoreStore.getPublicKeyRingBytes(owner, fingerprint))); - } -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/DryOxEncryptionTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/DryOxEncryptionTest.java deleted file mode 100644 index 5f04798fc..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/DryOxEncryptionTest.java +++ /dev/null @@ -1,138 +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.bouncycastle; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertNotNull; -import static junit.framework.TestCase.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.jivesoftware.smack.DummyConnection; -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.packet.ExtensionElement; -import org.jivesoftware.smack.packet.Message; -import org.jivesoftware.smack.util.FileUtils; -import org.jivesoftware.smackx.ox.OpenPgpContact; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.TestKeys; -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.SigncryptElement; -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.SmackOpenPgpException; - -import org.bouncycastle.util.encoders.Base64; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.jxmpp.jid.BareJid; -import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector; -import org.pgpainless.pgpainless.util.BCUtil; -import org.xmlpull.v1.XmlPullParserException; - - -public class DryOxEncryptionTest extends OxTestSuite { - - private static final Logger LOGGER = Logger.getLogger(DryOxEncryptionTest.class.getName()); - private static final Charset UTF8 = Charset.forName("UTF-8"); - - private static final File julietPath = FileUtils.getTempDir("ox-juliet"); - private static final File romeoPath = FileUtils.getTempDir("ox-romeo"); - - @BeforeClass - @AfterClass - public static void deletePath() { - LOGGER.log(Level.INFO, "Delete paths " + julietPath.getAbsolutePath() + " " + romeoPath.getAbsolutePath()); - FileUtils.deleteDirectory(julietPath); - FileUtils.deleteDirectory(romeoPath); - } - - // @Test - public void dryEncryptionTest() - throws IOException, SmackOpenPgpException, MissingUserIdOnKeyException, MissingOpenPgpPublicKeyException, - MissingOpenPgpKeyPairException, XmlPullParserException, SmackException.NotLoggedInException { - BareJid julietJid = TestKeys.JULIET_JID; - BareJid romeoJid = TestKeys.ROMEO_JID; - - XMPPConnection julietCon = new DummyConnection(); - XMPPConnection romeoCon = new DummyConnection(); - - FileBasedPainlessOpenPgpStore julietStore = new FileBasedPainlessOpenPgpStore(julietPath, new UnprotectedKeysProtector()); - FileBasedPainlessOpenPgpStore romeoStore = new FileBasedPainlessOpenPgpStore(romeoPath, new UnprotectedKeysProtector()); - - PainlessOpenPgpProvider julietProvider = new PainlessOpenPgpProvider(julietJid, julietStore); - PainlessOpenPgpProvider romeoProvider = new PainlessOpenPgpProvider(romeoJid, romeoStore); - - OpenPgpV4Fingerprint julietFinger = julietProvider.importSecretKey(julietJid, - BCUtil.getDecodedBytes(TestKeys.JULIET_PRIV.getBytes(UTF8))); - OpenPgpV4Fingerprint romeoFinger = romeoProvider.importSecretKey(romeoJid, - BCUtil.getDecodedBytes(TestKeys.ROMEO_PRIV.getBytes(UTF8))); - - julietStore.setSigningKeyPairFingerprint(julietFinger); - romeoStore.setSigningKeyPairFingerprint(romeoFinger); - - byte[] julietPubBytes = julietStore.getPublicKeyRingBytes(julietJid, julietFinger); - byte[] romeoPubBytes = romeoStore.getPublicKeyRingBytes(romeoJid, romeoFinger); - - assertNotNull(julietPubBytes); - assertNotNull(romeoPubBytes); - assertTrue(julietPubBytes.length != 0); - assertTrue(romeoPubBytes.length != 0); - - PubkeyElement julietPub = new PubkeyElement(new PubkeyElement.PubkeyDataElement( - Base64.encode(julietStore.getPublicKeyRingBytes(julietJid, julietFinger))), - new Date()); - PubkeyElement romeoPub = new PubkeyElement(new PubkeyElement.PubkeyDataElement( - Base64.encode(romeoStore.getPublicKeyRingBytes(romeoJid, romeoFinger))), - new Date()); - - julietProvider.importPublicKey(romeoJid, Base64.decode(romeoPub.getDataElement().getB64Data())); - romeoProvider.importPublicKey(julietJid, Base64.decode(julietPub.getDataElement().getB64Data())); - - julietStore.setAnnouncedKeysFingerprints(romeoJid, Collections.singletonMap(romeoFinger, new Date())); - romeoStore.setAnnouncedKeysFingerprints(julietJid, Collections.singletonMap(julietFinger, new Date())); - - OpenPgpContact julietForRomeo = new OpenPgpContact(romeoProvider, julietJid, romeoCon); - OpenPgpContact romeoForJuliet = new OpenPgpContact(julietProvider, romeoJid, julietCon); - - String bodyText = "Finden wir eine Kompromisslösung – machen wir es so, wie ich es sage."; - List payload = Collections.singletonList(new Message.Body("de", - bodyText)); - - OpenPgpElement encrypted = romeoForJuliet.encryptAndSign(payload); - - LOGGER.log(Level.INFO, encrypted.toXML(null).toString()); - - OpenPgpContentElement decrypted = julietForRomeo.receive(encrypted); - assertTrue(decrypted instanceof SigncryptElement); - - assertEquals(1, decrypted.getExtensions().size()); - Message.Body body = (Message.Body) decrypted.getExtensions().get(0); - assertEquals(bodyText, body.getMessage()); - } -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStoreTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStoreTest.java deleted file mode 100644 index a71ae662e..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStoreTest.java +++ /dev/null @@ -1,103 +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.bouncycastle; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Arrays; -import java.util.Collections; - -import org.jivesoftware.smack.util.FileUtils; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.jxmpp.jid.BareJid; -import org.jxmpp.jid.JidTestUtil; -import org.pgpainless.pgpainless.PGPainless; -import org.pgpainless.pgpainless.key.generation.type.length.RsaLength; -import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector; -import org.pgpainless.pgpainless.util.BCUtil; - -public class FileBasedPainlessOpenPgpStoreTest extends OxTestSuite { - - private final File basePath; - private final BareJid alice; - private final BareJid bob; - - private FileBasedPainlessOpenPgpStore store; - - public FileBasedPainlessOpenPgpStoreTest() { - super(); - this.basePath = FileUtils.getTempDir("ox-filebased-store-test"); - this.alice = JidTestUtil.BARE_JID_1; - this.bob = JidTestUtil.BARE_JID_2; - } - - @After - @Before - public void deleteStore() { - FileUtils.deleteDirectory(basePath); - this.store = new FileBasedPainlessOpenPgpStore(basePath, new UnprotectedKeysProtector()); - } - - @Test - public void storeSecretKeyRingsTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPSecretKeyRing secretKey = PGPainless.generateKeyRing().simpleRsaKeyRing("xmpp:" + alice.toString(), RsaLength._3072); - PGPSecretKeyRingCollection saving = new PGPSecretKeyRingCollection(Collections.singleton(secretKey)); - store.storeSecretKeyRing(alice, saving); - - FileBasedPainlessOpenPgpStore store2 = new FileBasedPainlessOpenPgpStore(basePath, new UnprotectedKeysProtector()); - PGPSecretKeyRingCollection restored = store2.getSecretKeyRings(alice); - - assertTrue(Arrays.equals(saving.getEncoded(), restored.getEncoded())); - } - - @Test - public void storePublicKeyRingTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleRsaKeyRing("xmpp:" + alice.toString(), RsaLength._3072); - - PGPPublicKeyRing publicKeys = BCUtil.publicKeyRingFromSecretKeyRing(secretKeys); - for (PGPSecretKey k : secretKeys) { - assertEquals(publicKeys.getPublicKey(k.getKeyID()), k.getPublicKey()); - } - - PGPPublicKeyRingCollection saving = new PGPPublicKeyRingCollection(Collections.singleton(publicKeys)); - store.storePublicKeyRing(alice, saving); - - FileBasedPainlessOpenPgpStore store2 = new FileBasedPainlessOpenPgpStore(basePath, new UnprotectedKeysProtector()); - - PGPPublicKeyRingCollection restored = store2.getPublicKeyRings(alice); - assertTrue(Arrays.equals(saving.getEncoded(), restored.getEncoded())); - } -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/OxTestSuite.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/OxTestSuite.java deleted file mode 100644 index 25445e718..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/OxTestSuite.java +++ /dev/null @@ -1,33 +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.bouncycastle; - -import java.security.Security; - -import org.jivesoftware.smack.test.util.SmackTestSuite; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.BeforeClass; - -public abstract class OxTestSuite extends SmackTestSuite { - - @BeforeClass - public static void registerProvider() { - Security.removeProvider("BC"); - Security.addProvider(new BouncyCastleProvider()); - } -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/SymmetricEncryptionTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/SymmetricEncryptionTest.java deleted file mode 100644 index a026f9738..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/SymmetricEncryptionTest.java +++ /dev/null @@ -1,52 +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.bouncycastle; - -import static junit.framework.TestCase.assertTrue; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Random; - -import org.bouncycastle.openpgp.PGPDataValidationException; -import org.bouncycastle.openpgp.PGPException; -import org.junit.Test; -import org.pgpainless.pgpainless.PGPainless; -import org.pgpainless.pgpainless.algorithm.SymmetricKeyAlgorithm; - -public class SymmetricEncryptionTest extends OxTestSuite { - - @Test - public void successfulEncryptionDecryption() throws IOException, PGPException { - byte[] data = new byte[5000]; - new Random().nextBytes(data); - - byte[] encrypted = PGPainless.encryptWithPassword(data, "Password".toCharArray(), SymmetricKeyAlgorithm.AES_256); - byte[] decrypted = PGPainless.decryptWithPassword(encrypted, "Password".toCharArray()); - - assertTrue(Arrays.equals(data, decrypted)); - } - - @Test(expected = PGPDataValidationException.class) - public void failingEncryptionDecryption() throws IOException, PGPException { - byte[] data = new byte[5000]; - new Random().nextBytes(data); - - byte[] encrypted = PGPainless.encryptWithPassword(data, "Password".toCharArray(), SymmetricKeyAlgorithm.AES_256); - byte[] decrypted = PGPainless.decryptWithPassword(encrypted, "Swordfish".toCharArray()); - } -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/UserIdTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/UserIdTest.java deleted file mode 100644 index 35e9e0f7d..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/UserIdTest.java +++ /dev/null @@ -1,75 +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.bouncycastle; - -import java.io.File; -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; - -import org.jivesoftware.smack.util.FileUtils; -import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException; -import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.jxmpp.jid.BareJid; -import org.jxmpp.jid.JidTestUtil; -import org.pgpainless.pgpainless.PGPainless; -import org.pgpainless.pgpainless.key.protection.UnprotectedKeysProtector; - -public class UserIdTest extends OxTestSuite { - - private final File path; - - public UserIdTest() { - this.path = FileUtils.getTempDir("ox-user-id-test"); - } - - @After - @Before - public void deleteDir() { - FileUtils.deleteDirectory(path); - } - - @Test - public void requireUserIdOnImportTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException, SmackOpenPgpException, MissingUserIdOnKeyException { - BareJid owner = JidTestUtil.BARE_JID_1; - FileBasedPainlessOpenPgpStore store = new FileBasedPainlessOpenPgpStore(path, new UnprotectedKeysProtector()); - PainlessOpenPgpProvider provider = new PainlessOpenPgpProvider(owner, store); - PGPSecretKeyRing ownerKey = PGPainless.generateKeyRing().simpleEcKeyRing("xmpp:" + owner.toString()); - provider.importSecretKey(owner, ownerKey.getEncoded()); - } - - @Test(expected = MissingUserIdOnKeyException.class) - public void throwOnMissingUserIdTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException, SmackOpenPgpException, MissingUserIdOnKeyException { - BareJid owner = JidTestUtil.BARE_JID_1; - BareJid stranger = JidTestUtil.BARE_JID_2; - FileBasedPainlessOpenPgpStore store = new FileBasedPainlessOpenPgpStore(path, new UnprotectedKeysProtector()); - PainlessOpenPgpProvider provider = new PainlessOpenPgpProvider(owner, store); - PGPSecretKeyRing strangerKey = PGPainless.generateKeyRing().simpleEcKeyRing("xmpp:" + stranger.toString()); - provider.importSecretKey(owner, strangerKey.getEncoded()); - } -} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OXInstantMessagingManager.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OXInstantMessagingManager.java index c2198f500..1bdbe1d4d 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OXInstantMessagingManager.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OXInstantMessagingManager.java @@ -172,7 +172,7 @@ 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); + //contact.addSignedEncryptedPayloadTo(message, payload); ChatManager.getInstanceFor(connection()).chatWith(contact.getJid().asEntityBareJidIfPossible()).send(message); } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpContact.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpContact.java index 1639312bc..8f27a154e 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpContact.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpContact.java @@ -1,381 +1,51 @@ -/** - * - * 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.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.logging.Level; import java.util.logging.Logger; -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.packet.ExtensionElement; -import org.jivesoftware.smack.packet.Message; -import org.jivesoftware.smack.util.MultiMap; -import org.jivesoftware.smack.util.stringencoder.Base64; -import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement; -import org.jivesoftware.smackx.hints.element.StoreHint; -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.SigncryptElement; -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.SmackOpenPgpException; -import org.jivesoftware.smackx.ox.util.DecryptedBytesAndMetadata; -import org.jivesoftware.smackx.ox.util.PubSubDelegate; -import org.jivesoftware.smackx.pubsub.LeafNode; -import org.jivesoftware.smackx.pubsub.PubSubException; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.jxmpp.jid.BareJid; -import org.jxmpp.jid.Jid; -import org.xmlpull.v1.XmlPullParserException; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public class OpenPgpContact { - private static final Logger LOGGER = Logger.getLogger(OpenPgpContact.class.getName()); + private final Logger LOGGER; - private final BareJid jid; - protected final OpenPgpProvider cryptoProvider; - private final XMPPConnection connection; + protected final BareJid jid; + protected final OpenPgpStore store; - private Map announcedKeys = null; - private Map availableKeys = null; - private final Map unfetchableKeys = new HashMap<>(); - - /** - * Create a OpenPgpContact. - * - * @param cryptoProvider {@link OpenPgpProvider} - * @param jid {@link BareJid} of the contact - * @param connection our authenticated {@link XMPPConnection} - */ - public OpenPgpContact(OpenPgpProvider cryptoProvider, - BareJid jid, - XMPPConnection connection) { + public OpenPgpContact(BareJid jid, OpenPgpStore store) { this.jid = jid; - this.cryptoProvider = cryptoProvider; - this.connection = connection; + this.store = store; + LOGGER = Logger.getLogger(OpenPgpContact.class.getName() + ":" + jid.toString()); } - /** - * Return the {@link BareJid} of the contact. - * - * @return jid - */ public BareJid getJid() { return jid; } - /** - * Return a {@link Map} of the announced keys of the contact and their last update dates. - * - * @return announced keys - */ - public Map getAnnouncedKeys() { - if (announcedKeys == null) { - announcedKeys = cryptoProvider.getStore().getAnnouncedKeysFingerprints(getJid()); - } - return announcedKeys; + public PGPPublicKeyRingCollection getAnyPublicKeys() throws IOException, PGPException { + return store.getPublicKeysOf(jid); } - /** - * Return a {@link Map} of all locally available keys of the contact. - * - * Note: This list might contain keys which are no longer associated to the contact. - * For encryption please use {@link #getActiveKeys()} instead. - * - * @return available keys - * @throws SmackOpenPgpException if we cannot read the locally available keys for some reason - */ - public Map getAvailableKeys() throws SmackOpenPgpException { - if (availableKeys == null) { - availableKeys = cryptoProvider.getStore().getAvailableKeysFingerprints(getJid()); - } - return availableKeys; - } + public PGPPublicKeyRingCollection getAnnouncedPublicKeys() throws IOException, PGPException { + PGPPublicKeyRingCollection anyKeys = getAnyPublicKeys(); + Set announced = store.getAnnouncedFingerprintsOf(jid).keySet(); - /** - * Return a {@link Map} of all the keys which cannot be fetched and the reason why this is. - * - * @return unfetched keys - */ - public Map getUnfetchableKeys() { - return unfetchableKeys; - } + PGPPublicKeyRingCollection announcedKeysCollection = anyKeys; + for (PGPPublicKeyRing ring : anyKeys) { - /** - * Return a {@link Set} of all active keys of this contact. - * Active keys are keys which are announced, not revoked or otherwise invalidated and locally available. - * - * @return active keys. - * @throws SmackOpenPgpException if we cannot access the keys of the contact. - */ - public Set getActiveKeys() throws SmackOpenPgpException { - Set fingerprints = getAvailableKeys().keySet(); - fingerprints.retainAll(getAnnouncedKeys().keySet()); - return fingerprints; - } + OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(ring.getPublicKey()); - /** - * Fetch the metadata node to get a {@link PublicKeysListElement} and update any missing or outdated keys. - * - * @throws InterruptedException if the thread is interrupted - * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error - * @throws SmackOpenPgpException in case of an OpenPGP exception - * @throws PubSubException.NotAPubSubNodeException in case the metadata node is not a PubSub node - * @throws PubSubException.NotALeafNodeException in case the metadata node is not a {@link LeafNode} - * @throws SmackException.NotConnectedException in case we are not connected - * @throws SmackException.NoResponseException in case the server doesn't respond - */ - public void updateKeys() - throws InterruptedException, XMPPException.XMPPErrorException, SmackOpenPgpException, - PubSubException.NotAPubSubNodeException, PubSubException.NotALeafNodeException, - SmackException.NotConnectedException, SmackException.NoResponseException { - updateKeys(PubSubDelegate.fetchPubkeysList(connection, getJid())); - } - - /** - * Update any missing or outdated keys based on the given {@link PublicKeysListElement}. - * - * @param metadata {@link PublicKeysListElement} - * @throws SmackOpenPgpException in case the available keys cannot be fetched - */ - public void updateKeys(PublicKeysListElement metadata) - throws SmackOpenPgpException { - storePublishedDevices(metadata); - this.availableKeys = getAvailableKeys(); - - for (OpenPgpV4Fingerprint fingerprint : announcedKeys.keySet()) { - Date announcedDate = announcedKeys.get(fingerprint); - Date availableDate = availableKeys.get(fingerprint); - - if (availableDate == null || availableDate.before(announcedDate)) { - try { - updateKey(fingerprint); - unfetchableKeys.remove(fingerprint); - } catch (IOException | XMPPException.XMPPErrorException | SmackException | InterruptedException | - SmackOpenPgpException | MissingUserIdOnKeyException | NullPointerException e) { - LOGGER.log(Level.WARNING, "Could not update key " + fingerprint + " of " + getJid()); - unfetchableKeys.put(fingerprint, e); - } + if (!announced.contains(fingerprint)) { + announcedKeysCollection = PGPPublicKeyRingCollection.removePublicKeyRing(announcedKeysCollection, ring); } } - } - - /** - * Update the key identified by the {@code fingerprint}. - * - * @param fingerprint fingerprint of the key - * @throws InterruptedException if the thread is interrupted - * @throws XMPPException.XMPPErrorException in case of an XMPP protocol error - * @throws SmackException in case of an exception in Smack - * @throws IOException IO is dangerous - * @throws MissingUserIdOnKeyException if the key is missing a user id with the contacts jid - * @throws SmackOpenPgpException in case of an OpenPGP exception - */ - public void updateKey(OpenPgpV4Fingerprint fingerprint) - throws InterruptedException, XMPPException.XMPPErrorException, SmackException, IOException, - MissingUserIdOnKeyException, SmackOpenPgpException { - PubkeyElement pubkeyElement = PubSubDelegate.fetchPubkey(connection, getJid(), fingerprint); - if (pubkeyElement == null) { - throw new NullPointerException("Fetched pubkeyElement for key " + fingerprint + " of " + getJid() + " is null."); - } - - byte[] base64 = pubkeyElement.getDataElement().getB64Data(); - OpenPgpV4Fingerprint imported = importPublicKey(Base64.decode(base64)); - - if (!fingerprint.equals(imported)) { - // Not sure, if this can/should happen. Lets be safe and throw, even if its too late at this point. - throw new AssertionError("Fingerprint of imported key differs from expected fingerprint. " + - "Expected: " + fingerprint + " Imported: " + imported); - } - } - - /** - * Import a public key. - * - * @param data OpenPgp keys byte representation. - * @return the fingerprint of the imported key. - * @throws SmackOpenPgpException in case of an OpenPGP error - * @throws MissingUserIdOnKeyException if the key is missing a user id with the contacts jid - * @throws IOException IO is dangerous - */ - private OpenPgpV4Fingerprint importPublicKey(byte[] data) - throws SmackOpenPgpException, MissingUserIdOnKeyException, IOException { - OpenPgpV4Fingerprint fingerprint = cryptoProvider.importPublicKey(getJid(), data); - availableKeys.put(fingerprint, new Date()); - return fingerprint; - } - - /** - * Process an incoming {@link PublicKeysListElement} and store the contained {@link OpenPgpV4Fingerprint}s and - * their publication dates in local storage. - * - * @param element publicKeysListElement - * @return {@link Map} with the contents of the element - */ - public Map storePublishedDevices(PublicKeysListElement element) { - Map announcedKeys = new HashMap<>(); - - for (OpenPgpV4Fingerprint f : element.getMetadata().keySet()) { - PublicKeysListElement.PubkeyMetadataElement meta = element.getMetadata().get(f); - announcedKeys.put(meta.getV4Fingerprint(), meta.getDate()); - } - - if (!announcedKeys.equals(this.announcedKeys)) { - cryptoProvider.getStore().setAnnouncedKeysFingerprints(getJid(), announcedKeys); - this.announcedKeys = announcedKeys; - } - return announcedKeys; - } - - /** - * Get all keys to which a message sent to the contact would be encrypted to. - * Those are all active keys of the contact as well as our own active keys. - * - * @return encryption keys - * @throws SmackOpenPgpException if we cannot read the contacts keys or our own keys. - * @throws SmackException.NotLoggedInException if we are not logged in. - */ - private MultiMap getEncryptionKeys() - throws SmackOpenPgpException, SmackException.NotLoggedInException { - OpenPgpSelf self = getSelf(); - - Set contactsKeys = getActiveKeys(); - Set ourKeys = self.getActiveKeys(); - - MultiMap recipientsKeys = new MultiMap<>(); - for (OpenPgpV4Fingerprint fingerprint : contactsKeys) { - recipientsKeys.put(getJid(), fingerprint); - } - - for (OpenPgpV4Fingerprint fingerprint : ourKeys) { - recipientsKeys.put(self.getJid(), fingerprint); - } - - return recipientsKeys; - } - - /** - * Get our OpenPgpSelf. - * The {@link OpenPgpSelf} contains all our fingerprints. - * - * @return openPgpSelf - * @throws SmackException.NotLoggedInException - */ - private OpenPgpSelf getSelf() throws SmackException.NotLoggedInException { - return OpenPgpManager.getInstanceFor(connection).getOpenPgpSelf(); - } - - /** - * Encrypt a message to a contact and ourselves and sign it with our signing key. - * The payload will be wrapped in a {@link SigncryptElement} before encryption. - * - * @param payload the payload we want to encrypt. - * @return {@link OpenPgpElement} containing the encrypted, signed {@link SigncryptElement}. - * @throws IOException IO is dangerous - * @throws SmackOpenPgpException OpenPgp is brittle - * @throws MissingOpenPgpKeyPairException if we cannot read our signing key pair - * @throws SmackException.NotLoggedInException if we are not logged in. - */ - public OpenPgpElement encryptAndSign(List payload) - throws IOException, SmackOpenPgpException, MissingOpenPgpKeyPairException, - SmackException.NotLoggedInException { - - OpenPgpSelf self = OpenPgpManager.getInstanceFor(connection).getOpenPgpSelf(); - - SigncryptElement preparedPayload = new SigncryptElement( - Collections.singleton(getJid()), - payload); - - byte[] encryptedBytes; - - // Encrypt the payload - try { - encryptedBytes = cryptoProvider.signAndEncrypt( - preparedPayload, - self.getSigningKey(), - getEncryptionKeys()); - } catch (MissingOpenPgpPublicKeyException e) { - throw new AssertionError("Missing OpenPGP public key, even though this should not happen here.", e); - } - - return new OpenPgpElement(Base64.encodeToString(encryptedBytes)); - } - - /** - * Create a signed and encrypted {@link SigncryptElement} containing the {@code payload} and append it as a - * {@link OpenPgpElement} to the {@code message}. - * - * @param message {@link Message} which will transport the payload. - * @param payload payload that will be encrypted and signed. - * @throws IOException IO is dangerous. - * @throws SmackOpenPgpException OpenPGP is brittle. - * @throws MissingOpenPgpKeyPairException if we cannot access our signing key. - * @throws SmackException.NotLoggedInException if we are not logged in. - */ - public void addSignedEncryptedPayloadTo(Message message, List payload) - throws IOException, SmackOpenPgpException, MissingOpenPgpKeyPairException, - SmackException.NotLoggedInException { - - // Add encrypted payload to message - OpenPgpElement encryptedPayload = encryptAndSign(payload); - message.addExtension(encryptedPayload); - - // Add additional information to the message - if (!ExplicitMessageEncryptionElement.hasProtocol(message, - ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0)) { - message.addExtension(new ExplicitMessageEncryptionElement( - ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0)); - } - StoreHint.set(message); - message.setBody("This message is encrypted using XEP-0374: OpenPGP for XMPP: Instant Messaging."); - - } - - /** - * Process an incoming {@link OpenPgpElement} and return the decrypted and verified {@link OpenPgpContentElement}. - * - * @param element possibly encrypted, possibly signed {@link OpenPgpElement}. - * @return decrypted {@link OpenPgpContentElement} - * @throws XmlPullParserException if the decrypted message does not represent valid XML. - * @throws MissingOpenPgpKeyPairException if we are missing the public key counterpart of the key that signed the message. - * @throws SmackOpenPgpException if the message cannot be decrypted and or verified. - * @throws IOException IO is dangerous - */ - public OpenPgpContentElement receive(OpenPgpElement element) - throws XmlPullParserException, MissingOpenPgpKeyPairException, SmackOpenPgpException, IOException { - byte[] decoded = Base64.decode(element.getEncryptedBase64MessageContent()); - - DecryptedBytesAndMetadata decryptedBytes = cryptoProvider.decrypt(decoded, getJid(), null); - - OpenPgpMessage openPgpMessage = new OpenPgpMessage(decryptedBytes.getBytes(), - new OpenPgpMessage.Metadata(decryptedBytes.getDecryptionKey(), - decryptedBytes.getVerifiedSignatures())); - - return openPgpMessage.getOpenPgpContentElement(); + return announcedKeysCollection; } } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java index 33a20c0b7..b15693e76 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java @@ -18,7 +18,6 @@ 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; @@ -49,16 +48,14 @@ 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.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; @@ -66,11 +63,10 @@ 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; -import org.jivesoftware.smackx.ox.util.KeyBytesAndFingerprint; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore; import org.jivesoftware.smackx.ox.util.PubSubDelegate; import org.jivesoftware.smackx.ox.util.SecretKeyBackupHelper; import org.jivesoftware.smackx.pep.PEPListener; -import org.jivesoftware.smackx.pep.PEPManager; import org.jivesoftware.smackx.pubsub.EventElement; import org.jivesoftware.smackx.pubsub.ItemsExtension; import org.jivesoftware.smackx.pubsub.LeafNode; @@ -78,9 +74,11 @@ import org.jivesoftware.smackx.pubsub.PayloadItem; import org.jivesoftware.smackx.pubsub.PubSubException; import org.jivesoftware.smackx.pubsub.PubSubFeature; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.EntityBareJid; -import org.xmlpull.v1.XmlPullParserException; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public final class OpenPgpManager extends Manager { @@ -96,6 +94,8 @@ public final class OpenPgpManager extends Manager { */ private OpenPgpProvider provider; + private OpenPgpStore store; + private final Map openPgpCapableContacts = new HashMap<>(); private final Set signcryptElementReceivedListeners = new HashSet<>(); @@ -129,6 +129,11 @@ public final class OpenPgpManager extends Manager { return manager; } + public BareJid getJidOrThrow() throws SmackException.NotLoggedInException { + throwIfNotAuthenticated(); + return connection().getUser().asEntityBareJidOrThrow(); + } + /** * Set the {@link OpenPgpProvider} which will be used to process incoming OpenPGP elements, * as well as to execute cryptographic operations. @@ -146,10 +151,8 @@ public final class OpenPgpManager extends Manager { * @throws SmackException.NotLoggedInException if we are not logged in */ public OpenPgpSelf getOpenPgpSelf() throws SmackException.NotLoggedInException { - throwIfNotAuthenticated(); - if (self == null) { - self = new OpenPgpSelf(provider, connection().getUser().asBareJid(), connection()); + self = new OpenPgpSelf(getJidOrThrow(), store); } return self; @@ -182,25 +185,25 @@ public final class OpenPgpManager extends Manager { BareJid ourJid = connection().getUser().asBareJid(); - OpenPgpV4Fingerprint primaryFingerprint = getOurFingerprint(); + // OpenPgpV4Fingerprint primaryFingerprint = getOurFingerprint(); - if (primaryFingerprint == null) { - primaryFingerprint = generateAndImportKeyPair(ourJid); - } + // if (primaryFingerprint == null) { + // primaryFingerprint = generateAndImportKeyPair(ourJid); + // } // Create 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(ourJid, 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); + // PEPManager.getInstanceFor(connection()).addPEPListener(metadataListener); ServiceDiscoveryManager.getInstanceFor(connection()) .addFeature(PEP_NODE_PUBLIC_KEYS_NOTIFY); } @@ -211,25 +214,23 @@ public final class OpenPgpManager extends Manager { * @param ourJid our {@link BareJid}. * @return {@link OpenPgpV4Fingerprint} of the generated key. * @throws NoSuchAlgorithmException if the JVM doesn't support one of the used algorithms. - * @throws IOException IO is dangerous. * @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, IOException, InvalidAlgorithmParameterException, NoSuchProviderException, - SmackOpenPgpException { - KeyBytesAndFingerprint bytesAndFingerprint = provider.generateOpenPgpKeyPair(ourJid); - OpenPgpV4Fingerprint fingerprint = bytesAndFingerprint.getFingerprint(); + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException, + SmackOpenPgpException, PGPException { - // This should never throw, since we set our jid literally one line above this comment. - try { - provider.importSecretKey(ourJid, bytesAndFingerprint.getBytes()); - } catch (MissingUserIdOnKeyException e) { - throw new AssertionError(e); - } + PGPSecretKeyRing keyPair = store.generateKeyRing(ourJid); + // try { + // provider.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); + // } - return fingerprint; + return new OpenPgpV4Fingerprint(keyPair); } /** @@ -237,9 +238,9 @@ public final class OpenPgpManager extends Manager { * * @return fingerprint. */ - public OpenPgpV4Fingerprint getOurFingerprint() { - throwIfNoProviderSet(); - return provider.getStore().getSigningKeyPairFingerprint(); + public OpenPgpV4Fingerprint getOurFingerprint() + throws SmackException.NotLoggedInException, IOException, PGPException { + return getOpenPgpSelf().getSigningKeyFingerprint(); } /** @@ -250,15 +251,7 @@ public final class OpenPgpManager extends Manager { * @return {@link OpenPgpContact}. */ public OpenPgpContact getOpenPgpContact(EntityBareJid jid) { - - OpenPgpContact openPgpContact = openPgpCapableContacts.get(jid); - - if (openPgpContact == null) { - openPgpContact = new OpenPgpContact(provider, jid, connection()); - openPgpCapableContacts.put(jid, openPgpContact); - } - - return openPgpContact; + return store.getOpenPgpContact(jid); } @@ -311,13 +304,13 @@ public final class OpenPgpManager extends Manager { BareJid ownJid = connection().getUser().asBareJid(); String backupCode = SecretKeyBackupHelper.generateBackupPassword(); - Set availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(ownJid); - Set selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs); + // Set availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(ownJid); + // Set selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs); - SecretkeyElement secretKey = SecretKeyBackupHelper.createSecretkeyElement(provider, ownJid, selectedKeyPairs, backupCode); + // SecretkeyElement secretKey = SecretKeyBackupHelper.createSecretkeyElement(provider, ownJid, selectedKeyPairs, backupCode); - PubSubDelegate.depositSecretKey(connection(), secretKey); - displayCodeCallback.displayBackupCode(backupCode); + // PubSubDelegate.depositSecretKey(connection(), secretKey); + // displayCodeCallback.displayBackupCode(backupCode); } /** @@ -401,19 +394,21 @@ 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); } + */ } 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 @@ -457,6 +452,7 @@ public final class OpenPgpManager extends Manager { else { throw new AssertionError("Invalid element received: " + contentElement.getClass().getName()); } + */ } }; @@ -477,7 +473,7 @@ public final class OpenPgpManager extends Manager { private void processPublicKey(PubkeyElement pubkeyElement, BareJid owner) throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException { byte[] base64 = pubkeyElement.getDataElement().getB64Data(); - provider.importPublicKey(owner, Base64.decode(base64)); + // provider.importPublicKey(owner, Base64.decode(base64)); } /** @@ -495,8 +491,9 @@ public final class OpenPgpManager extends Manager { OpenPgpV4Fingerprint fingerprint, Date date) throws MissingOpenPgpPublicKeyException { - byte[] keyBytes = provider.getStore().getPublicKeyRingBytes(owner, fingerprint); - return createPubkeyElement(keyBytes, date); + // byte[] keyBytes = provider.getStore().getPublicKeyRingBytes(owner, fingerprint); + // return createPubkeyElement(keyBytes, date); + return null; } /** diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpMessage.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpMessage.java index 7f9870604..b2bcc098e 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpMessage.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpMessage.java @@ -29,6 +29,7 @@ import org.jivesoftware.smackx.ox.element.SignElement; import org.jivesoftware.smackx.ox.element.SigncryptElement; import org.jivesoftware.smackx.ox.provider.OpenPgpContentElementProvider; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; import org.xmlpull.v1.XmlPullParserException; /** @@ -133,31 +134,31 @@ public class OpenPgpMessage { public static class Metadata { - private final Long encryptionKeyId; - private final Set validSignatureIds; + private final OpenPgpV4Fingerprint decryptionFingerprint; + private final Set validSignatureFingerprints; - public Metadata(Long encryptionKeyId, Set validSignatureIds) { - this.encryptionKeyId = encryptionKeyId; - this.validSignatureIds = validSignatureIds; + public Metadata(OpenPgpV4Fingerprint decryptionFingerprint, Set validSignatureFingerprints) { + this.decryptionFingerprint = decryptionFingerprint; + this.validSignatureFingerprints = validSignatureFingerprints; } - public Long getEncryptionKeyId() { - return encryptionKeyId; + public OpenPgpV4Fingerprint getDecryptionFingerprint() { + return decryptionFingerprint; } - public Set getValidSignatureIds() { - return new HashSet<>(validSignatureIds); + public Set getValidSignatureFingerprints() { + return new HashSet<>(validSignatureFingerprints); } public State getState() { - if (validSignatureIds.size() != 0) { - if (encryptionKeyId != null) { + if (validSignatureFingerprints.size() != 0) { + if (decryptionFingerprint != null) { return State.signcrypt; } else { return State.sign; } } else { - if (encryptionKeyId != null) { + if (decryptionFingerprint != null) { return State.crypt; } else { throw new IllegalStateException("OpenPGP message appears to be neither encrypted, " + diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpProvider.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpProvider.java deleted file mode 100644 index 69dfcdd9f..000000000 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpProvider.java +++ /dev/null @@ -1,216 +0,0 @@ -/** - * - * Copyright 2017 Florian Schmaus. - * - * 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.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; - -import org.jivesoftware.smack.util.MultiMap; -import org.jivesoftware.smackx.ox.callback.backup.SmackMissingOpenPgpPublicKeyCallback; -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.SignElement; -import org.jivesoftware.smackx.ox.element.SigncryptElement; -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.SmackOpenPgpException; -import org.jivesoftware.smackx.ox.util.DecryptedBytesAndMetadata; -import org.jivesoftware.smackx.ox.util.KeyBytesAndFingerprint; - -import org.jxmpp.jid.BareJid; - -public interface OpenPgpProvider { - - /** - * Sign and encrypt a {@link SigncryptElement} element for usage within the context of instant messaging. - * The resulting byte array can be decrypted by each recipient, as well as all devices of the user. - * The message contains a signature made by our key. - * - * @see XEP-0373 §3 - * @see XEP-0374 §2.1 - * - * @param element {@link SigncryptElement} which contains the content of the message as plaintext. - * @param signingKey {@link OpenPgpV4Fingerprint} of the signing key. - * @param encryptionKeys {@link MultiMap} containing all {@link OpenPgpV4Fingerprint}s of recipients which will - * be able to decrypt the message. - * @return encrypted and signed data which contains the encrypted, encoded message. - * - * @throws MissingOpenPgpKeyPairException if the OpenPGP key pair with the given {@link OpenPgpV4Fingerprint} - * is not available. - * @throws MissingOpenPgpPublicKeyException if any of the OpenPGP public keys whose {@link OpenPgpV4Fingerprint} - * is listed in {@code encryptionKeys} is not available. - * @throws SmackOpenPgpException in case of an OpenPGP error - * @throws IOException IO is dangerous - */ - byte[] signAndEncrypt(SigncryptElement element, - OpenPgpV4Fingerprint signingKey, - MultiMap encryptionKeys) - throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException, SmackOpenPgpException, IOException; - - /** - * Sign a {@link SignElement} with the users signing key. - * The resulting byte array contains the signed byte representation of the {@link SignElement}. - * - * @see XEP-0373 §3.1 - * @see XEP-0374 §2.1 - * - * @param element {@link SignElement} which will be signed. - * @param singingKeyFingerprint {@link OpenPgpV4Fingerprint} of the key that is used for signing. - * @return byte array which contains the signed {@link SignElement}. - * - * @throws MissingOpenPgpKeyPairException if we don't have the key pair for the - * {@link OpenPgpV4Fingerprint} available. - * @throws IOException IO is dangerous - * @throws SmackOpenPgpException in case of an OpenPGP error - */ - byte[] sign(SignElement element, OpenPgpV4Fingerprint singingKeyFingerprint) - throws MissingOpenPgpKeyPairException, IOException, SmackOpenPgpException; - - /** - * Encrypt a {@link CryptElement} for all keys which fingerprints are contained in - * {@code encryptionKeyFingerprints}. - * The resulting byte array contains the encrypted {@link CryptElement} - * which can be decrypted by all recipients, as well as by ourselves. - *
- * Note: DO NOT use this method in the context of instant messaging, as XEP-0374 forbids that. - * - * @see XEP-0374 §2.1 - * - * @param element plaintext {@link CryptElement} which will be encrypted. - * @param encryptionKeyFingerprints {@link MultiMap} of recipients and {@link OpenPgpV4Fingerprint}s of the - * keys which are used for encryption. - * @return byte array which contains the encrypted {@link CryptElement}. - * @throws MissingOpenPgpPublicKeyException if any of the OpenPGP public keys whose - * {@link OpenPgpV4Fingerprint} is listed in {@code encryptionKeys} - * is not available. - * @throws IOException IO is dangerous - * @throws SmackOpenPgpException in case of an OpenPGP error - */ - byte[] encrypt(CryptElement element, MultiMap encryptionKeyFingerprints) - throws MissingOpenPgpPublicKeyException, IOException, SmackOpenPgpException; - - /** - * Process an incoming {@link OpenPgpElement}. - * If its content is encrypted ({@link CryptElement} or {@link SigncryptElement}), the content will be decrypted. - * If its content is signed ({@link SignElement} or {@link SigncryptElement}), signatures are verified using - * the announced public keys of the sender. - * The resulting byte array will contain the decrypted {@link OpenPgpContentElement}. - * - * @see XEP-0373 §3.1 - * - * @param bytes byte array which contains the encrypted {@link OpenPgpContentElement}. - * @param sender sender of the message - * @param missingPublicKeyCallback callback to handle missing public keys - * @return byte array which contains the decrypted {@link OpenPgpContentElement}, as well as metadata. - * - * @throws MissingOpenPgpKeyPairException if we don't have an OpenPGP key pair available that to decrypt - * the message. - * @throws SmackOpenPgpException in case of an OpenPGP error - */ - DecryptedBytesAndMetadata decrypt(byte[] bytes, BareJid sender, SmackMissingOpenPgpPublicKeyCallback missingPublicKeyCallback) - throws MissingOpenPgpKeyPairException, SmackOpenPgpException; - - /** - * Encrypt some data symmetrically using a password. - * @param bytes data - * @param password password - * @return encrypted data - * @throws SmackOpenPgpException in case of an OpenPGP error - * @throws IOException IO is dangerous - */ - byte[] symmetricallyEncryptWithPassword(byte[] bytes, String password) throws SmackOpenPgpException, IOException; - - /** - * Decrypt a symmetrically encrypted array of data using the provided password. - * - * @param bytes symmetrically encrypted data - * @param password password for decryption - * @return decrypted data - * @throws SmackOpenPgpException if the password is incorrect - * @throws IOException io is dangerous - */ - byte[] symmetricallyDecryptWithPassword(byte[] bytes, String password) throws SmackOpenPgpException, IOException; - - /** - * Generate a fresh OpenPGP key pair. - * - * @param owner JID of the keys owner. - * @return byte array representation + {@link OpenPgpV4Fingerprint} of the generated key pair. - * @throws SmackOpenPgpException in case of an OpenPGP error - * @throws InvalidAlgorithmParameterException if invalid algorithm parameters are used for crypto - * @throws NoSuchAlgorithmException if the JVM is lacking support for a used algorithm - * @throws NoSuchProviderException if the JVM is missing a security provider - * @throws IOException IO is dangerous - */ - KeyBytesAndFingerprint generateOpenPgpKeyPair(BareJid owner) - throws SmackOpenPgpException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, - NoSuchProviderException, IOException; - - /** - * Import a public key. The bytes are expected to be decoded from base64. - * - * @param owner owner of the public key - * @param bytes byte representation of the publick key - * - * @return fingerprint of the imported public key - * - * @throws MissingUserIdOnKeyException if the key is missing a user id with {@code owner}. - * @throws IOException IO is dangerous - * @throws SmackOpenPgpException if an OpenPGP error occurs - */ - OpenPgpV4Fingerprint importPublicKey(BareJid owner, byte[] bytes) - throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException; - - /** - * Import a secret key. The bytes are expected to be decoded from base64. - * - * @param owner owner of the secret key - * @param bytes byte representation of the secret key - * - * @return fingerprint of the imported secret key - * - * @throws MissingUserIdOnKeyException if the key is missing a user-id of {@code owner} - * @throws SmackOpenPgpException in case of an OpenPGP error - * @throws IOException IO is dangerous - */ - OpenPgpV4Fingerprint importSecretKey(BareJid owner, byte[] bytes) - throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException; - - /** - * Import a secret key that belong to ourselves. - * - * @param bytes byte representation of the secret key. - * - * @return fingerprint of the imported secret key. - * - * @throws MissingUserIdOnKeyException if the secret key is missing a user-id with our jid - * @throws SmackOpenPgpException in case of an OpenPGP error - * @throws IOException IO is dangerous - */ - OpenPgpV4Fingerprint importSecretKey(byte[] bytes) - throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException; - - /** - * Return the underlying {@link OpenPgpStore}. - * @return store - */ - OpenPgpStore getStore(); -} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpSelf.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpSelf.java index bbbdfa9fe..ad5502c37 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpSelf.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpSelf.java @@ -1,32 +1,52 @@ -/** - * - * 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 org.jivesoftware.smack.XMPPConnection; +import java.io.IOException; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public class OpenPgpSelf extends OpenPgpContact { - public OpenPgpSelf(OpenPgpProvider cryptoProvider, BareJid jid, XMPPConnection connection) { - super(cryptoProvider, jid, connection); + public OpenPgpSelf(BareJid jid, OpenPgpStore store) { + super(jid, store); } - public OpenPgpV4Fingerprint getSigningKey() { - return cryptoProvider.getStore().getSigningKeyPairFingerprint(); + public boolean hasSecretKeyAvailable() throws IOException, PGPException { + return getSecretKeys() != null; + } + + public PGPSecretKeyRingCollection getSecretKeys() throws IOException, PGPException { + return store.getSecretKeysOf(jid); + } + + public PGPSecretKeyRing getSigningKeyRing() throws IOException, PGPException { + PGPSecretKeyRingCollection secretKeyRings = getSecretKeys(); + if (secretKeyRings == null) { + return null; + } + + PGPSecretKeyRing signingKeyRing = null; + for (PGPSecretKeyRing ring : secretKeyRings) { + if (signingKeyRing == null) { + signingKeyRing = ring; + continue; + } + + if (ring.getPublicKey().getCreationTime().after(signingKeyRing.getPublicKey().getCreationTime())) { + signingKeyRing = ring; + } + } + + return signingKeyRing; + } + + public OpenPgpV4Fingerprint getSigningKeyFingerprint() throws IOException, PGPException { + PGPSecretKeyRing signingKeyRing = getSigningKeyRing(); + return signingKeyRing != null ? new OpenPgpV4Fingerprint(signingKeyRing.getPublicKey()) : null; } } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpStore.java deleted file mode 100644 index ecabcd5a4..000000000 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpStore.java +++ /dev/null @@ -1,147 +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; - -import java.util.Date; -import java.util.Map; -import java.util.Set; - -import org.jivesoftware.smack.util.MultiMap; -import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException; -import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException; -import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException; - -import org.jxmpp.jid.BareJid; - -public interface OpenPgpStore { - - /** - * Return the {@link OpenPgpV4Fingerprint} of the primary OpenPGP key pair. - * If multiple key pairs are available, only the primary key pair is used for signing. - *
- * Note: This method returns {@code null} if no key pair is available. - * - * @return fingerprint of the primary OpenPGP key pair. - */ - OpenPgpV4Fingerprint getSigningKeyPairFingerprint(); - - /** - * Set the {@link OpenPgpV4Fingerprint} of the primary OpenPGP key pair. - * If multiple key pairs are available, only the primary key pair is used for signing. - * - * @param fingerprint {@link OpenPgpV4Fingerprint} of the new primary key pair. - */ - void setSigningKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint); - - /** - * Return a {@link Set} containing the {@link OpenPgpV4Fingerprint}s of the master keys of all available - * OpenPGP key pairs of {@code owner}. - * - * @param owner owner. - * @return set of fingerprints of available OpenPGP key pairs master keys. - * - * @throws SmackOpenPgpException in case of an OpenPGP error - */ - Set getAvailableKeyPairFingerprints(BareJid owner) throws SmackOpenPgpException; - - /** - * Return a {@link Map} containing the {@link OpenPgpV4Fingerprint}s of all OpenPGP public keys of a - * contact, which we have locally available, as well as the date, those keys had been published on. - *
- * Note: This returns a {@link Map} that might be different from the result of (BareJid)}. - * Messages should be encrypted to the intersection of both key sets. - * - * @param contact contact. - * @return list of contacts locally available public keys. - * - * @throws SmackOpenPgpException if something goes wrong - */ - Map getAvailableKeysFingerprints(BareJid contact) - throws SmackOpenPgpException; - - /** - * Return a {@link Map} containing the {@link OpenPgpV4Fingerprint}s of all currently announced OpenPGP - * public keys of a contact along with the dates of their latest revision. - *
- * Note: Those are the keys announced in the latest received metadata update. - * This returns a {@link Map} which might contain different {@link OpenPgpV4Fingerprint}s than the result of - * {@link #getAvailableKeysFingerprints(BareJid)} (BareJid)}. - * Messages should be encrypted to the intersection of both key sets. - * - * @param contact contact. - * @return map of contacts last announced public keys and their update dates. - */ - Map getAnnouncedKeysFingerprints(BareJid contact); - - /** - * Store a {@link Map} of a contacts fingerprints and publication dates in persistent storage. - * - * @param contact {@link BareJid} of the owner of the announced public keys. - * @param fingerprints {@link Map} which contains a list of the keys of {@code owner}. - */ - void setAnnouncedKeysFingerprints(BareJid contact, Map fingerprints); - - /** - * Return the a {@link Map} of {@link OpenPgpV4Fingerprint}s and the {@link Date}s of when they were last - * fetched from PubSub. - * - * @param owner owner of the keys - * @return {@link Map} of keys last revision dates. - */ - Map getPubkeysLastRevisions(BareJid owner); - - /** - * Set the last revision dates of all keys of a contact. - * - * @param owner owner of the keys - * @param revisionDates {@link Map} of {@link OpenPgpV4Fingerprint}s and the {@link Date}s of when they - * were last fetched from PubSub. - */ - void setPubkeysLastRevision(BareJid owner, Map revisionDates); - - /** - * Return a {@link MultiMap} which contains contacts and their trusted keys {@link OpenPgpV4Fingerprint}s. - * - * @return trusted fingerprints. - */ - MultiMap getAllContactsTrustedFingerprints(); - - /** - * Return the byte array representation of {@code owner}s public key ring with fingerprint {@code fingerprint}. - * - * @param owner owner of the key - * @param fingerprint fingerprint of the key - * @return byte representation of the public key. - * - * @throws MissingOpenPgpPublicKeyException if the key does not exist. - */ - byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) - throws MissingOpenPgpPublicKeyException; - - /** - * Return the byte array representation of {@code owner}s secret key ring with fingerprint {@code fingerprint}. - * - * @param owner owner of the key - * @param fingerprint fingerprint of the key - * @return byte representation of the secret key. - * - * @throws MissingOpenPgpKeyPairException if the secret key doesn't exist. - */ - byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) - throws MissingOpenPgpKeyPairException; - -} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/SecretKeyPassphraseCallback.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/SecretKeyPassphraseCallback.java index a4c6ec154..a94db2fac 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/SecretKeyPassphraseCallback.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/SecretKeyPassphraseCallback.java @@ -16,7 +16,7 @@ */ package org.jivesoftware.smackx.ox.callback; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public interface SecretKeyPassphraseCallback { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/SecretKeyBackupSelectionCallback.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/SecretKeyBackupSelectionCallback.java index 13ca496cd..a6a53abe5 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/SecretKeyBackupSelectionCallback.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/SecretKeyBackupSelectionCallback.java @@ -18,7 +18,7 @@ package org.jivesoftware.smackx.ox.callback.backup; import java.util.Set; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; /** * Callback to allow the user to decide, which locally available secret keys they want to include in a backup. diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/SecretKeyRestoreSelectionCallback.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/SecretKeyRestoreSelectionCallback.java index 13f8e224a..2d81d7e9d 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/SecretKeyRestoreSelectionCallback.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/backup/SecretKeyRestoreSelectionCallback.java @@ -18,7 +18,7 @@ package org.jivesoftware.smackx.ox.callback.backup; import java.util.Set; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; /** * Callback to let the user decide which key from a backup they want to restore. diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpProvider.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/crypto/OpenPgpProvider.java similarity index 70% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpProvider.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/crypto/OpenPgpProvider.java index 3bd6a1188..2a96278e5 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpProvider.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/crypto/OpenPgpProvider.java @@ -14,12 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2; +package org.jivesoftware.smackx.ox.crypto; import java.io.IOException; import java.util.Collection; +import org.jivesoftware.smackx.ox.OpenPgpContact; import org.jivesoftware.smackx.ox.OpenPgpMessage; +import org.jivesoftware.smackx.ox.OpenPgpSelf; import org.jivesoftware.smackx.ox.element.CryptElement; import org.jivesoftware.smackx.ox.element.OpenPgpElement; import org.jivesoftware.smackx.ox.element.SignElement; @@ -29,11 +31,15 @@ import org.bouncycastle.openpgp.PGPException; public interface OpenPgpProvider { - OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection recipients) throws IOException, PGPException; + OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection recipients) + throws IOException, PGPException; - OpenPgpElement sign(SignElement element, OpenPgpSelf self) throws IOException, PGPException; + OpenPgpElement sign(SignElement element, OpenPgpSelf self) + throws IOException, PGPException; - OpenPgpElement encrypt(CryptElement element, OpenPgpSelf self, Collection recipients) throws IOException, PGPException; + OpenPgpElement encrypt(CryptElement element, OpenPgpSelf self, Collection recipients) + throws IOException, PGPException; - OpenPgpMessage decryptAndOrVerify(OpenPgpElement element, OpenPgpSelf self, OpenPgpContact sender) throws IOException, PGPException; + OpenPgpMessage decryptAndOrVerify(OpenPgpElement element, OpenPgpSelf self, OpenPgpContact sender) + throws IOException, PGPException; } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/PainlessOpenPgpProvider.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/crypto/PainlessOpenPgpProvider.java similarity index 95% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/PainlessOpenPgpProvider.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/crypto/PainlessOpenPgpProvider.java index 467ed70c4..4cf0263eb 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/PainlessOpenPgpProvider.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/crypto/PainlessOpenPgpProvider.java @@ -1,4 +1,4 @@ -package org.jivesoftware.smackx.ox.v2; +package org.jivesoftware.smackx.ox.crypto; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -7,7 +7,9 @@ import java.util.ArrayList; import java.util.Collection; import org.jivesoftware.smack.util.stringencoder.Base64; +import org.jivesoftware.smackx.ox.OpenPgpContact; import org.jivesoftware.smackx.ox.OpenPgpMessage; +import org.jivesoftware.smackx.ox.OpenPgpSelf; import org.jivesoftware.smackx.ox.element.CryptElement; import org.jivesoftware.smackx.ox.element.OpenPgpElement; import org.jivesoftware.smackx.ox.element.SignElement; @@ -122,6 +124,6 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider { PainlessResult info = cipherStream.getResult(); return new OpenPgpMessage(plainText.toByteArray(), new OpenPgpMessage.Metadata( - info.getDecryptionKeyId(), info.getVerifiedSignatureKeyIds())); + info.getDecryptionFingerprint(), info.getVerifiedSignaturesFingerprints())); } } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/PublicKeysListElement.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/PublicKeysListElement.java index 21b2cc072..b2e2792ac 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/PublicKeysListElement.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/element/PublicKeysListElement.java @@ -25,7 +25,8 @@ import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.NamedElement; import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.XmlStringBuilder; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; + +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public final class PublicKeysListElement implements ExtensionElement { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingOpenPgpKeyPairException.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingOpenPgpKeyPairException.java index d2f6b290a..9b1daf3cc 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingOpenPgpKeyPairException.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingOpenPgpKeyPairException.java @@ -16,9 +16,8 @@ */ package org.jivesoftware.smackx.ox.exception; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; /** * Exception that gets thrown whenever an operation is missing an OpenPGP key pair. diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingOpenPgpPublicKeyException.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingOpenPgpPublicKeyException.java index 08ed5bf3f..ac29d878c 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingOpenPgpPublicKeyException.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingOpenPgpPublicKeyException.java @@ -16,9 +16,8 @@ */ package org.jivesoftware.smackx.ox.exception; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; /** * Exception that gets thrown when an operation is missing an OpenPGP public key. diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/provider/PublicKeysListElementProvider.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/provider/PublicKeysListElementProvider.java index c34d97b17..ae2c16e12 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/provider/PublicKeysListElementProvider.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/provider/PublicKeysListElementProvider.java @@ -22,10 +22,10 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import java.util.Date; import org.jivesoftware.smack.provider.ExtensionElementProvider; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; import org.jivesoftware.smackx.ox.element.PublicKeysListElement; import org.jxmpp.util.XmppDateTime; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; import org.xmlpull.v1.XmlPullParser; public final class PublicKeysListElementProvider extends ExtensionElementProvider { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpKeyStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpKeyStore.java similarity index 95% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpKeyStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpKeyStore.java index 2a2018dc4..c045c9eaa 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpKeyStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpKeyStore.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.abstr; +package org.jivesoftware.smackx.ox.store.abstr; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; @@ -23,8 +23,7 @@ import java.security.NoSuchProviderException; import java.util.HashMap; import java.util.Map; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpKeyStore; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpKeyStore; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; @@ -33,6 +32,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.jxmpp.jid.BareJid; import org.pgpainless.pgpainless.PGPainless; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.pgpainless.key.generation.type.length.RsaLength; public abstract class AbstractOpenPgpKeyStore implements OpenPgpKeyStore { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpMetadataStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpMetadataStore.java similarity index 91% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpMetadataStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpMetadataStore.java index 396f702e3..7a877002a 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpMetadataStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpMetadataStore.java @@ -14,17 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.abstr; +package org.jivesoftware.smackx.ox.store.abstr; import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Map; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpMetadataStore; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpMetadataStore; import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public abstract class AbstractOpenPgpMetadataStore implements OpenPgpMetadataStore { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpStore.java similarity index 90% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpStore.java index 3c8a23320..a7e1299ff 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpStore.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.abstr; +package org.jivesoftware.smackx.ox.store.abstr; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; @@ -27,12 +27,11 @@ import java.util.Observable; import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smackx.ox.OpenPgpContact; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback; -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpKeyStore; -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpMetadataStore; -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpStore; -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpTrustStore; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpKeyStore; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpMetadataStore; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; @@ -40,6 +39,7 @@ import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.pgpainless.key.protection.SecretKeyRingProtector; public abstract class AbstractOpenPgpStore extends Observable implements OpenPgpStore { @@ -76,6 +76,11 @@ public abstract class AbstractOpenPgpStore extends Observable implements OpenPgp this.unlocker = protector; } + @Override + public SecretKeyRingProtector getKeyRingProtector() { + return unlocker; + } + @Override public void setSecretKeyPassphraseCallback(SecretKeyPassphraseCallback callback) { this.secretKeyPassphraseCallback = callback; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpTrustStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpTrustStore.java similarity index 89% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpTrustStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpTrustStore.java index 32e5e5c59..ea953669d 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/abstr/AbstractOpenPgpTrustStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/AbstractOpenPgpTrustStore.java @@ -1,13 +1,13 @@ -package org.jivesoftware.smackx.ox.v2.store.abstr; +package org.jivesoftware.smackx.ox.store.abstr; import java.io.IOException; import java.util.HashMap; import java.util.Map; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpTrustStore; +import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore; import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public abstract class AbstractOpenPgpTrustStore implements OpenPgpTrustStore { diff --git a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/package-info.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/package-info.java similarity index 84% rename from smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/package-info.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/package-info.java index a251c0154..4dc7507e2 100644 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/package-info.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/abstr/package-info.java @@ -15,6 +15,6 @@ * limitations under the License. */ /** - * Providers for XEP-0373: OpenPGP for XMPP using Bouncycastle. + * Abstract OpenPGP store implementations. */ -package org.jivesoftware.smackx.ox.bouncycastle; +package org.jivesoftware.smackx.ox.store.abstr; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpKeyStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpKeyStore.java similarity index 93% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpKeyStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpKeyStore.java index 592a928e5..20c004afd 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpKeyStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpKeyStore.java @@ -14,21 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.definition; +package org.jivesoftware.smackx.ox.store.definition; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - 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.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public interface OpenPgpKeyStore { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpMetadataStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpMetadataStore.java similarity index 89% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpMetadataStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpMetadataStore.java index 8ef8e66c4..ed4715d23 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpMetadataStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpMetadataStore.java @@ -14,15 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.definition; +package org.jivesoftware.smackx.ox.store.definition; import java.io.IOException; import java.util.Date; import java.util.Map; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public interface OpenPgpMetadataStore { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpStore.java similarity index 91% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpStore.java index 25a751bdf..87a6df8b6 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpStore.java @@ -1,4 +1,4 @@ -package org.jivesoftware.smackx.ox.v2.store.definition; +package org.jivesoftware.smackx.ox.store.definition; import org.jivesoftware.smackx.ox.OpenPgpContact; import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpTrustStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpTrustStore.java similarity index 89% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpTrustStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpTrustStore.java index a7da9cad4..294d6e061 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/definition/OpenPgpTrustStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/OpenPgpTrustStore.java @@ -14,13 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.definition; +package org.jivesoftware.smackx.ox.store.definition; import java.io.IOException; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public interface OpenPgpTrustStore { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/package-info.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/package-info.java similarity index 87% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/package-info.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/package-info.java index 9e0e52408..2f35fed67 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/package-info.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/definition/package-info.java @@ -15,6 +15,6 @@ * limitations under the License. */ /** - * Second iteration. + * OpenPgp store class definitions. */ -package org.jivesoftware.smackx.ox.v2.store.filebased; +package org.jivesoftware.smackx.ox.store.definition; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpKeyStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpKeyStore.java similarity index 97% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpKeyStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpKeyStore.java index 4337ccd2a..cc2dce5d0 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpKeyStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpKeyStore.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.filebased; +package org.jivesoftware.smackx.ox.store.filebased; import static org.jivesoftware.smackx.ox.util.FileUtils.prepareFileInputStream; import static org.jivesoftware.smackx.ox.util.FileUtils.prepareFileOutputStream; @@ -26,7 +26,7 @@ import java.io.IOException; import java.io.OutputStream; import org.jivesoftware.smack.util.Objects; -import org.jivesoftware.smackx.ox.v2.store.abstr.AbstractOpenPgpKeyStore; +import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpKeyStore; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpMetadataStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpMetadataStore.java similarity index 94% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpMetadataStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpMetadataStore.java index f636f3c77..057bcf649 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpMetadataStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpMetadataStore.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.filebased; +package org.jivesoftware.smackx.ox.store.filebased; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -28,12 +28,13 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; +import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpMetadataStore; import org.jivesoftware.smackx.ox.util.Util; -import org.jivesoftware.smackx.ox.v2.store.abstr.AbstractOpenPgpMetadataStore; +import org.bouncycastle.openpgp.PGPException; import org.jxmpp.jid.BareJid; import org.jxmpp.util.XmppDateTime; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public class FileBasedOpenPgpMetadataStore extends AbstractOpenPgpMetadataStore { @@ -81,7 +82,7 @@ public class FileBasedOpenPgpMetadataStore extends AbstractOpenPgpMetadataStore OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(split[0]); Date date = XmppDateTime.parseXEP0082Date(split[1]); fingerprintDateMap.put(fingerprint, date); - } catch (ParseException e) { + } catch (PGPException | ParseException e) { LOGGER.log(Level.WARNING, "Error parsing fingerprint/date touple in line " + lineNr + " of file " + source.getAbsolutePath(), e); } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpStore.java similarity index 90% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpStore.java index b77d25623..998c24456 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpStore.java @@ -14,12 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.filebased; +package org.jivesoftware.smackx.ox.store.filebased; import java.io.File; import org.jivesoftware.smack.util.Objects; -import org.jivesoftware.smackx.ox.v2.store.abstr.AbstractOpenPgpStore; +import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpStore; import org.jxmpp.jid.BareJid; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpTrustStore.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpTrustStore.java similarity index 95% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpTrustStore.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpTrustStore.java index 3b6ca328c..b51a95642 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/filebased/FileBasedOpenPgpTrustStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/FileBasedOpenPgpTrustStore.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.ox.v2.store.filebased; +package org.jivesoftware.smackx.ox.store.filebased; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -25,11 +25,11 @@ import java.nio.file.Files; import java.util.logging.Level; import java.util.logging.Logger; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; +import org.jivesoftware.smackx.ox.store.abstr.AbstractOpenPgpTrustStore; import org.jivesoftware.smackx.ox.util.Util; -import org.jivesoftware.smackx.ox.v2.store.abstr.AbstractOpenPgpTrustStore; import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public class FileBasedOpenPgpTrustStore extends AbstractOpenPgpTrustStore { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/package-info.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/package-info.java similarity index 87% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/package-info.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/package-info.java index b99cb4457..69fd79832 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/package-info.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/filebased/package-info.java @@ -15,6 +15,6 @@ * limitations under the License. */ /** - * Second iteration. + * File based store implementations. */ -package org.jivesoftware.smackx.ox.v2; +package org.jivesoftware.smackx.ox.store.filebased; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/package-info.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/package-info.java similarity index 88% rename from smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/package-info.java rename to smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/package-info.java index e5cfa2608..81992a046 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/store/package-info.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/store/package-info.java @@ -15,6 +15,6 @@ * limitations under the License. */ /** - * Second iteration. + * OpenPGP store implementations. */ -package org.jivesoftware.smackx.ox.v2.store; +package org.jivesoftware.smackx.ox.store; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/KeyBytesAndFingerprint.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/KeyBytesAndFingerprint.java deleted file mode 100644 index 229ac11e7..000000000 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/KeyBytesAndFingerprint.java +++ /dev/null @@ -1,40 +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.util; - -import java.util.Arrays; - -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - -public class KeyBytesAndFingerprint { - - private final byte[] bytes; - private final OpenPgpV4Fingerprint fingerprint; - - public KeyBytesAndFingerprint(byte[] bytes, OpenPgpV4Fingerprint fingerprint) { - this.bytes = bytes; - this.fingerprint = fingerprint; - } - - public byte[] getBytes() { - return Arrays.copyOf(bytes, bytes.length); - } - - public OpenPgpV4Fingerprint getFingerprint() { - return fingerprint; - } -} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/PubSubDelegate.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/PubSubDelegate.java index 3a9541222..7ccd86a09 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/PubSubDelegate.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/PubSubDelegate.java @@ -31,7 +31,6 @@ import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.StanzaError; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.ox.OpenPgpManager; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; import org.jivesoftware.smackx.ox.element.PubkeyElement; import org.jivesoftware.smackx.ox.element.PublicKeysListElement; import org.jivesoftware.smackx.ox.element.SecretkeyElement; @@ -46,6 +45,7 @@ import org.jivesoftware.smackx.pubsub.PubSubManager; import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public class PubSubDelegate { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/SecretKeyBackupHelper.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/SecretKeyBackupHelper.java index 8fa91e62b..1e44523d2 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/SecretKeyBackupHelper.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/SecretKeyBackupHelper.java @@ -16,21 +16,18 @@ */ 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.OpenPgpProvider; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; +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.MissingOpenPgpKeyPairException; import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException; import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException; import org.jxmpp.jid.BareJid; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public class SecretKeyBackupHelper { @@ -66,6 +63,7 @@ public class SecretKeyBackupHelper { BareJid owner, Set fingerprints, String backupCode) throws SmackOpenPgpException, IOException { + /* ByteArrayOutputStream buffer = new ByteArrayOutputStream(); for (OpenPgpV4Fingerprint fingerprint : fingerprints) { try { @@ -76,18 +74,22 @@ public class SecretKeyBackupHelper { } } 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)); + // byte[] encrypted = provider.symmetricallyEncryptWithPassword(keys, backupCode); + // return new SecretkeyElement(Base64.encode(encrypted)); + return null; } public static OpenPgpV4Fingerprint restoreSecretKeyBackup(OpenPgpProvider provider, SecretkeyElement backup, String backupCode) throws InvalidBackupCodeException, IOException, MissingUserIdOnKeyException, SmackOpenPgpException { + /* byte[] encrypted = Base64.decode(backup.getB64Data()); byte[] decrypted; @@ -98,5 +100,7 @@ public class SecretKeyBackupHelper { } return provider.importSecretKey(decrypted); + */ + return null; } } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpContact.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpContact.java deleted file mode 100644 index a2ca7d250..000000000 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpContact.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.jivesoftware.smackx.ox.v2; - -import java.io.IOException; -import java.util.Set; -import java.util.logging.Logger; - -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpStore; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.jxmpp.jid.BareJid; - -public class OpenPgpContact { - - private final Logger LOGGER; - - protected final BareJid jid; - protected final OpenPgpStore store; - - public OpenPgpContact(BareJid jid, OpenPgpStore store) { - this.jid = jid; - this.store = store; - LOGGER = Logger.getLogger(OpenPgpContact.class.getName() + ":" + jid.toString()); - } - - public PGPPublicKeyRingCollection getAnyPublicKeys() throws IOException, PGPException { - return store.getPublicKeysOf(jid); - } - - public PGPPublicKeyRingCollection getAnnouncedPublicKeys() throws IOException, PGPException { - PGPPublicKeyRingCollection anyKeys = getAnyPublicKeys(); - Set announced = store.getAnnouncedFingerprintsOf(jid).keySet(); - - PGPPublicKeyRingCollection announcedKeysCollection = anyKeys; - for (PGPPublicKeyRing ring : anyKeys) { - - OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(ring.getPublicKey()); - - if (!announced.contains(fingerprint)) { - announcedKeysCollection = PGPPublicKeyRingCollection.removePublicKeyRing(announcedKeysCollection, ring); - } - } - return announcedKeysCollection; - } -} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpSelf.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpSelf.java deleted file mode 100644 index ff638becd..000000000 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/v2/OpenPgpSelf.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.jivesoftware.smackx.ox.v2; - -import java.io.IOException; - -import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpStore; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.jxmpp.jid.BareJid; - -public class OpenPgpSelf extends OpenPgpContact { - - public OpenPgpSelf(BareJid jid, OpenPgpStore store) { - super(jid, store); - } - - public boolean hasSecretKeyAvailable() throws IOException, PGPException { - return getSecretKeys() != null; - } - - public PGPSecretKeyRingCollection getSecretKeys() throws IOException, PGPException { - return store.getSecretKeysOf(jid); - } - - public PGPSecretKeyRing getSigningKeyRing() throws IOException, PGPException { - PGPSecretKeyRingCollection secretKeyRings = getSecretKeys(); - if (secretKeyRings == null) { - return null; - } - - PGPSecretKeyRing signingKeyRing = null; - for (PGPSecretKeyRing ring : secretKeyRings) { - if (signingKeyRing == null) { - signingKeyRing = ring; - continue; - } - - if (ring.getPublicKey().getCreationTime().after(signingKeyRing.getPublicKey().getCreationTime())) { - signingKeyRing = ring; - } - } - - return signingKeyRing; - } - - public OpenPgpV4Fingerprint getSigningKeyFingerprint() throws IOException, PGPException { - PGPSecretKeyRing signingKeyRing = getSigningKeyRing(); - return signingKeyRing != null ? new OpenPgpV4Fingerprint(signingKeyRing.getPublicKey()) : null; - } -} diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpV4FingerprintTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpV4FingerprintTest.java deleted file mode 100644 index 0f67ddc96..000000000 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/OpenPgpV4FingerprintTest.java +++ /dev/null @@ -1,58 +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; - -import static junit.framework.TestCase.assertEquals; - -import org.jivesoftware.smack.test.util.SmackTestSuite; - -import org.junit.Test; - -public class OpenPgpV4FingerprintTest extends SmackTestSuite { - - @Test(expected = IllegalArgumentException.class) - public void fpTooShort() { - String fp = "484f57414c495645"; // Asking Mark - new OpenPgpV4Fingerprint(fp); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidHexTest() { - String fp = "UNFORTUNATELYTHISISNOVALIDHEXADECIMALDOH"; - new OpenPgpV4Fingerprint(fp); - } - - @Test - public void validFingerprintTest() { - String fp = "4A4F48414E4E53454E2049532041204E45524421"; - OpenPgpV4Fingerprint finger = new OpenPgpV4Fingerprint(fp); - assertEquals(fp, finger.toString()); - } - - @Test - public void convertsToUpperCaseTest() { - String fp = "444f4e5420552048415645204120484f4242593f"; - OpenPgpV4Fingerprint finger = new OpenPgpV4Fingerprint(fp); - assertEquals("444F4E5420552048415645204120484F4242593F", finger.toString()); - } - - @Test - public void equalsOtherFingerprintTest() { - OpenPgpV4Fingerprint finger = new OpenPgpV4Fingerprint("5448452043414b452049532041204c4945212121"); - assertEquals(finger, new OpenPgpV4Fingerprint("5448452043414B452049532041204C4945212121")); - } -} diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PubSubDelegateTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PubSubDelegateTest.java index 2a4fd13be..afa5fe1f9 100644 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PubSubDelegateTest.java +++ b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PubSubDelegateTest.java @@ -21,12 +21,14 @@ import static junit.framework.TestCase.assertEquals; import org.jivesoftware.smack.test.util.SmackTestSuite; import org.jivesoftware.smackx.ox.util.PubSubDelegate; +import org.bouncycastle.openpgp.PGPException; import org.junit.Test; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; public class PubSubDelegateTest extends SmackTestSuite { @Test - public void pubkeyNodeNameTest() { + public void pubkeyNodeNameTest() throws PGPException { OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint("486f7065207520646f6e2068617665204f43640a"); assertEquals("urn:xmpp:openpgp:0:public-keys:486F7065207520646F6E2068617665204F43640A", PubSubDelegate.PEP_NODE_PUBLIC_KEY(fingerprint)); diff --git a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PublicKeysListElementTest.java b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PublicKeysListElementTest.java index 68901b5ca..2a7819d2d 100644 --- a/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PublicKeysListElementTest.java +++ b/smack-openpgp/src/test/java/org/jivesoftware/smackx/ox/PublicKeysListElementTest.java @@ -17,7 +17,6 @@ package org.jivesoftware.smackx.ox; import static junit.framework.TestCase.assertEquals; - import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import java.util.Date; @@ -27,8 +26,10 @@ import org.jivesoftware.smack.test.util.TestUtils; import org.jivesoftware.smackx.ox.element.PublicKeysListElement; import org.jivesoftware.smackx.ox.provider.PublicKeysListElementProvider; +import org.bouncycastle.openpgp.PGPException; import org.junit.Test; import org.jxmpp.util.XmppDateTime; +import org.pgpainless.pgpainless.key.OpenPgpV4Fingerprint; import org.xmlpull.v1.XmlPullParser; public class PublicKeysListElementTest extends SmackTestSuite { @@ -70,7 +71,7 @@ public class PublicKeysListElementTest extends SmackTestSuite { } @Test - public void listBuilderRefusesDuplicatesTest() { + public void listBuilderRefusesDuplicatesTest() throws PGPException { PublicKeysListElement.Builder builder = PublicKeysListElement.builder(); String fp40 = "49545320414c4c2041424f555420444120484558"; Date oneDate = new Date(12337883234L);