mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-27 14:32:06 +01:00
Implement new OpenPgpProvider
This commit is contained in:
parent
bf92cec618
commit
15eee8e65f
18 changed files with 301 additions and 188 deletions
|
@ -1,129 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2018 Paul Schaub.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.ox;
|
|
||||||
|
|
||||||
import javax.xml.bind.DatatypeConverter;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.Objects;
|
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents an hex encoded, uppercase OpenPGP v4 fingerprint.
|
|
||||||
*/
|
|
||||||
public class OpenPgpV4Fingerprint implements CharSequence, Comparable<OpenPgpV4Fingerprint> {
|
|
||||||
|
|
||||||
private final String fingerprint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an {@link OpenPgpV4Fingerprint}.
|
|
||||||
* @see <a href="https://xmpp.org/extensions/xep-0373.html#annoucning-pubkey">
|
|
||||||
* XEP-0373 §4.1: The OpenPGP Public-Key Data Node about how to obtain the fingerprint</a>
|
|
||||||
* @param fingerprint hexadecimal representation of the fingerprint.
|
|
||||||
*/
|
|
||||||
public OpenPgpV4Fingerprint(String fingerprint) throws ParseException {
|
|
||||||
String fp = Objects.requireNonNull(fingerprint)
|
|
||||||
.trim()
|
|
||||||
.toUpperCase();
|
|
||||||
if (!isValid(fp)) {
|
|
||||||
throw new ParseException("Fingerprint " + fingerprint +
|
|
||||||
" does not appear to be a valid OpenPGP v4 fingerprint.", 0);
|
|
||||||
}
|
|
||||||
this.fingerprint = fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OpenPgpV4Fingerprint(byte[] bytes) throws ParseException {
|
|
||||||
this(new String(bytes, Charset.forName("UTF-8")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public OpenPgpV4Fingerprint(PGPPublicKey key) throws ParseException {
|
|
||||||
this(Hex.encode(key.getFingerprint()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check, whether the fingerprint consists of 40 valid hexadecimal characters.
|
|
||||||
* @param fp fingerprint to check.
|
|
||||||
* @return true if fingerprint is valid.
|
|
||||||
*/
|
|
||||||
private boolean isValid(String fp) {
|
|
||||||
return fp.matches("[0-9A-F]{40}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the key id of the OpenPGP public key this {@link OpenPgpV4Fingerprint} belongs to.
|
|
||||||
*
|
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc4880#section-12.2">
|
|
||||||
* RFC-4880 §12.2: Key IDs and Fingerprints</a>
|
|
||||||
* @return key id
|
|
||||||
*/
|
|
||||||
public long getKeyId() {
|
|
||||||
byte[] bytes = DatatypeConverter.parseHexBinary(this.toString());
|
|
||||||
byte[] lower8Bytes = Arrays.copyOfRange(bytes, 12, 20);
|
|
||||||
ByteBuffer byteBuffer = ByteBuffer.allocate(8);
|
|
||||||
byteBuffer.put(lower8Bytes);
|
|
||||||
byteBuffer.flip();
|
|
||||||
return byteBuffer.getLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object other) {
|
|
||||||
if (other == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(other instanceof CharSequence)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.toString().equals(other.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return fingerprint.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int length() {
|
|
||||||
return fingerprint.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public char charAt(int i) {
|
|
||||||
return fingerprint.charAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharSequence subSequence(int i, int i1) {
|
|
||||||
return fingerprint.subSequence(i, i1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return fingerprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(OpenPgpV4Fingerprint openPgpV4Fingerprint) {
|
|
||||||
return fingerprint.compareTo(openPgpV4Fingerprint.fingerprint);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,8 +16,12 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.element;
|
package org.jivesoftware.smackx.ox.element;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
import org.jivesoftware.smackx.ox.util.Util;
|
||||||
|
|
||||||
public class OpenPgpElement implements ExtensionElement {
|
public class OpenPgpElement implements ExtensionElement {
|
||||||
|
|
||||||
|
@ -31,6 +35,10 @@ public class OpenPgpElement implements ExtensionElement {
|
||||||
this.base64EncodedOpenPgpMessage = base64EncodedOpenPgpMessage;
|
this.base64EncodedOpenPgpMessage = base64EncodedOpenPgpMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InputStream toInputStream() {
|
||||||
|
return new ByteArrayInputStream(base64EncodedOpenPgpMessage.getBytes(Util.UTF8));
|
||||||
|
}
|
||||||
|
|
||||||
public String getEncryptedBase64MessageContent() {
|
public String getEncryptedBase64MessageContent() {
|
||||||
return base64EncodedOpenPgpMessage;
|
return base64EncodedOpenPgpMessage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package org.jivesoftware.smackx.ox.v2;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpStore;
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
public class OpenPgpContact {
|
||||||
|
|
||||||
|
private final Logger LOGGER;
|
||||||
|
|
||||||
|
protected final BareJid jid;
|
||||||
|
protected final OpenPgpStore store;
|
||||||
|
|
||||||
|
public OpenPgpContact(BareJid jid, OpenPgpStore store) {
|
||||||
|
this.jid = jid;
|
||||||
|
this.store = store;
|
||||||
|
LOGGER = Logger.getLogger(OpenPgpContact.class.getName() + ":" + jid.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRingCollection getAnyPublicKeys() throws IOException, PGPException {
|
||||||
|
return store.getPublicKeysOf(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRingCollection getAnnouncedPublicKeys() throws IOException, PGPException {
|
||||||
|
PGPPublicKeyRingCollection anyKeys = getAnyPublicKeys();
|
||||||
|
Set<OpenPgpV4Fingerprint> announced = store.getAnnouncedFingerprintsOf(jid).keySet();
|
||||||
|
|
||||||
|
PGPPublicKeyRingCollection announcedKeysCollection = anyKeys;
|
||||||
|
for (PGPPublicKeyRing ring : anyKeys) {
|
||||||
|
|
||||||
|
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(ring.getPublicKey());
|
||||||
|
|
||||||
|
if (!announced.contains(fingerprint)) {
|
||||||
|
announcedKeysCollection = PGPPublicKeyRingCollection.removePublicKeyRing(announcedKeysCollection, ring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return announcedKeysCollection;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,22 +16,24 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.v2;
|
package org.jivesoftware.smackx.ox.v2;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpContact;
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
||||||
import org.jivesoftware.smackx.ox.element.CryptElement;
|
import org.jivesoftware.smackx.ox.element.CryptElement;
|
||||||
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
||||||
import org.jivesoftware.smackx.ox.element.SignElement;
|
import org.jivesoftware.smackx.ox.element.SignElement;
|
||||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
|
||||||
public interface OpenPgpProvider {
|
public interface OpenPgpProvider {
|
||||||
|
|
||||||
OpenPgpElement signAndEncrypt(SigncryptElement element, Collection<OpenPgpContact> recipients);
|
OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients) throws IOException, PGPException;
|
||||||
|
|
||||||
OpenPgpElement sign(SignElement element);
|
OpenPgpElement sign(SignElement element, OpenPgpSelf self) throws IOException, PGPException;
|
||||||
|
|
||||||
OpenPgpElement encrypt(CryptElement element, Collection<OpenPgpContact> recipients);
|
OpenPgpElement encrypt(CryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients) throws IOException, PGPException;
|
||||||
|
|
||||||
OpenPgpMessage decryptAndOrVerify(OpenPgpElement element);
|
OpenPgpMessage decryptAndOrVerify(OpenPgpElement element, OpenPgpSelf self, OpenPgpContact sender) throws IOException, PGPException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package org.jivesoftware.smackx.ox.v2;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpStore;
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
public class OpenPgpSelf extends OpenPgpContact {
|
||||||
|
|
||||||
|
public OpenPgpSelf(BareJid jid, OpenPgpStore store) {
|
||||||
|
super(jid, store);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasSecretKeyAvailable() throws IOException, PGPException {
|
||||||
|
return getSecretKeys() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRingCollection getSecretKeys() throws IOException, PGPException {
|
||||||
|
return store.getSecretKeysOf(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing getSigningKeyRing() throws IOException, PGPException {
|
||||||
|
PGPSecretKeyRingCollection secretKeyRings = getSecretKeys();
|
||||||
|
if (secretKeyRings == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPSecretKeyRing signingKeyRing = null;
|
||||||
|
for (PGPSecretKeyRing ring : secretKeyRings) {
|
||||||
|
if (signingKeyRing == null) {
|
||||||
|
signingKeyRing = ring;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ring.getPublicKey().getCreationTime().after(signingKeyRing.getPublicKey().getCreationTime())) {
|
||||||
|
signingKeyRing = ring;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return signingKeyRing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenPgpV4Fingerprint getSigningKeyFingerprint() throws IOException, PGPException {
|
||||||
|
PGPSecretKeyRing signingKeyRing = getSigningKeyRing();
|
||||||
|
return signingKeyRing != null ? new OpenPgpV4Fingerprint(signingKeyRing.getPublicKey()) : null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package org.jivesoftware.smackx.ox.v2;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
||||||
|
import org.jivesoftware.smackx.ox.element.CryptElement;
|
||||||
|
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
||||||
|
import org.jivesoftware.smackx.ox.element.SignElement;
|
||||||
|
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
import org.bouncycastle.util.io.Streams;
|
||||||
|
import org.pgpainless.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.pgpainless.decryption_verification.DecryptionStream;
|
||||||
|
import org.pgpainless.pgpainless.decryption_verification.PainlessResult;
|
||||||
|
import org.pgpainless.pgpainless.encryption_signing.EncryptionStream;
|
||||||
|
|
||||||
|
public class PainlessOpenPgpProvider implements OpenPgpProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients)
|
||||||
|
throws IOException, PGPException {
|
||||||
|
InputStream plainText = element.toInputStream();
|
||||||
|
ByteArrayOutputStream cipherText = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
ArrayList<PGPPublicKeyRingCollection> recipientKeys = new ArrayList<>();
|
||||||
|
for (OpenPgpContact contact : recipients) {
|
||||||
|
recipientKeys.add(contact.getAnnouncedPublicKeys());
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionStream cipherStream = PGPainless.createEncryptor().onOutputStream(cipherText)
|
||||||
|
.toRecipients(recipientKeys.toArray(new PGPPublicKeyRingCollection[]{}))
|
||||||
|
.andToSelf(self.getAnnouncedPublicKeys())
|
||||||
|
.usingSecureAlgorithms()
|
||||||
|
.signWith(null, self.getSigningKeyRing())
|
||||||
|
.noArmor();
|
||||||
|
|
||||||
|
Streams.pipeAll(plainText, cipherStream);
|
||||||
|
plainText.close();
|
||||||
|
cipherStream.flush();
|
||||||
|
cipherStream.close();
|
||||||
|
cipherText.close();
|
||||||
|
|
||||||
|
String base64 = Base64.encodeToString(cipherText.toByteArray());
|
||||||
|
// TODO: Return feedback about encryption?
|
||||||
|
return new OpenPgpElement(base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenPgpElement sign(SignElement element, OpenPgpSelf self)
|
||||||
|
throws IOException, PGPException {
|
||||||
|
InputStream plainText = element.toInputStream();
|
||||||
|
ByteArrayOutputStream cipherText = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
EncryptionStream cipherStream = PGPainless.createEncryptor().onOutputStream(cipherText)
|
||||||
|
.doNotEncrypt()
|
||||||
|
.signWith(null, self.getSigningKeyRing())
|
||||||
|
.noArmor();
|
||||||
|
|
||||||
|
Streams.pipeAll(plainText, cipherStream);
|
||||||
|
plainText.close();
|
||||||
|
cipherStream.flush();
|
||||||
|
cipherStream.close();
|
||||||
|
cipherText.close();
|
||||||
|
|
||||||
|
String base64 = Base64.encodeToString(cipherText.toByteArray());
|
||||||
|
return new OpenPgpElement(base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenPgpElement encrypt(CryptElement element, OpenPgpSelf self, Collection<OpenPgpContact> recipients)
|
||||||
|
throws IOException, PGPException {
|
||||||
|
InputStream plainText = element.toInputStream();
|
||||||
|
ByteArrayOutputStream cipherText = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
ArrayList<PGPPublicKeyRingCollection> recipientKeys = new ArrayList<>();
|
||||||
|
for (OpenPgpContact contact : recipients) {
|
||||||
|
recipientKeys.add(contact.getAnnouncedPublicKeys());
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionStream cipherStream = PGPainless.createEncryptor().onOutputStream(cipherText)
|
||||||
|
.toRecipients(recipientKeys.toArray(new PGPPublicKeyRingCollection[]{}))
|
||||||
|
.andToSelf(self.getAnnouncedPublicKeys())
|
||||||
|
.usingSecureAlgorithms()
|
||||||
|
.doNotSign()
|
||||||
|
.noArmor();
|
||||||
|
|
||||||
|
Streams.pipeAll(plainText, cipherStream);
|
||||||
|
plainText.close();
|
||||||
|
cipherStream.flush();
|
||||||
|
cipherStream.close();
|
||||||
|
cipherText.close();
|
||||||
|
|
||||||
|
String base64 = Base64.encodeToString(cipherText.toByteArray());
|
||||||
|
// TODO: Return feedback about encryption?
|
||||||
|
return new OpenPgpElement(base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenPgpMessage decryptAndOrVerify(OpenPgpElement element, OpenPgpSelf self, OpenPgpContact sender) throws IOException, PGPException {
|
||||||
|
ByteArrayOutputStream plainText = new ByteArrayOutputStream();
|
||||||
|
InputStream cipherText = element.toInputStream();
|
||||||
|
|
||||||
|
DecryptionStream cipherStream = PGPainless.createDecryptor().onInputStream(cipherText)
|
||||||
|
.decryptWith(null, self.getSecretKeys())
|
||||||
|
.verifyWith(sender.getAnnouncedPublicKeys())
|
||||||
|
.ignoreMissingPublicKeys()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Streams.pipeAll(cipherStream, plainText);
|
||||||
|
|
||||||
|
cipherText.close();
|
||||||
|
cipherStream.close();
|
||||||
|
plainText.close();
|
||||||
|
|
||||||
|
PainlessResult info = cipherStream.getResult();
|
||||||
|
|
||||||
|
return new OpenPgpMessage(plainText.toByteArray(), new OpenPgpMessage.Metadata(
|
||||||
|
info.getDecryptionKeyId(), info.getVerifiedSignatureKeyIds()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.v2.store;
|
package org.jivesoftware.smackx.ox.v2.store.abstr;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
@ -24,6 +24,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpKeyStore;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.v2.store;
|
package org.jivesoftware.smackx.ox.v2.store.abstr;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -22,6 +22,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpMetadataStore;
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
|
@ -14,20 +14,25 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.v2.store;
|
package org.jivesoftware.smackx.ox.v2.store.abstr;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Observable;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.Objects;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpContact;
|
import org.jivesoftware.smackx.ox.OpenPgpContact;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback;
|
import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback;
|
||||||
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpKeyStore;
|
||||||
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpMetadataStore;
|
||||||
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpStore;
|
||||||
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpTrustStore;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
@ -37,24 +42,26 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.pgpainless.pgpainless.key.protection.SecretKeyRingProtector;
|
import org.pgpainless.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
|
|
||||||
public abstract class OpenPgpStore implements OpenPgpKeyStore, OpenPgpMetadataStore, OpenPgpTrustStore {
|
public abstract class AbstractOpenPgpStore extends Observable implements OpenPgpStore {
|
||||||
|
|
||||||
protected final OpenPgpKeyStore keyStore;
|
protected final OpenPgpKeyStore keyStore;
|
||||||
protected final OpenPgpMetadataStore metadataStore;
|
protected final OpenPgpMetadataStore metadataStore;
|
||||||
protected final OpenPgpTrustStore trustStore;
|
protected final OpenPgpTrustStore trustStore;
|
||||||
|
|
||||||
protected SecretKeyPassphraseCallback secretKeyPassphraseCallback;
|
protected SecretKeyPassphraseCallback secretKeyPassphraseCallback;
|
||||||
|
protected SecretKeyRingProtector unlocker;
|
||||||
protected final Map<BareJid, OpenPgpContact> contacts = new HashMap<>();
|
protected final Map<BareJid, OpenPgpContact> contacts = new HashMap<>();
|
||||||
|
|
||||||
public OpenPgpStore(OpenPgpKeyStore keyStore,
|
protected AbstractOpenPgpStore(OpenPgpKeyStore keyStore,
|
||||||
OpenPgpMetadataStore metadataStore,
|
OpenPgpMetadataStore metadataStore,
|
||||||
OpenPgpTrustStore trustStore) {
|
OpenPgpTrustStore trustStore) {
|
||||||
this.keyStore = keyStore;
|
this.keyStore = Objects.requireNonNull(keyStore);
|
||||||
this.metadataStore = metadataStore;
|
this.metadataStore = Objects.requireNonNull(metadataStore);
|
||||||
this.trustStore = trustStore;
|
this.trustStore = Objects.requireNonNull(trustStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenPgpContact getContact(BareJid jid) {
|
@Override
|
||||||
|
public OpenPgpContact getOpenPgpContact(BareJid jid) {
|
||||||
OpenPgpContact contact = contacts.get(jid);
|
OpenPgpContact contact = contacts.get(jid);
|
||||||
if (contact != null) {
|
if (contact != null) {
|
||||||
return contact;
|
return contact;
|
||||||
|
@ -64,11 +71,13 @@ public abstract class OpenPgpStore implements OpenPgpKeyStore, OpenPgpMetadataSt
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setKeyRingProtector(SecretKeyRingProtector protector) {
|
public void setKeyRingProtector(SecretKeyRingProtector protector) {
|
||||||
|
this.unlocker = protector;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUnknownSecretKeyPassphraseCallback(SecretKeyPassphraseCallback callback) {
|
@Override
|
||||||
|
public void setSecretKeyPassphraseCallback(SecretKeyPassphraseCallback callback) {
|
||||||
this.secretKeyPassphraseCallback = callback;
|
this.secretKeyPassphraseCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,31 +85,11 @@ public abstract class OpenPgpStore implements OpenPgpKeyStore, OpenPgpMetadataSt
|
||||||
OpenPgpKeyStore
|
OpenPgpKeyStore
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPPublicKeyRingCollection readPublicKeysOf(BareJid owner) throws IOException, PGPException {
|
|
||||||
return keyStore.readPublicKeysOf(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writePublicKeysOf(BareJid owner, PGPPublicKeyRingCollection publicKeys) throws IOException {
|
|
||||||
keyStore.writePublicKeysOf(owner, publicKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException {
|
public PGPPublicKeyRingCollection getPublicKeysOf(BareJid owner) throws IOException, PGPException {
|
||||||
return keyStore.getPublicKeysOf(owner);
|
return keyStore.getPublicKeysOf(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PGPSecretKeyRingCollection readSecretKeysOf(BareJid owner) throws IOException, PGPException {
|
|
||||||
return keyStore.readSecretKeysOf(owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeSecretKeysOf(BareJid owner, PGPSecretKeyRingCollection secretKeys) throws IOException {
|
|
||||||
keyStore.writeSecretKeysOf(owner, secretKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException {
|
public PGPSecretKeyRingCollection getSecretKeysOf(BareJid owner) throws IOException, PGPException {
|
||||||
return keyStore.getSecretKeysOf(owner);
|
return keyStore.getSecretKeysOf(owner);
|
||||||
|
@ -126,18 +115,13 @@ public abstract class OpenPgpStore implements OpenPgpKeyStore, OpenPgpMetadataSt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<OpenPgpV4Fingerprint> getAnnouncedFingerprintsOf(BareJid contact) throws IOException {
|
public Map<OpenPgpV4Fingerprint, Date> getAnnouncedFingerprintsOf(BareJid contact) throws IOException {
|
||||||
return metadataStore.getAnnouncedFingerprintsOf(contact);
|
return metadataStore.getAnnouncedFingerprintsOf(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<OpenPgpV4Fingerprint> readAnnouncedFingerprintsOf(BareJid contact) throws IOException {
|
public void setAnnouncedFingerprintsOf(BareJid contact, Map<OpenPgpV4Fingerprint, Date> data) throws IOException {
|
||||||
return metadataStore.readAnnouncedFingerprintsOf(contact);
|
metadataStore.setAnnouncedFingerprintsOf(contact, data);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeAnnouncedFingerprintsOf(BareJid contact, PublicKeysListElement metadata) throws IOException {
|
|
||||||
metadataStore.writeAnnouncedFingerprintsOf(contact, metadata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -145,12 +129,12 @@ public abstract class OpenPgpStore implements OpenPgpKeyStore, OpenPgpMetadataSt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Trust getTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) {
|
public Trust getTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint) throws IOException {
|
||||||
return trustStore.getTrust(owner, fingerprint);
|
return trustStore.getTrust(owner, fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) {
|
public void setTrust(BareJid owner, OpenPgpV4Fingerprint fingerprint, Trust trust) throws IOException {
|
||||||
trustStore.setTrust(owner, fingerprint, trust);
|
trustStore.setTrust(owner, fingerprint, trust);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package org.jivesoftware.smackx.ox.v2.store;
|
package org.jivesoftware.smackx.ox.v2.store.abstr;
|
||||||
|
|
||||||
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 org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
|
import org.jivesoftware.smackx.ox.v2.store.definition.OpenPgpTrustStore;
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.v2.store;
|
package org.jivesoftware.smackx.ox.v2.store.definition;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.v2.store;
|
package org.jivesoftware.smackx.ox.v2.store.definition;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.jivesoftware.smackx.ox.v2.store.definition;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpContact;
|
||||||
|
import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.pgpainless.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
|
|
||||||
|
public interface OpenPgpStore extends OpenPgpKeyStore, OpenPgpMetadataStore, OpenPgpTrustStore {
|
||||||
|
|
||||||
|
OpenPgpContact getOpenPgpContact(BareJid contactsJid);
|
||||||
|
|
||||||
|
void setKeyRingProtector(SecretKeyRingProtector unlocker);
|
||||||
|
|
||||||
|
SecretKeyRingProtector getKeyRingProtector();
|
||||||
|
|
||||||
|
void setSecretKeyPassphraseCallback(SecretKeyPassphraseCallback callback);
|
||||||
|
|
||||||
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.v2.store;
|
package org.jivesoftware.smackx.ox.v2.store.definition;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.Objects;
|
import org.jivesoftware.smack.util.Objects;
|
||||||
import org.jivesoftware.smackx.ox.v2.store.AbstractOpenPgpKeyStore;
|
import org.jivesoftware.smackx.ox.v2.store.abstr.AbstractOpenPgpKeyStore;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
|
|
@ -30,7 +30,7 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
import org.jivesoftware.smackx.ox.util.Util;
|
import org.jivesoftware.smackx.ox.util.Util;
|
||||||
import org.jivesoftware.smackx.ox.v2.store.AbstractOpenPgpMetadataStore;
|
import org.jivesoftware.smackx.ox.v2.store.abstr.AbstractOpenPgpMetadataStore;
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
import org.jxmpp.util.XmppDateTime;
|
import org.jxmpp.util.XmppDateTime;
|
||||||
|
|
|
@ -19,11 +19,11 @@ package org.jivesoftware.smackx.ox.v2.store.filebased;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.Objects;
|
import org.jivesoftware.smack.util.Objects;
|
||||||
import org.jivesoftware.smackx.ox.v2.store.OpenPgpStore;
|
import org.jivesoftware.smackx.ox.v2.store.abstr.AbstractOpenPgpStore;
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
public class FileBasedOpenPgpStore extends OpenPgpStore {
|
public class FileBasedOpenPgpStore extends AbstractOpenPgpStore {
|
||||||
|
|
||||||
public FileBasedOpenPgpStore(File basePath) {
|
public FileBasedOpenPgpStore(File basePath) {
|
||||||
super(new FileBasedOpenPgpKeyStore(basePath),
|
super(new FileBasedOpenPgpKeyStore(basePath),
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
import org.jivesoftware.smackx.ox.util.Util;
|
import org.jivesoftware.smackx.ox.util.Util;
|
||||||
import org.jivesoftware.smackx.ox.v2.store.AbstractOpenPgpTrustStore;
|
import org.jivesoftware.smackx.ox.v2.store.abstr.AbstractOpenPgpTrustStore;
|
||||||
|
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue