1
0
Fork 0
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:
Paul Schaub 2018-06-14 14:40:35 +02:00
parent 49a51bfa2d
commit 422baa6d2e
21 changed files with 647 additions and 396 deletions

View file

@ -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<BareJid, PGPPublicKeyRingCollection> publicKeyRings = 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
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;

View file

@ -1,4 +0,0 @@
package org.jivesoftware.smackx.ox.bouncycastle;
public interface FileBasedOpenPgpStore {
}

View file

@ -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<OpenPgpV4Fingerprint> 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<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
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
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
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
public Date getPubkeysLastRevision(BareJid owner, OpenPgpV4Fingerprint fingerprint) {
return null;
public Map<OpenPgpV4Fingerprint, Date> 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<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
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
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
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();
}
};
}

View file

@ -1,3 +1,19 @@
/**
*
* Copyright 2018 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ox.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;
}

View file

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

View file

@ -1,3 +1,19 @@
/**
*
* Copyright 2018 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ox.bouncycastle.selection_strategy;
import java.util.Iterator;

View file

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

View file

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

View file

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

View file

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

View file

@ -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<OpenPgpV4Fingerprint> availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints();
Set<OpenPgpV4Fingerprint> availableKeyPairs = provider.getStore().getAvailableKeyPairFingerprints(ownJid);
Set<OpenPgpV4Fingerprint> 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<OpenPgpV4Fingerprint> 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));
}

View file

@ -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<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
@ -86,7 +87,7 @@ public interface OpenPgpStore {
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 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);
/**
* 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<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 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<OpenPgpV4Fingerprint, Date> 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;
}

View file

@ -1,3 +1,19 @@
/**
*
* Copyright 2018 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ox.callback;
public interface SmackMissingOpenPgpPublicKeyCallback {

View file

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

View file

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

View file

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

View file

@ -1,3 +1,19 @@
/**
*
* Copyright 2018 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ox.exception;
import org.jxmpp.jid.BareJid;

View file

@ -1,3 +1,19 @@
/**
*
* Copyright 2018 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ox.exception;
public class NoBackupFoundException {

View file

@ -1,3 +1,19 @@
/**
*
* Copyright 2018 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ox.util;
import java.util.Arrays;

View file

@ -1,3 +1,19 @@
/**
*
* Copyright 2018 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.ox.util;
import java.util.Arrays;

View file

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