mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 20:42:06 +01:00
WiP finished, no more compiler errors - untested
This commit is contained in:
parent
49a51bfa2d
commit
422baa6d2e
21 changed files with 647 additions and 396 deletions
|
@ -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;
|
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
|
@ -16,6 +35,28 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto
|
||||||
|
|
||||||
private final Map<BareJid, PGPPublicKeyRingCollection> publicKeyRings = new HashMap<>();
|
private final Map<BareJid, PGPPublicKeyRingCollection> publicKeyRings = new HashMap<>();
|
||||||
private final Map<BareJid, PGPSecretKeyRingCollection> secretKeyRings = new HashMap<>();
|
private final Map<BareJid, PGPSecretKeyRingCollection> 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
|
@Override
|
||||||
public PGPPublicKeyRingCollection getPublicKeyRings(BareJid owner) throws IOException, PGPException {
|
public PGPPublicKeyRingCollection getPublicKeyRings(BareJid owner) throws IOException, PGPException {
|
||||||
|
@ -33,7 +74,7 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PGPSecretKeyRingCollection getSecretKeyRing(BareJid owner) throws IOException, PGPException {
|
public PGPSecretKeyRingCollection getSecretKeyRings(BareJid owner) throws IOException, PGPException {
|
||||||
PGPSecretKeyRingCollection keyRing = secretKeyRings.get(owner);
|
PGPSecretKeyRingCollection keyRing = secretKeyRings.get(owner);
|
||||||
if (keyRing != null) {
|
if (keyRing != null) {
|
||||||
return keyRing;
|
return keyRing;
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
|
||||||
|
|
||||||
public interface FileBasedOpenPgpStore {
|
|
||||||
}
|
|
|
@ -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;
|
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.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.MultiMap;
|
import org.jivesoftware.smack.util.MultiMap;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpStore;
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
||||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
||||||
import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException;
|
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.BareJid;
|
||||||
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
import org.jxmpp.util.XmppDateTime;
|
||||||
|
|
||||||
public class FileBasedPainlessOpenPgpStore implements OpenPgpStore, FileBasedOpenPgpStore {
|
public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore {
|
||||||
|
|
||||||
@Override
|
private static final Logger LOGGER = Logger.getLogger(FileBasedPainlessOpenPgpStore.class.getName());
|
||||||
public OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint() {
|
|
||||||
return null;
|
private final File basePath;
|
||||||
|
|
||||||
|
public FileBasedPainlessOpenPgpStore(File base, SecretKeyRingProtector secretKeyRingProtector) {
|
||||||
|
super(secretKeyRingProtector);
|
||||||
|
this.basePath = base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public Set<OpenPgpV4Fingerprint> getAvailableKeyPairFingerprints() {
|
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;
|
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<OpenPgpV4Fingerprint> getAvailableKeyPairFingerprints(BareJid owner) throws SmackOpenPgpException {
|
||||||
|
Set<OpenPgpV4Fingerprint> 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
|
@Override
|
||||||
public Map<OpenPgpV4Fingerprint, Date> getAvailableKeysFingerprints(BareJid contact) throws SmackOpenPgpException {
|
public Map<OpenPgpV4Fingerprint, Date> getAvailableKeysFingerprints(BareJid contact) throws SmackOpenPgpException {
|
||||||
return null;
|
Map<OpenPgpV4Fingerprint, Date> availableFingerprints = new HashMap<>();
|
||||||
|
try {
|
||||||
|
PGPPublicKeyRingCollection publicKeys = getPublicKeyRings(contact);
|
||||||
|
Set<OpenPgpV4Fingerprint> fingerprints = new HashSet<>();
|
||||||
|
for (PGPPublicKeyRing ring : publicKeys) {
|
||||||
|
OpenPgpV4Fingerprint fingerprint = PainlessOpenPgpProvider.getFingerprint(ring.getPublicKey());
|
||||||
|
fingerprints.add(fingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<OpenPgpV4Fingerprint, Date> 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
|
@Override
|
||||||
public Map<OpenPgpV4Fingerprint, Date> getAnnouncedKeysFingerprints(BareJid contact) {
|
public Map<OpenPgpV4Fingerprint, Date> 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
|
@Override
|
||||||
public void setAnnouncedKeysFingerprints(BareJid contact, Map<OpenPgpV4Fingerprint, Date> fingerprints) {
|
public void setAnnouncedKeysFingerprints(BareJid contact, Map<OpenPgpV4Fingerprint, Date> 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
|
@Override
|
||||||
public Date getPubkeysLastRevision(BareJid owner, OpenPgpV4Fingerprint fingerprint) {
|
public Map<OpenPgpV4Fingerprint, Date> getPubkeysLastRevisions(BareJid owner) {
|
||||||
return null;
|
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<OpenPgpV4Fingerprint, Date> loadFingerprintsAndDates(File file) throws IOException {
|
||||||
|
Map<OpenPgpV4Fingerprint, Date> 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<OpenPgpV4Fingerprint, Date> 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
|
@Override
|
||||||
public void setPubkeysLastRevision(BareJid owner, OpenPgpV4Fingerprint fingerprint, Date revision) {
|
public void setPubkeysLastRevision(BareJid owner, Map<OpenPgpV4Fingerprint, Date> 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
|
@Override
|
||||||
public MultiMap<BareJid, OpenPgpV4Fingerprint> getAllContactsTrustedFingerprints() {
|
public MultiMap<BareJid, OpenPgpV4Fingerprint> getAllContactsTrustedFingerprints() {
|
||||||
return null;
|
MultiMap<BareJid, OpenPgpV4Fingerprint> 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
|
@Override
|
||||||
public byte[] getPublicKeyBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
public byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
||||||
throws MissingOpenPgpPublicKeyException {
|
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
|
@Override
|
||||||
public byte[] getSecretKeyBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
public byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
||||||
throws MissingOpenPgpKeyPairException {
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -86,9 +102,9 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
||||||
InputStream fromPlain = element.toInputStream();
|
InputStream fromPlain = element.toInputStream();
|
||||||
PGPSecretKeyRing signingKeyRing;
|
PGPSecretKeyRing signingKeyRing;
|
||||||
try {
|
try {
|
||||||
signingKeyRing = store.getSecretKeyRing(owner).getSecretKeyRing(signingKeyFingerprint.getKeyId());
|
signingKeyRing = store.getSecretKeyRings(owner).getSecretKeyRing(signingKeyFingerprint.getKeyId());
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
throw new MissingOpenPgpKeyPairException(owner, e);
|
throw new MissingOpenPgpKeyPairException(owner, signingKeyFingerprint, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream toSigned = new ByteArrayOutputStream();
|
ByteArrayOutputStream toSigned = new ByteArrayOutputStream();
|
||||||
|
@ -146,7 +162,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
||||||
DecryptionStream decryptionStream;
|
DecryptionStream decryptionStream;
|
||||||
try {
|
try {
|
||||||
decryptionStream = PGPainless.createDecryptor().onInputStream(fromEncrypted)
|
decryptionStream = PGPainless.createDecryptor().onInputStream(fromEncrypted)
|
||||||
.decryptWith(store.getSecretKeyRing(owner), store.getSecretKeyProtector())
|
.decryptWith(store.getSecretKeyRings(owner), store.getSecretKeyProtector())
|
||||||
.verifyWith(trustedKeyIds, senderKeys)
|
.verifyWith(trustedKeyIds, senderKeys)
|
||||||
.handleMissingPublicKeysWith(new MissingPublicKeyCallback() {
|
.handleMissingPublicKeysWith(new MissingPublicKeyCallback() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -218,9 +234,9 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
||||||
throws IOException, MissingOpenPgpKeyPairException {
|
throws IOException, MissingOpenPgpKeyPairException {
|
||||||
PGPSecretKeyRing signingKeyRing;
|
PGPSecretKeyRing signingKeyRing;
|
||||||
try {
|
try {
|
||||||
signingKeyRing = store.getSecretKeyRing(owner).getSecretKeyRing(signingKey.getKeyId());
|
signingKeyRing = store.getSecretKeyRings(owner).getSecretKeyRing(signingKey.getKeyId());
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
throw new MissingOpenPgpKeyPairException(owner, e);
|
throw new MissingOpenPgpKeyPairException(owner, signingKey, e);
|
||||||
}
|
}
|
||||||
return signingKeyRing;
|
return signingKeyRing;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,19 @@ public interface PainlessOpenPgpStore extends OpenPgpStore {
|
||||||
|
|
||||||
PGPPublicKeyRingCollection getPublicKeyRings(BareJid owner) throws IOException, PGPException;
|
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 storePublicKeyRing(BareJid owner, PGPPublicKeyRingCollection publicKeys) throws IOException;
|
||||||
|
|
||||||
void storeSecretKeyRing(BareJid owner, PGPSecretKeyRingCollection secretKeys) 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();
|
SecretKeyRingProtector getSecretKeyProtector();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.jivesoftware.smackx.ox.bouncycastle.selection_strategy;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.<Jid>singleton(cheshire),
|
|
||||||
Collections.<ExtensionElement>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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -232,14 +232,14 @@ public final class OpenPgpManager extends Manager {
|
||||||
SecretKeyBackupSelectionCallback selectKeyCallback)
|
SecretKeyBackupSelectionCallback selectKeyCallback)
|
||||||
throws InterruptedException, PubSubException.NotALeafNodeException,
|
throws InterruptedException, PubSubException.NotALeafNodeException,
|
||||||
XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException,
|
XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException,
|
||||||
SmackException.NotLoggedInException {
|
SmackException.NotLoggedInException, SmackOpenPgpException, IOException {
|
||||||
throwIfNoProviderSet();
|
throwIfNoProviderSet();
|
||||||
throwIfNotAuthenticated();
|
throwIfNotAuthenticated();
|
||||||
|
|
||||||
BareJid ownJid = connection().getUser().asBareJid();
|
BareJid ownJid = connection().getUser().asBareJid();
|
||||||
|
|
||||||
String backupCode = generateBackupPassword();
|
String backupCode = generateBackupPassword();
|
||||||
Set<OpenPgpV4Fingerprint> availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints();
|
Set<OpenPgpV4Fingerprint> availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(ownJid);
|
||||||
Set<OpenPgpV4Fingerprint> selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs);
|
Set<OpenPgpV4Fingerprint> selectedKeyPairs = selectKeyCallback.selectKeysToBackup(availableKeyPairs);
|
||||||
|
|
||||||
SecretkeyElement secretKey = createSecretkeyElement(ownJid, selectedKeyPairs, backupCode);
|
SecretkeyElement secretKey = createSecretkeyElement(ownJid, selectedKeyPairs, backupCode);
|
||||||
|
@ -419,7 +419,7 @@ public final class OpenPgpManager extends Manager {
|
||||||
OpenPgpV4Fingerprint fingerprint,
|
OpenPgpV4Fingerprint fingerprint,
|
||||||
Date date)
|
Date date)
|
||||||
throws MissingOpenPgpPublicKeyException {
|
throws MissingOpenPgpPublicKeyException {
|
||||||
byte[] keyBytes = provider.getStore().getPublicKeyBytes(owner, fingerprint);
|
byte[] keyBytes = provider.getStore().getPublicKeyRingBytes(owner, fingerprint);
|
||||||
return createPubkeyElement(keyBytes, date);
|
return createPubkeyElement(keyBytes, date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,11 +429,11 @@ public final class OpenPgpManager extends Manager {
|
||||||
|
|
||||||
private SecretkeyElement createSecretkeyElement(BareJid owner,
|
private SecretkeyElement createSecretkeyElement(BareJid owner,
|
||||||
Set<OpenPgpV4Fingerprint> fingerprints,
|
Set<OpenPgpV4Fingerprint> fingerprints,
|
||||||
String backupCode) {
|
String backupCode) throws SmackOpenPgpException, IOException {
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
for (OpenPgpV4Fingerprint fingerprint : fingerprints) {
|
for (OpenPgpV4Fingerprint fingerprint : fingerprints) {
|
||||||
try {
|
try {
|
||||||
byte[] bytes = provider.getStore().getSecretKeyBytes(owner, fingerprint);
|
byte[] bytes = provider.getStore().getSecretKeyRingBytes(owner, fingerprint);
|
||||||
buffer.write(bytes);
|
buffer.write(bytes);
|
||||||
} catch (MissingOpenPgpKeyPairException | IOException e) {
|
} catch (MissingOpenPgpKeyPairException | IOException e) {
|
||||||
LOGGER.log(Level.WARNING, "Cannot backup secret key " + Long.toHexString(fingerprint.getKeyId()) + ".", 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);
|
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);
|
byte[] encrypted = provider.symmetricallyEncryptWithPassword(keys, backupCode);
|
||||||
return new SecretkeyElement(Base64.encode(encrypted));
|
return new SecretkeyElement(Base64.encode(encrypted));
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,11 +49,12 @@ public interface OpenPgpStore {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a {@link Set} containing the {@link OpenPgpV4Fingerprint}s of the master keys of all available
|
* 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.
|
* @return set of fingerprints of available OpenPGP key pairs master keys.
|
||||||
*/
|
*/
|
||||||
Set<OpenPgpV4Fingerprint> getAvailableKeyPairFingerprints();
|
Set<OpenPgpV4Fingerprint> getAvailableKeyPairFingerprints(BareJid owner) throws SmackOpenPgpException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a {@link Map} containing the {@link OpenPgpV4Fingerprint}s of all OpenPGP public keys of a
|
* Return a {@link Map} containing the {@link OpenPgpV4Fingerprint}s of all OpenPGP public keys of a
|
||||||
|
@ -86,7 +87,7 @@ public interface OpenPgpStore {
|
||||||
Map<OpenPgpV4Fingerprint, Date> getAnnouncedKeysFingerprints(BareJid contact);
|
Map<OpenPgpV4Fingerprint, Date> 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 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}.
|
* @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<OpenPgpV4Fingerprint, Date> fingerprints);
|
void setAnnouncedKeysFingerprints(BareJid contact, Map<OpenPgpV4Fingerprint, Date> 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 owner owner of the keys
|
||||||
* @param fingerprint fingerprint of the key.
|
* @return {@link Map} of keys last revision dates.
|
||||||
* @return {@link Date} or {@code null} if no record found.
|
|
||||||
*/
|
*/
|
||||||
Date getPubkeysLastRevision(BareJid owner, OpenPgpV4Fingerprint fingerprint);
|
Map<OpenPgpV4Fingerprint, Date> 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 owner owner of the keys
|
||||||
* @param fingerprint fingerprint of the key
|
* @param revisionDates {@link Map} of {@link OpenPgpV4Fingerprint}s and the {@link Date}s of when they
|
||||||
* @param revision {@link Date} of the revision
|
* were last fetched from PubSub.
|
||||||
*/
|
*/
|
||||||
void setPubkeysLastRevision(BareJid owner, OpenPgpV4Fingerprint fingerprint, Date revision);
|
void setPubkeysLastRevision(BareJid owner, Map<OpenPgpV4Fingerprint, Date> revisionDates);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a {@link MultiMap} which contains contacts and their trusted keys {@link OpenPgpV4Fingerprint}s.
|
* 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
|
* @param fingerprint fingerprint of the key
|
||||||
* @return byte representation of the public key.
|
* @return byte representation of the public key.
|
||||||
*/
|
*/
|
||||||
byte[] getPublicKeyBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
||||||
throws MissingOpenPgpPublicKeyException;
|
throws MissingOpenPgpPublicKeyException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,7 +136,7 @@ public interface OpenPgpStore {
|
||||||
* @param fingerprint fingerprint of the key
|
* @param fingerprint fingerprint of the key
|
||||||
* @return byte representation of the secret key.
|
* @return byte representation of the secret key.
|
||||||
*/
|
*/
|
||||||
byte[] getSecretKeyBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
|
||||||
throws MissingOpenPgpKeyPairException;
|
throws MissingOpenPgpKeyPairException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.jivesoftware.smackx.ox.callback;
|
||||||
|
|
||||||
public interface SmackMissingOpenPgpPublicKeyCallback {
|
public interface SmackMissingOpenPgpPublicKeyCallback {
|
||||||
|
|
|
@ -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;
|
|
@ -16,6 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.exception;
|
package org.jivesoftware.smackx.ox.exception;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,15 +28,23 @@ public class MissingOpenPgpKeyPairException extends Exception {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final BareJid owner;
|
private final BareJid owner;
|
||||||
|
private final OpenPgpV4Fingerprint fingerprint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MissingOpenPgpKeyPairException}.
|
* Create a new {@link MissingOpenPgpKeyPairException}.
|
||||||
*
|
*
|
||||||
* @param owner owner of the missing key pair.
|
* @param owner owner of the missing key pair.
|
||||||
* @param e
|
* @param fingerprint fingerprint of the missing key.
|
||||||
*/
|
*/
|
||||||
public MissingOpenPgpKeyPairException(BareJid owner, Throwable e) {
|
public MissingOpenPgpKeyPairException(BareJid owner, OpenPgpV4Fingerprint fingerprint) {
|
||||||
super("Missing OpenPGP key pair for user " + owner);
|
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;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,4 +56,10 @@ public class MissingOpenPgpKeyPairException extends Exception {
|
||||||
public BareJid getOwner() {
|
public BareJid getOwner() {
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OpenPgpV4Fingerprint getFingerprint() {
|
||||||
|
return fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ public class MissingOpenPgpPublicKeyException extends Exception {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private BareJid user;
|
private final BareJid owner;
|
||||||
private OpenPgpV4Fingerprint fingerprint;
|
private final OpenPgpV4Fingerprint fingerprint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MissingOpenPgpPublicKeyException}.
|
* Create a new {@link MissingOpenPgpPublicKeyException}.
|
||||||
|
@ -37,22 +37,25 @@ public class MissingOpenPgpPublicKeyException extends Exception {
|
||||||
* @param fingerprint {@link OpenPgpV4Fingerprint} of the missing key.
|
* @param fingerprint {@link OpenPgpV4Fingerprint} of the missing key.
|
||||||
*/
|
*/
|
||||||
public MissingOpenPgpPublicKeyException(BareJid owner, OpenPgpV4Fingerprint fingerprint) {
|
public MissingOpenPgpPublicKeyException(BareJid owner, OpenPgpV4Fingerprint fingerprint) {
|
||||||
super("Missing public key " + fingerprint.toString() + " for user " + owner + ".");
|
super("Missing public key " + fingerprint.toString() + " for owner " + owner + ".");
|
||||||
this.user = owner;
|
this.owner = owner;
|
||||||
this.fingerprint = fingerprint;
|
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 the {@link BareJid} of the owner of the missing key.
|
||||||
*
|
*
|
||||||
* @return owner of missing key.
|
* @return owner of missing key.
|
||||||
*/
|
*/
|
||||||
public BareJid getUser() {
|
public BareJid getOwner() {
|
||||||
return user;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
package org.jivesoftware.smackx.ox.exception;
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
|
@ -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;
|
package org.jivesoftware.smackx.ox.exception;
|
||||||
|
|
||||||
public class NoBackupFoundException {
|
public class NoBackupFoundException {
|
||||||
|
|
|
@ -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;
|
package org.jivesoftware.smackx.ox.util;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
|
@ -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;
|
package org.jivesoftware.smackx.ox.util;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
|
@ -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;
|
Loading…
Reference in a new issue