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 index f6c3742ca..9b355018b 100644 --- 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 @@ -1,9 +1,28 @@ +/** + * + * 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 de.vanitasvitae.crypto.pgpainless.key.SecretKeyRingProtector; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; @@ -16,6 +35,28 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto private final Map publicKeyRings = new HashMap<>(); private final Map secretKeyRings = new HashMap<>(); + private OpenPgpV4Fingerprint primaryKeyFingerprint = null; + private final SecretKeyRingProtector secretKeyRingProtector; + + + @Override + public OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint() { + return primaryKeyFingerprint; + } + + @Override + public void setPrimaryOpenPgpKeyPairFingerprint(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 { @@ -33,7 +74,7 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto } @Override - public PGPSecretKeyRingCollection getSecretKeyRing(BareJid owner) throws IOException, PGPException { + public PGPSecretKeyRingCollection getSecretKeyRings(BareJid owner) throws IOException, PGPException { PGPSecretKeyRingCollection keyRing = secretKeyRings.get(owner); if (keyRing != null) { return keyRing; diff --git a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedOpenPgpStore.java b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedOpenPgpStore.java deleted file mode 100644 index 0c3b99583..000000000 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedOpenPgpStore.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.jivesoftware.smackx.ox.bouncycastle; - -public interface FileBasedOpenPgpStore { -} 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 index b593e5243..a99b92a81 100644 --- 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 @@ -1,74 +1,440 @@ +/** + * + * 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.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.OpenPgpStore; 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 de.vanitasvitae.crypto.pgpainless.key.SecretKeyRingProtector; +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; -public class FileBasedPainlessOpenPgpStore implements OpenPgpStore, FileBasedOpenPgpStore { +public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore { - @Override - public OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint() { - return null; + 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 void setPrimaryOpenPgpKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint) { + 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.INFO, "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 Set getAvailableKeyPairFingerprints() { - return null; + 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.INFO, "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) { + 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 { - return null; + Map availableFingerprints = new HashMap<>(); + try { + PGPPublicKeyRingCollection publicKeys = getPublicKeyRings(contact); + Set fingerprints = new HashSet<>(); + for (PGPPublicKeyRing ring : publicKeys) { + 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) { + LOGGER.log(Level.WARNING, "Could not read public keys of contact " + contact.toString(), e); + } + return availableFingerprints; } @Override public Map getAnnouncedKeysFingerprints(BareJid contact) { - return null; + 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 Date getPubkeysLastRevision(BareJid owner, OpenPgpV4Fingerprint fingerprint) { - return null; + 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, OpenPgpV4Fingerprint fingerprint, Date revision) { - + 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() { - return null; + MultiMap trustedFingerprints = new MultiMap<>(); + try { + File contactsDir = getContactsPath(false); + if (!contactsDir.exists()) { + LOGGER.log(Level.INFO, "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[] getPublicKeyBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) + public byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws MissingOpenPgpPublicKeyException { - return new byte[0]; + 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[] getSecretKeyBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) + public byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws MissingOpenPgpKeyPairException { - return new byte[0]; + 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 index 5ed0a7ca2..726a91488 100644 --- 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 @@ -1,3 +1,19 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jivesoftware.smackx.ox.bouncycastle; import java.io.ByteArrayInputStream; @@ -86,9 +102,9 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider { InputStream fromPlain = element.toInputStream(); PGPSecretKeyRing signingKeyRing; try { - signingKeyRing = store.getSecretKeyRing(owner).getSecretKeyRing(signingKeyFingerprint.getKeyId()); + signingKeyRing = store.getSecretKeyRings(owner).getSecretKeyRing(signingKeyFingerprint.getKeyId()); } catch (PGPException e) { - throw new MissingOpenPgpKeyPairException(owner, e); + throw new MissingOpenPgpKeyPairException(owner, signingKeyFingerprint, e); } ByteArrayOutputStream toSigned = new ByteArrayOutputStream(); @@ -146,7 +162,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider { DecryptionStream decryptionStream; try { decryptionStream = PGPainless.createDecryptor().onInputStream(fromEncrypted) - .decryptWith(store.getSecretKeyRing(owner), store.getSecretKeyProtector()) + .decryptWith(store.getSecretKeyRings(owner), store.getSecretKeyProtector()) .verifyWith(trustedKeyIds, senderKeys) .handleMissingPublicKeysWith(new MissingPublicKeyCallback() { @Override @@ -218,9 +234,9 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider { throws IOException, MissingOpenPgpKeyPairException { PGPSecretKeyRing signingKeyRing; try { - signingKeyRing = store.getSecretKeyRing(owner).getSecretKeyRing(signingKey.getKeyId()); + signingKeyRing = store.getSecretKeyRings(owner).getSecretKeyRing(signingKey.getKeyId()); } catch (PGPException e) { - throw new MissingOpenPgpKeyPairException(owner, e); + throw new MissingOpenPgpKeyPairException(owner, signingKey, e); } return signingKeyRing; } 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 index 41819a748..e086ce131 100644 --- 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 @@ -30,11 +30,19 @@ public interface PainlessOpenPgpStore extends OpenPgpStore { PGPPublicKeyRingCollection getPublicKeyRings(BareJid owner) throws IOException, PGPException; - PGPSecretKeyRingCollection getSecretKeyRing(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/main/java/org/jivesoftware/smackx/ox/bouncycastle/selection_strategy/BareJidUserId.java b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/selection_strategy/BareJidUserId.java index d3f763d99..6f6fea36a 100644 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/selection_strategy/BareJidUserId.java +++ b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/selection_strategy/BareJidUserId.java @@ -1,3 +1,19 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jivesoftware.smackx.ox.bouncycastle.selection_strategy; import java.util.Iterator; diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BasicEncryptionTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BasicEncryptionTest.java deleted file mode 100644 index 98c0aef32..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BasicEncryptionTest.java +++ /dev/null @@ -1,165 +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 static org.jivesoftware.smackx.ox.TestKeys.JULIET_UID; -import static org.jivesoftware.smackx.ox.TestKeys.ROMEO_UID; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SignatureException; -import java.util.Arrays; -import java.util.Date; - -import org.jivesoftware.smack.test.util.SmackTestSuite; -import org.jivesoftware.smackx.ox.TestKeys; - -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.BouncyGPG; -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeySelectionStrategy; -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallbacks; -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.XmppKeySelectionStrategy; -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.InMemoryKeyring; -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfig; -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfigs; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPKeyRingGenerator; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.util.io.Streams; -import org.junit.Ignore; -import org.jxmpp.jid.impl.JidCreate; - -public class BasicEncryptionTest extends SmackTestSuite { - - private static final Charset UTF8 = Charset.forName("UTF-8"); - private final KeyringConfig keyringJuliet; - private final KeyringConfig keyringRomeo; - - public BasicEncryptionTest() throws IOException, PGPException { - super(); - - // Prepare Juliet's keyring - keyringJuliet = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys()); - ((InMemoryKeyring) keyringJuliet).addSecretKey(TestKeys.JULIET_PRIV.getBytes(UTF8)); - ((InMemoryKeyring) keyringJuliet).addPublicKey(TestKeys.JULIET_PUB.getBytes(UTF8)); - ((InMemoryKeyring) keyringJuliet).addPublicKey(TestKeys.ROMEO_PUB.getBytes(UTF8)); - - // Prepare Romeos keyring - keyringRomeo = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys()); - ((InMemoryKeyring) keyringRomeo).addSecretKey(TestKeys.ROMEO_PRIV.getBytes(UTF8)); - ((InMemoryKeyring) keyringRomeo).addPublicKey(TestKeys.ROMEO_PUB.getBytes(UTF8)); - ((InMemoryKeyring) keyringRomeo).addPublicKey(TestKeys.JULIET_PUB.getBytes(UTF8)); - } - - @Ignore - public void encryptionTest() - throws IOException, PGPException, NoSuchAlgorithmException, SignatureException, NoSuchProviderException { - ByteArrayOutputStream result = new ByteArrayOutputStream(); - KeySelectionStrategy selectionStrategy = new XmppKeySelectionStrategy(new Date()); - - byte[] message = "How long do you want these messages to remain secret?".getBytes(UTF8); - - // Encrypt - OutputStream out = BouncyGPG.encryptToStream() - .withConfig(keyringJuliet) - .withKeySelectionStrategy(selectionStrategy) - .withOxAlgorithms() - .toRecipients(ROMEO_UID, JULIET_UID) - .andSignWith(JULIET_UID) - .binaryOutput() - .andWriteTo(result); - - out.write(message); - out.close(); - - byte[] encrypted = result.toByteArray(); - - // Decrypt - ByteArrayInputStream encIn = new ByteArrayInputStream(encrypted); - InputStream in = BouncyGPG.decryptAndVerifyStream() - .withConfig(keyringRomeo) - .withKeySelectionStrategy(selectionStrategy) - .andRequireSignatureFromAllKeys(JULIET_UID) - .fromEncryptedInputStream(encIn); - - ByteArrayOutputStream decrypted = new ByteArrayOutputStream(); - Streams.pipeAll(in, decrypted); - - byte[] message2 = decrypted.toByteArray(); - - assertTrue(Arrays.equals(message, message2)); - } - - @Ignore - public void encryptionWithFreshKeysTest() - throws IOException, PGPException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException { - final String alice = "alice@wonderland.lit"; - final String bob = "bob@builder.tv"; - PGPKeyRingGenerator g1 = BCOpenPgpProvider.generateKey(JidCreate.bareFrom(alice)); - PGPKeyRingGenerator g2 = BCOpenPgpProvider.generateKey(JidCreate.bareFrom(bob)); - PGPSecretKey s1 = g1.generateSecretKeyRing().getSecretKey(); - PGPSecretKey s2 = g2.generateSecretKeyRing().getSecretKey(); - PGPPublicKey p1 = g1.generatePublicKeyRing().getPublicKey(); - PGPPublicKey p2 = g2.generatePublicKeyRing().getPublicKey(); - - KeyringConfig c1 = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys()); - KeyringConfig c2 = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys()); - ((InMemoryKeyring) c1).addSecretKey(s1.getEncoded()); - ((InMemoryKeyring) c1).addPublicKey(p1.getEncoded()); - ((InMemoryKeyring) c1).addPublicKey(p2.getEncoded()); - ((InMemoryKeyring) c2).addSecretKey(s2.getEncoded()); - ((InMemoryKeyring) c2).addPublicKey(p2.getEncoded()); - ((InMemoryKeyring) c2).addPublicKey(p1.getEncoded()); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - - byte[] m1 = "I want them to remain secret for as long as men are capable of evil.".getBytes(UTF8); - OutputStream encrypt = BouncyGPG.encryptToStream() - .withConfig(c1) - .withKeySelectionStrategy(new XmppKeySelectionStrategy(new Date())) - .withOxAlgorithms() - .toRecipients("xmpp:" + alice, "xmpp:" + bob) - .andSignWith("xmpp:" + alice) - .binaryOutput() - .andWriteTo(result); - - encrypt.write(m1); - encrypt.close(); - - byte[] e1 = result.toByteArray(); - result.reset(); - - ByteArrayInputStream in = new ByteArrayInputStream(e1); - InputStream decrypt = BouncyGPG.decryptAndVerifyStream() - .withConfig(c2) - .withKeySelectionStrategy(new XmppKeySelectionStrategy(new Date())) - .andValidateSomeoneSigned() - .fromEncryptedInputStream(in); - - Streams.pipeAll(decrypt, result); - - byte[] m2 = result.toByteArray(); - assertTrue(Arrays.equals(m1, m2)); - } -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastleOpenPgpProviderTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastleOpenPgpProviderTest.java deleted file mode 100644 index d784c3c16..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastleOpenPgpProviderTest.java +++ /dev/null @@ -1,79 +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 static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; - -import java.security.Security; -import java.util.Collections; - -import org.jivesoftware.smack.packet.ExtensionElement; -import org.jivesoftware.smack.packet.Message; -import org.jivesoftware.smack.test.util.SmackTestSuite; -import org.jivesoftware.smackx.ox.chat.OpenPgpMessage; -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.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.Ignore; -import org.jxmpp.jid.BareJid; -import org.jxmpp.jid.Jid; -import org.jxmpp.jid.impl.JidCreate; - -public class BouncyCastleOpenPgpProviderTest extends SmackTestSuite { - - @Ignore - public void encryptAndSign_decryptAndVerifyElementTest() throws Exception { - Security.addProvider(new BouncyCastleProvider()); - - // Create providers for alice and the cat - BareJid alice = JidCreate.bareFrom("alice@wonderland.lit"); - BareJid cheshire = JidCreate.bareFrom("cheshire@wonderland.lit"); - BCOpenPgpProvider aliceProvider = new BCOpenPgpProvider(alice); - BCOpenPgpProvider cheshireProvider = new BCOpenPgpProvider(cheshire); - - aliceProvider.createOpenPgpKeyPair(); - cheshireProvider.createOpenPgpKeyPair(); - - // dry exchange keys - - PubkeyElement aliceKeys = aliceProvider.createPubkeyElement(aliceProvider.getPrimaryOpenPgpKeyPairFingerprint()); - PubkeyElement cheshireKeys = cheshireProvider.createPubkeyElement(cheshireProvider.getPrimaryOpenPgpKeyPairFingerprint()); - aliceProvider.storePublicKey(cheshire, cheshireProvider.getPrimaryOpenPgpKeyPairFingerprint(), cheshireKeys); - cheshireProvider.storePublicKey(alice, aliceProvider.getPrimaryOpenPgpKeyPairFingerprint(), aliceKeys); - - // Create signed and encrypted message from alice to the cheshire cat - SigncryptElement signcryptElement = new SigncryptElement( - Collections.singleton(cheshire), - Collections.singletonList( - new Message.Body("en", "How do you know I’m mad?"))); - OpenPgpElement encrypted = aliceProvider.signAndEncrypt( - signcryptElement, - aliceProvider.getPrimaryOpenPgpKeyPairFingerprint(), - Collections.singleton(cheshireProvider.getPrimaryOpenPgpKeyPairFingerprint())); - - // Decrypt the message as the cheshire cat - OpenPgpMessage decrypted = cheshireProvider.decryptAndVerify(encrypted, Collections.singleton(aliceProvider.getPrimaryOpenPgpKeyPairFingerprint())); - OpenPgpContentElement content = decrypted.getOpenPgpContentElement(); - - assertTrue(content instanceof SigncryptElement); - assertXMLEqual(signcryptElement.toXML(null).toString(), content.toXML(null).toString()); - } -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastle_OpenPgpV4FingerprintTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastle_OpenPgpV4FingerprintTest.java deleted file mode 100644 index 1241c3ad9..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/BouncyCastle_OpenPgpV4FingerprintTest.java +++ /dev/null @@ -1,49 +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 org.jivesoftware.smack.util.StringUtils.UTF8; - -import java.io.IOException; - -import org.jivesoftware.smack.test.util.SmackTestSuite; -import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; -import org.jivesoftware.smackx.ox.TestKeys; -import org.jivesoftware.smackx.ox.util.Util; - -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallbacks; -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.InMemoryKeyring; -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfigs; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.junit.Test; - -public class BouncyCastle_OpenPgpV4FingerprintTest extends SmackTestSuite { - - @Test - public void keyIdFromFingerprintTest() throws IOException, PGPException { - // Parse the key - InMemoryKeyring keyringJuliet = KeyringConfigs.forGpgExportedKeys( - KeyringConfigCallbacks.withUnprotectedKeys()); - keyringJuliet.addPublicKey(TestKeys.JULIET_PUB.getBytes(UTF8)); - PGPPublicKey publicKey = keyringJuliet.getPublicKeyRings().iterator().next().getPublicKey(); - - OpenPgpV4Fingerprint fp = BCOpenPgpProvider.getFingerprint(publicKey); - assertEquals(publicKey.getKeyID(), Util.keyIdFromFingerprint(fp)); - } -} diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/KeyGenerationTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/KeyGenerationTest.java deleted file mode 100644 index db6a9c528..000000000 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/KeyGenerationTest.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.bouncycastle; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertTrue; - -import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PublicKeyType; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.junit.Ignore; -import org.jxmpp.jid.impl.JidCreate; - -public class KeyGenerationTest { - - @Ignore - public void createSecretKey() throws Exception { - PGPSecretKey secretKey = BCOpenPgpProvider - .generateKey(JidCreate.bareFrom("alice@wonderland.lit")) - .generateSecretKeyRing() - .getSecretKey(); - assertEquals(PublicKeyType.RSA_GENERAL.getId(), secretKey.getPublicKey().getAlgorithm()); - assertTrue(secretKey.getPublicKey().isEncryptionKey()); - assertEquals(2048, secretKey.getPublicKey().getBitStrength()); - assertEquals("xmpp:alice@wonderland.lit", secretKey.getPublicKey().getUserIDs().next()); - } -} 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 ee2ccf4e8..2672c2093 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 @@ -232,14 +232,14 @@ public final class OpenPgpManager extends Manager { SecretKeyBackupSelectionCallback selectKeyCallback) throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException, - SmackException.NotLoggedInException { + SmackException.NotLoggedInException, SmackOpenPgpException, IOException { throwIfNoProviderSet(); throwIfNotAuthenticated(); BareJid ownJid = connection().getUser().asBareJid(); String backupCode = generateBackupPassword(); - Set availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(); + Set availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(ownJid); Set selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs); SecretkeyElement secretKey = createSecretkeyElement(ownJid, selectedKeyPairs, backupCode); @@ -419,7 +419,7 @@ public final class OpenPgpManager extends Manager { OpenPgpV4Fingerprint fingerprint, Date date) throws MissingOpenPgpPublicKeyException { - byte[] keyBytes = provider.getStore().getPublicKeyBytes(owner, fingerprint); + byte[] keyBytes = provider.getStore().getPublicKeyRingBytes(owner, fingerprint); return createPubkeyElement(keyBytes, date); } @@ -429,11 +429,11 @@ public final class OpenPgpManager extends Manager { private SecretkeyElement createSecretkeyElement(BareJid owner, Set fingerprints, - String backupCode) { + String backupCode) throws SmackOpenPgpException, IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); for (OpenPgpV4Fingerprint fingerprint : fingerprints) { try { - byte[] bytes = provider.getStore().getSecretKeyBytes(owner, fingerprint); + byte[] bytes = provider.getStore().getSecretKeyRingBytes(owner, fingerprint); buffer.write(bytes); } catch (MissingOpenPgpKeyPairException | IOException e) { LOGGER.log(Level.WARNING, "Cannot backup secret key " + Long.toHexString(fingerprint.getKeyId()) + ".", e); @@ -443,7 +443,8 @@ public final class OpenPgpManager extends Manager { return createSecretkeyElement(buffer.toByteArray(), backupCode); } - private SecretkeyElement createSecretkeyElement(byte[] keys, String backupCode) { + private SecretkeyElement createSecretkeyElement(byte[] keys, String backupCode) + throws SmackOpenPgpException, IOException { byte[] encrypted = provider.symmetricallyEncryptWithPassword(keys, backupCode); return new SecretkeyElement(Base64.encode(encrypted)); } 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 index 79f1281fa..28d311c74 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpStore.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpStore.java @@ -49,11 +49,12 @@ public interface OpenPgpStore { /** * Return a {@link Set} containing the {@link OpenPgpV4Fingerprint}s of the master keys of all available - * OpenPGP key pairs. + * OpenPGP key pairs of {@code owner}. * + * @param owner owner. * @return set of fingerprints of available OpenPGP key pairs master keys. */ - Set getAvailableKeyPairFingerprints(); + Set getAvailableKeyPairFingerprints(BareJid owner) throws SmackOpenPgpException; /** * Return a {@link Map} containing the {@link OpenPgpV4Fingerprint}s of all OpenPGP public keys of a @@ -86,7 +87,7 @@ public interface OpenPgpStore { Map getAnnouncedKeysFingerprints(BareJid contact); /** - * Store a {@Map} of a contacts fingerprints and publication dates in persistent storage. + * 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}. @@ -94,22 +95,22 @@ public interface OpenPgpStore { void setAnnouncedKeysFingerprints(BareJid contact, Map fingerprints); /** - * Return the {@link Date} of the last revision which was fetched from PubSub. + * 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 key - * @param fingerprint fingerprint of the key. - * @return {@link Date} or {@code null} if no record found. + * @param owner owner of the keys + * @return {@link Map} of keys last revision dates. */ - Date getPubkeysLastRevision(BareJid owner, OpenPgpV4Fingerprint fingerprint); + Map getPubkeysLastRevisions(BareJid owner); /** - * Set the {@link Date} of the last revision which was fetched from PubSub. + * Set the last revision dates of all keys of a contact. * - * @param owner owner of the key - * @param fingerprint fingerprint of the key - * @param revision {@link Date} of the revision + * @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, OpenPgpV4Fingerprint fingerprint, Date revision); + void setPubkeysLastRevision(BareJid owner, Map revisionDates); /** * Return a {@link MultiMap} which contains contacts and their trusted keys {@link OpenPgpV4Fingerprint}s. @@ -125,7 +126,7 @@ public interface OpenPgpStore { * @param fingerprint fingerprint of the key * @return byte representation of the public key. */ - byte[] getPublicKeyBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) + byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws MissingOpenPgpPublicKeyException; /** @@ -135,7 +136,7 @@ public interface OpenPgpStore { * @param fingerprint fingerprint of the key * @return byte representation of the secret key. */ - byte[] getSecretKeyBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) + byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws MissingOpenPgpKeyPairException; } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/SmackMissingOpenPgpPublicKeyCallback.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/SmackMissingOpenPgpPublicKeyCallback.java index 028add7f4..b16e5f7ac 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/SmackMissingOpenPgpPublicKeyCallback.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/callback/SmackMissingOpenPgpPublicKeyCallback.java @@ -1,3 +1,19 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jivesoftware.smackx.ox.callback; public interface SmackMissingOpenPgpPublicKeyCallback { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/chat/package-info.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/chat/package-info.java new file mode 100644 index 000000000..add1442bc --- /dev/null +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/chat/package-info.java @@ -0,0 +1,20 @@ +/** + * + * 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. + */ +/** + * Chat related classes for XEP-0373: OpenPGP for XMPP. + */ +package org.jivesoftware.smackx.ox.chat; 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 a7ef0be03..d2f6b290a 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,6 +16,8 @@ */ package org.jivesoftware.smackx.ox.exception; +import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; + import org.jxmpp.jid.BareJid; /** @@ -26,15 +28,23 @@ public class MissingOpenPgpKeyPairException extends Exception { private static final long serialVersionUID = 1L; private final BareJid owner; + private final OpenPgpV4Fingerprint fingerprint; /** * Create a new {@link MissingOpenPgpKeyPairException}. * * @param owner owner of the missing key pair. - * @param e + * @param fingerprint fingerprint of the missing key. */ - public MissingOpenPgpKeyPairException(BareJid owner, Throwable e) { - super("Missing OpenPGP key pair for user " + owner); + public MissingOpenPgpKeyPairException(BareJid owner, OpenPgpV4Fingerprint fingerprint) { + super("Missing OpenPGP key pair " + fingerprint.toString() + " for user " + owner); + this.owner = owner; + this.fingerprint = fingerprint; + } + + public MissingOpenPgpKeyPairException(BareJid owner, OpenPgpV4Fingerprint fingerprint, Throwable e) { + super("Missing OpenPGP key pair " + fingerprint.toString() + " for user " + owner, e); + this.fingerprint = fingerprint; this.owner = owner; } @@ -46,4 +56,10 @@ public class MissingOpenPgpKeyPairException extends Exception { public BareJid getOwner() { return owner; } + + public OpenPgpV4Fingerprint getFingerprint() { + return fingerprint; + } + + } 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 a68f8341a..08ed5bf3f 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 @@ -27,8 +27,8 @@ public class MissingOpenPgpPublicKeyException extends Exception { private static final long serialVersionUID = 1L; - private BareJid user; - private OpenPgpV4Fingerprint fingerprint; + private final BareJid owner; + private final OpenPgpV4Fingerprint fingerprint; /** * Create a new {@link MissingOpenPgpPublicKeyException}. @@ -37,22 +37,25 @@ public class MissingOpenPgpPublicKeyException extends Exception { * @param fingerprint {@link OpenPgpV4Fingerprint} of the missing key. */ public MissingOpenPgpPublicKeyException(BareJid owner, OpenPgpV4Fingerprint fingerprint) { - super("Missing public key " + fingerprint.toString() + " for user " + owner + "."); - this.user = owner; + super("Missing public key " + fingerprint.toString() + " for owner " + owner + "."); + this.owner = owner; this.fingerprint = fingerprint; } - public MissingOpenPgpPublicKeyException(Throwable e) { - + public MissingOpenPgpPublicKeyException(BareJid owner, OpenPgpV4Fingerprint fingerprint, Throwable e) { + super("Missing public key " + fingerprint.toString() + " for owner " + owner + ".", e); + this.owner = owner; + this.fingerprint = fingerprint; } + /** * Return the {@link BareJid} of the owner of the missing key. * * @return owner of missing key. */ - public BareJid getUser() { - return user; + public BareJid getOwner() { + return owner; } /** diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingUserIdOnKeyException.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingUserIdOnKeyException.java index 59bb36d19..dedd3ca13 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingUserIdOnKeyException.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/MissingUserIdOnKeyException.java @@ -1,3 +1,19 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jivesoftware.smackx.ox.exception; import org.jxmpp.jid.BareJid; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/NoBackupFoundException.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/NoBackupFoundException.java index 5e69a87e2..afa07025a 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/NoBackupFoundException.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/exception/NoBackupFoundException.java @@ -1,3 +1,19 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jivesoftware.smackx.ox.exception; public class NoBackupFoundException { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/DecryptedBytesAndMetadata.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/DecryptedBytesAndMetadata.java index ff480d7a3..a85639f70 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/DecryptedBytesAndMetadata.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/DecryptedBytesAndMetadata.java @@ -1,3 +1,19 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jivesoftware.smackx.ox.util; import java.util.Arrays; 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 index 80044e7fc..229ac11e7 100644 --- 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 @@ -1,3 +1,19 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jivesoftware.smackx.ox.util; import java.util.Arrays; diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/package-info.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/package-info.java new file mode 100644 index 000000000..890ef6685 --- /dev/null +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/util/package-info.java @@ -0,0 +1,20 @@ +/** + * + * 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. + */ +/** + * Utility classes for XEP-0373: OpenPGP for XMPP. + */ +package org.jivesoftware.smackx.ox.util;