mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-27 14:32:06 +01:00
Finish rewrite :D
This commit is contained in:
parent
2b7738cc9c
commit
f522cea748
12 changed files with 437 additions and 559 deletions
|
@ -0,0 +1,4 @@
|
||||||
|
package org.jivesoftware.smackx.openpgp;
|
||||||
|
|
||||||
|
public class OpenPgpIntegrationTest {
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2015 Florian Schmaus
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smacks implementation of XEP-0199: XMPP Ping.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.ping;
|
|
@ -1,11 +1,18 @@
|
||||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpProvider;
|
import org.jivesoftware.smackx.ox.OpenPgpProvider;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
|
@ -22,21 +29,34 @@ import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||||
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 name.neuhalfen.projects.crypto.bouncycastle.openpgp.BouncyGPG;
|
||||||
|
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PublicKeySize;
|
||||||
|
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.XmppKeySelectionStrategy;
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPKeyRingGenerator;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||||
|
|
||||||
public class BCOpenPgpProvider implements OpenPgpProvider {
|
public class BCOpenPgpProvider implements OpenPgpProvider {
|
||||||
|
|
||||||
private final BareJid user;
|
private final BareJid user;
|
||||||
private OpenPgpV4Fingerprint primaryKeyPair;
|
private OpenPgpV4Fingerprint primaryKeyPair;
|
||||||
|
|
||||||
|
private BCOpenPgpStore store;
|
||||||
|
|
||||||
|
|
||||||
public BCOpenPgpProvider(BareJid user) {
|
public BCOpenPgpProvider(BareJid user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.primaryKeyPair = null;
|
this.primaryKeyPair = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setStore(BCOpenPgpStore store) {
|
||||||
|
this.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpV4Fingerprint primaryOpenPgpKeyPairFingerprint() {
|
public OpenPgpV4Fingerprint primaryOpenPgpKeyPairFingerprint() {
|
||||||
return primaryKeyPair;
|
return primaryKeyPair;
|
||||||
|
@ -44,89 +64,153 @@ public class BCOpenPgpProvider implements OpenPgpProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeyPairFingerprints() {
|
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeyPairFingerprints() {
|
||||||
return null;
|
return store.availableOpenPgpKeyPairFingerprints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<OpenPgpV4Fingerprint> announcedOpenPgpKeyFingerprints(BareJid contact) {
|
public Set<OpenPgpV4Fingerprint> announcedOpenPgpKeyFingerprints(BareJid contact) {
|
||||||
return null;
|
return store.announcedOpenPgpKeyFingerprints(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpV4Fingerprint signingKey, Set<OpenPgpV4Fingerprint> encryptionKeys)
|
public OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpV4Fingerprint signingKey, Set<OpenPgpV4Fingerprint> encryptionKeys)
|
||||||
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException {
|
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException {
|
||||||
return null;
|
if (encryptionKeys.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Set of recipients must not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptionKeys.addAll(store.announcedOpenPgpKeyFingerprints(user));
|
||||||
|
long[] recipientIds = new long[encryptionKeys.size()];
|
||||||
|
int pos = 0;
|
||||||
|
for (OpenPgpV4Fingerprint f : encryptionKeys) {
|
||||||
|
recipientIds[pos++] = f.getKeyId();
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream inputStream = element.toInputStream();
|
||||||
|
ByteArrayOutputStream encryptedOut = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
try {
|
||||||
|
OutputStream encryptor = BouncyGPG.encryptToStream()
|
||||||
|
.withConfig(store.getKeyringConfig())
|
||||||
|
.withKeySelectionStrategy(new XmppKeySelectionStrategy(new Date()))
|
||||||
|
.withOxAlgorithms()
|
||||||
|
.toRecipients(recipientIds)
|
||||||
|
.andSignWith(signingKey.getKeyId())
|
||||||
|
.binaryOutput()
|
||||||
|
.andWriteTo(encryptedOut);
|
||||||
|
|
||||||
|
Streams.pipeAll(inputStream, encryptor);
|
||||||
|
encryptor.close();
|
||||||
|
|
||||||
|
String base64 = Base64.encodeToString(encryptedOut.toByteArray());
|
||||||
|
|
||||||
|
return new OpenPgpElement(base64);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
// TODO: Later
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpMessage decryptAndVerify(OpenPgpElement element, Set<OpenPgpV4Fingerprint> sendersKeys)
|
public OpenPgpMessage decryptAndVerify(OpenPgpElement element, Set<OpenPgpV4Fingerprint> sendersKeys)
|
||||||
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException {
|
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException {
|
||||||
|
|
||||||
|
ByteArrayInputStream encryptedIn = new ByteArrayInputStream(
|
||||||
|
element.getEncryptedBase64MessageContent().getBytes(Charset.forName("UTF-8")));
|
||||||
|
|
||||||
|
try {
|
||||||
|
InputStream decrypted = BouncyGPG.decryptAndVerifyStream()
|
||||||
|
.withConfig(store.getKeyringConfig())
|
||||||
|
.withKeySelectionStrategy(new XmppKeySelectionStrategy(new Date()))
|
||||||
|
.andValidateSomeoneSigned() // TODO: Validate using sender keys
|
||||||
|
.fromEncryptedInputStream(encryptedIn);
|
||||||
|
|
||||||
|
ByteArrayOutputStream decryptedOut = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
Streams.pipeAll(decrypted, decryptedOut);
|
||||||
|
|
||||||
|
return new OpenPgpMessage(OpenPgpMessage.State.signcrypt, new String(decryptedOut.toByteArray(), Charset.forName("UTF-8")));
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO: Hm...
|
||||||
return null;
|
return null;
|
||||||
|
} catch (NoSuchProviderException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpElement sign(SignElement element, OpenPgpV4Fingerprint singingKeyFingerprint)
|
public OpenPgpElement sign(SignElement element, OpenPgpV4Fingerprint singingKeyFingerprint)
|
||||||
throws MissingOpenPgpKeyPairException {
|
throws MissingOpenPgpKeyPairException {
|
||||||
return null;
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpMessage verify(OpenPgpElement element, Set<OpenPgpV4Fingerprint> singingKeyFingerprints)
|
public OpenPgpMessage verify(OpenPgpElement element, Set<OpenPgpV4Fingerprint> singingKeyFingerprints)
|
||||||
throws MissingOpenPgpPublicKeyException {
|
throws MissingOpenPgpPublicKeyException {
|
||||||
return null;
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpElement encrypt(CryptElement element, Set<OpenPgpV4Fingerprint> encryptionKeyFingerprints)
|
public OpenPgpElement encrypt(CryptElement element, Set<OpenPgpV4Fingerprint> encryptionKeyFingerprints)
|
||||||
throws MissingOpenPgpPublicKeyException {
|
throws MissingOpenPgpPublicKeyException {
|
||||||
return null;
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpMessage decrypt(OpenPgpElement element) throws MissingOpenPgpKeyPairException {
|
public OpenPgpMessage decrypt(OpenPgpElement element) throws MissingOpenPgpKeyPairException {
|
||||||
return null;
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PubkeyElement createPubkeyElement(OpenPgpV4Fingerprint fingerprint)
|
public PubkeyElement createPubkeyElement(OpenPgpV4Fingerprint fingerprint)
|
||||||
throws MissingOpenPgpPublicKeyException, CorruptedOpenPgpKeyException {
|
throws MissingOpenPgpPublicKeyException, CorruptedOpenPgpKeyException {
|
||||||
return null;
|
return store.createPubkeyElement(fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void storePublicKey(BareJid owner, OpenPgpV4Fingerprint fingerprint, PubkeyElement element)
|
public void storePublicKey(BareJid owner, OpenPgpV4Fingerprint fingerprint, PubkeyElement element)
|
||||||
throws CorruptedOpenPgpKeyException {
|
throws CorruptedOpenPgpKeyException {
|
||||||
|
store.storePublicKey(owner, fingerprint, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void storePublicKeysList(XMPPConnection connection, PublicKeysListElement listElement, BareJid owner)
|
public void storePublicKeysList(XMPPConnection connection, PublicKeysListElement listElement, BareJid owner) {
|
||||||
throws CorruptedOpenPgpKeyException, InterruptedException, SmackException.NotConnectedException,
|
store.storePublicKeysList(connection, listElement, owner);
|
||||||
SmackException.NoResponseException {
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenPgpV4Fingerprint createOpenPgpKeyPair()
|
||||||
|
throws NoSuchAlgorithmException, NoSuchProviderException, CorruptedOpenPgpKeyException {
|
||||||
|
return store.createOpenPgpKeyPair();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretkeyElement createSecretkeyElement(Set<OpenPgpV4Fingerprint> fingerprints, String password)
|
public SecretkeyElement createSecretkeyElement(Set<OpenPgpV4Fingerprint> fingerprints, String password)
|
||||||
throws MissingOpenPgpKeyPairException, CorruptedOpenPgpKeyException {
|
throws MissingOpenPgpKeyPairException, CorruptedOpenPgpKeyException {
|
||||||
return null;
|
return store.createSecretkeyElement(fingerprints, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeysFingerprints(BareJid contact) {
|
public Set<OpenPgpV4Fingerprint> availableOpenPgpPublicKeysFingerprints(BareJid contact)
|
||||||
return null;
|
throws CorruptedOpenPgpKeyException {
|
||||||
|
return store.availableOpenPgpPublicKeysFingerprints(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restoreSecretKeyBackup(SecretkeyElement secretkeyElement, String password, SecretKeyRestoreSelectionCallback callback)
|
public void restoreSecretKeyBackup(SecretkeyElement secretkeyElement, String password, SecretKeyRestoreSelectionCallback callback)
|
||||||
throws CorruptedOpenPgpKeyException, InvalidBackupCodeException {
|
throws CorruptedOpenPgpKeyException, InvalidBackupCodeException {
|
||||||
|
store.restoreSecretKeyBackup(secretkeyElement, password, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
static PGPKeyRingGenerator generateKey(BareJid owner)
|
||||||
public OpenPgpV4Fingerprint createOpenPgpKeyPair()
|
throws NoSuchAlgorithmException, PGPException, NoSuchProviderException {
|
||||||
throws NoSuchAlgorithmException, NoSuchProviderException {
|
PGPKeyRingGenerator generator = BouncyGPG.createKeyPair()
|
||||||
return null;
|
.withRSAKeys()
|
||||||
|
.ofSize(PublicKeySize.RSA._2048)
|
||||||
|
.forIdentity("xmpp:" + owner.toString())
|
||||||
|
.withoutPassphrase()
|
||||||
|
.build();
|
||||||
|
return generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) {
|
public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) {
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.ox.OpenPgpStore;
|
||||||
|
|
||||||
|
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfig;
|
||||||
|
|
||||||
|
public interface BCOpenPgpStore extends OpenPgpStore {
|
||||||
|
|
||||||
|
KeyringConfig getKeyringConfig();
|
||||||
|
}
|
|
@ -1,414 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 Florian Schmaus.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
|
||||||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpProvider;
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
|
||||||
import org.jivesoftware.smackx.ox.Util;
|
|
||||||
import org.jivesoftware.smackx.ox.callback.SecretKeyRestoreSelectionCallback;
|
|
||||||
import org.jivesoftware.smackx.ox.element.CryptElement;
|
|
||||||
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
|
||||||
import org.jivesoftware.smackx.ox.element.PubkeyElement;
|
|
||||||
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
|
|
||||||
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
|
||||||
import org.jivesoftware.smackx.ox.element.SignElement;
|
|
||||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
|
||||||
import org.jivesoftware.smackx.ox.exception.CorruptedOpenPgpKeyException;
|
|
||||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
|
||||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
|
||||||
|
|
||||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.BouncyGPG;
|
|
||||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PublicKeySize;
|
|
||||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.InMemoryKeyring;
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
|
||||||
import org.bouncycastle.openpgp.PGPKeyRingGenerator;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
|
||||||
import org.jxmpp.jid.BareJid;
|
|
||||||
|
|
||||||
public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(BouncyCastleOpenPgpProvider.class.getName());
|
|
||||||
|
|
||||||
private final BareJid ourJid;
|
|
||||||
private OpenPgpV4Fingerprint primaryKeyPairFingerprint;
|
|
||||||
private InMemoryKeyring keyring;
|
|
||||||
|
|
||||||
private final Map<BareJid, Set<OpenPgpV4Fingerprint>> contactsFingerprints = new HashMap<>();
|
|
||||||
|
|
||||||
public BouncyCastleOpenPgpProvider(BareJid ourJid) {
|
|
||||||
this.ourJid = ourJid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public PubkeyElement createPubkeyElement(OpenPgpV4Fingerprint keyFingerprint)
|
|
||||||
throws MissingOpenPgpPublicKeyException, CorruptedOpenPgpKeyException {
|
|
||||||
// TODO: throw missing key exception
|
|
||||||
try {
|
|
||||||
PGPPublicKey pubKey = keyring.getPublicKeyRings().getPublicKey(Util.keyIdFromFingerprint(keyFingerprint));
|
|
||||||
PubkeyElement.PubkeyDataElement dataElement = new PubkeyElement.PubkeyDataElement(
|
|
||||||
Base64.encode(pubKey.getEncoded()));
|
|
||||||
return new PubkeyElement(dataElement, new Date());
|
|
||||||
} catch (PGPException | IOException e) {
|
|
||||||
throw new CorruptedOpenPgpKeyException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public SecretkeyElement createSecretkeyElement(Set<OpenPgpV4Fingerprint> fingerprints, String password) throws MissingOpenPgpKeyPairException, CorruptedOpenPgpKeyException {
|
|
||||||
/*
|
|
||||||
try {
|
|
||||||
// Our unencrypted secret key
|
|
||||||
PGPSecretKey secretKey;
|
|
||||||
try {
|
|
||||||
secretKey = ourKeys.getSecretKeyRings().getSecretKey(ourKeyId);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
throw new MissingOpenPgpKeyPairException(ourJid);
|
|
||||||
}
|
|
||||||
|
|
||||||
PGPDigestCalculator calculator = new JcaPGPDigestCalculatorProviderBuilder()
|
|
||||||
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
|
||||||
.build()
|
|
||||||
.get(HashAlgorithmTags.SHA1);
|
|
||||||
|
|
||||||
PBESecretKeyEncryptor encryptor = new JcePBESecretKeyEncryptorBuilder(
|
|
||||||
PGPSymmetricEncryptionAlgorithms.AES_256.getAlgorithmId())
|
|
||||||
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
|
||||||
.build(password.toCharArray());
|
|
||||||
|
|
||||||
PGPSecretKey encrypted = new PGPSecretKey(
|
|
||||||
secretKey.extractPrivateKey(null),
|
|
||||||
secretKey.getPublicKey(),
|
|
||||||
calculator,
|
|
||||||
true,
|
|
||||||
encryptor);
|
|
||||||
|
|
||||||
byte[] base64 = Base64.encode(encrypted.getEncoded());
|
|
||||||
|
|
||||||
return new SecretkeyElement(base64);
|
|
||||||
|
|
||||||
} catch (PGPException | IOException e) {
|
|
||||||
throw new CorruptedOpenPgpKeyException(e);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void storePublicKey(BareJid owner, OpenPgpV4Fingerprint fingerprint, PubkeyElement element) throws CorruptedOpenPgpKeyException {
|
|
||||||
/*
|
|
||||||
byte[] decoded = Base64.decode(element.getDataElement().getB64Data());
|
|
||||||
|
|
||||||
try {
|
|
||||||
InMemoryKeyring contactsKeyring = theirKeys.get(owner);
|
|
||||||
if (contactsKeyring == null) {
|
|
||||||
contactsKeyring = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys());
|
|
||||||
theirKeys.put(owner, contactsKeyring);
|
|
||||||
}
|
|
||||||
|
|
||||||
contactsKeyring.addPublicKey(decoded);
|
|
||||||
} catch (IOException | PGPException e) {
|
|
||||||
throw new CorruptedOpenPgpKeyException(e);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void storePublicKeysList(XMPPConnection connection, PublicKeysListElement listElement, BareJid owner) {
|
|
||||||
/*
|
|
||||||
InMemoryKeyring contactsKeys = theirKeys.get(owner);
|
|
||||||
for (OpenPgpV4Fingerprint fingerprint : listElement.getMetadata().keySet()) {
|
|
||||||
byte[] asBytes = fingerprint.toString().getBytes(Charset.forName("UTF-8"));
|
|
||||||
try {
|
|
||||||
if (contactsKeys.getPublicKeyRings().getPublicKey(asBytes) == null) {
|
|
||||||
try {
|
|
||||||
PubkeyElement pubkey = PubSubDelegate.fetchPubkey(connection, owner, fingerprint);
|
|
||||||
storePublicKey(pubkey, owner);
|
|
||||||
} catch (PubSubException.NotAPubSubNodeException | PubSubException.NotALeafNodeException |
|
|
||||||
XMPPException.XMPPErrorException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Could not fetch public key " + fingerprint + " of " + owner + ".", e);
|
|
||||||
} catch (CorruptedOpenPgpKeyException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Key " + fingerprint + " of " + owner + " is corrupted and cannot be imported.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (PGPException | IOException e) {
|
|
||||||
throw new CorruptedOpenPgpKeyException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void restoreSecretKeyBackup(SecretkeyElement secretkeyElement, String password, SecretKeyRestoreSelectionCallback callback)
|
|
||||||
throws CorruptedOpenPgpKeyException {
|
|
||||||
/*
|
|
||||||
byte[] encoded = Base64.decode(secretkeyElement.getB64Data());
|
|
||||||
|
|
||||||
try {
|
|
||||||
PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
|
|
||||||
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
InMemoryKeyring keyring = KeyringConfigs.forGpgExportedKeys(
|
|
||||||
KeyringConfigCallbacks.withPassword(password));
|
|
||||||
keyring.addSecretKey(encoded);
|
|
||||||
for (PGPSecretKeyRing r : keyring.getSecretKeyRings()) {
|
|
||||||
PGPSecretKey s = r.getSecretKey();
|
|
||||||
PGPPrivateKey privateKey = s.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(calculatorProvider).build(password.toCharArray()));
|
|
||||||
PGPPublicKey publicKey = s.getPublicKey();
|
|
||||||
PGPSecretKey secretKey = new PGPSecretKey(
|
|
||||||
privateKey,
|
|
||||||
publicKey,
|
|
||||||
calculatorProvider.get(PGPHashAlgorithms.SHA1.getAlgorithmId()),
|
|
||||||
true,
|
|
||||||
null);
|
|
||||||
|
|
||||||
InMemoryKeyring newKeyring = KeyringConfigs.forGpgExportedKeys(
|
|
||||||
KeyringConfigCallbacks.withUnprotectedKeys());
|
|
||||||
|
|
||||||
newKeyring.addPublicKey(secretKey.getPublicKey().getEncoded());
|
|
||||||
newKeyring.addSecretKey(secretKey.getEncoded());
|
|
||||||
|
|
||||||
ourKeys = newKeyring;
|
|
||||||
ourKeyId = secretKey.getKeyID();
|
|
||||||
|
|
||||||
InMemoryKeyring theirKeyRing = KeyringConfigs.forGpgExportedKeys(
|
|
||||||
KeyringConfigCallbacks.withUnprotectedKeys());
|
|
||||||
theirKeyRing.addPublicKey(secretKey.getPublicKey().getEncoded());
|
|
||||||
|
|
||||||
theirKeys.put(ourJid, theirKeyRing);
|
|
||||||
}
|
|
||||||
} catch (PGPException | IOException e) {
|
|
||||||
throw new CorruptedOpenPgpKeyException(e);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public OpenPgpV4Fingerprint primaryOpenPgpKeyPairFingerprint() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeyPairFingerprints() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Set<OpenPgpV4Fingerprint> announcedOpenPgpKeyFingerprints(BareJid contact) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeysFingerprints(BareJid contact) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public OpenPgpElement signAndEncrypt(SigncryptElement element,
|
|
||||||
OpenPgpV4Fingerprint signingKey,
|
|
||||||
Set<OpenPgpV4Fingerprint> encryptionKeys)
|
|
||||||
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException {
|
|
||||||
/*
|
|
||||||
if (encryptionKeys.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Set of recipients must not be empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
InMemoryKeyring encryptionConfig = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys());
|
|
||||||
|
|
||||||
// Add all recipients public keys to encryption config
|
|
||||||
for (BareJid recipient : recipients) {
|
|
||||||
KeyringConfig c = theirKeys.get(recipient);
|
|
||||||
for (PGPPublicKeyRing p : c.getPublicKeyRings()) {
|
|
||||||
encryptionConfig.addPublicKey(p.getPublicKey().getEncoded());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add our public and secret keys to encryption config
|
|
||||||
for (PGPPublicKeyRing p : ourKeys.getPublicKeyRings()) {
|
|
||||||
encryptionConfig.addPublicKey(p.getPublicKey().getEncoded());
|
|
||||||
}
|
|
||||||
for (PGPSecretKeyRing s : ourKeys.getSecretKeyRings()) {
|
|
||||||
encryptionConfig.addSecretKey(s.getSecretKey().getEncoded());
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] recipientUIDs = new String[recipients.size() + 1];
|
|
||||||
int pos = 0;
|
|
||||||
for (BareJid b : recipients) {
|
|
||||||
recipientUIDs[pos++] = "xmpp:" + b.toString();
|
|
||||||
}
|
|
||||||
recipientUIDs[pos] = "xmpp:" + ourJid.toString();
|
|
||||||
|
|
||||||
InputStream inputStream = element.toInputStream();
|
|
||||||
ByteArrayOutputStream encryptedOut = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
OutputStream encryptor = BouncyGPG.encryptToStream()
|
|
||||||
.withConfig(encryptionConfig)
|
|
||||||
.withKeySelectionStrategy(new XmppKeySelectionStrategy(new Date()))
|
|
||||||
.withOxAlgorithms()
|
|
||||||
.toRecipients(recipientUIDs)
|
|
||||||
.andSignWith(ourKeyId)
|
|
||||||
.binaryOutput()
|
|
||||||
.andWriteTo(encryptedOut);
|
|
||||||
|
|
||||||
Streams.pipeAll(inputStream, encryptor);
|
|
||||||
encryptor.close();
|
|
||||||
|
|
||||||
String base64 = Base64.encodeToString(encryptedOut.toByteArray());
|
|
||||||
|
|
||||||
return new OpenPgpElement(base64);
|
|
||||||
*/
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public OpenPgpMessage decryptAndVerify(OpenPgpElement element, Set<OpenPgpV4Fingerprint> possibleSigningKeys)
|
|
||||||
throws MissingOpenPgpPublicKeyException, MissingOpenPgpKeyPairException {
|
|
||||||
/*
|
|
||||||
InMemoryKeyring decryptionConfig = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys());
|
|
||||||
|
|
||||||
// Add our secret keys to decryption config
|
|
||||||
for (PGPSecretKeyRing s : ourKeys.getSecretKeyRings()) {
|
|
||||||
decryptionConfig.addSecretKey(s.getSecretKey().getEncoded());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add their public keys to decryption config
|
|
||||||
for (PGPPublicKeyRing p : theirKeys.get(sender).getPublicKeyRings()) {
|
|
||||||
decryptionConfig.addPublicKey(p.getPublicKey().getEncoded());
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] b64decoded = Base64.decode(element.getEncryptedBase64MessageContent());
|
|
||||||
|
|
||||||
ByteArrayInputStream encryptedIn = new ByteArrayInputStream(b64decoded);
|
|
||||||
|
|
||||||
InputStream decrypted = BouncyGPG.decryptAndVerifyStream()
|
|
||||||
.withConfig(decryptionConfig)
|
|
||||||
.withKeySelectionStrategy(new XmppKeySelectionStrategy(new Date()))
|
|
||||||
.andValidateSomeoneSigned()
|
|
||||||
.fromEncryptedInputStream(encryptedIn);
|
|
||||||
|
|
||||||
ByteArrayOutputStream decryptedOut = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
Streams.pipeAll(decrypted, decryptedOut);
|
|
||||||
|
|
||||||
return new OpenPgpMessage(OpenPgpMessage.State.signcrypt, new String(decryptedOut.toByteArray(), Charset.forName("UTF-8")));
|
|
||||||
*/
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OpenPgpElement sign(SignElement element, OpenPgpV4Fingerprint singingKeyFingerprint)
|
|
||||||
throws MissingOpenPgpKeyPairException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OpenPgpMessage verify(OpenPgpElement element, Set<OpenPgpV4Fingerprint> singingKeyFingerprints)
|
|
||||||
throws MissingOpenPgpPublicKeyException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OpenPgpElement encrypt(CryptElement element, Set<OpenPgpV4Fingerprint> encryptionKeyFingerprints)
|
|
||||||
throws MissingOpenPgpPublicKeyException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OpenPgpMessage decrypt(OpenPgpElement element) throws MissingOpenPgpKeyPairException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) {
|
|
||||||
byte[] hex = Hex.encode(publicKey.getFingerprint());
|
|
||||||
return new OpenPgpV4Fingerprint(hex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public OpenPgpV4Fingerprint createOpenPgpKeyPair()
|
|
||||||
throws NoSuchAlgorithmException, NoSuchProviderException {
|
|
||||||
/*
|
|
||||||
try {
|
|
||||||
PGPSecretKeyRing ourKey = generateKey(ourJid).generateSecretKeyRing();
|
|
||||||
primaryKeyPairFingerprint = getFingerprint(ourKey.getPublicKey());
|
|
||||||
ourKeys = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys());
|
|
||||||
ourKeys.addSecretKey(ourKey.getSecretKey().getEncoded());
|
|
||||||
ourKeys.addPublicKey(ourKey.getPublicKey().getEncoded());
|
|
||||||
} catch (PGPException | IOException e) {
|
|
||||||
throw new CorruptedOpenPgpKeyException(e);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PGPKeyRingGenerator generateKey(BareJid owner)
|
|
||||||
throws NoSuchAlgorithmException, PGPException, NoSuchProviderException {
|
|
||||||
PGPKeyRingGenerator generator = BouncyGPG.createKeyPair()
|
|
||||||
.withRSAKeys()
|
|
||||||
.ofSize(PublicKeySize.RSA._2048)
|
|
||||||
.forIdentity("xmpp:" + owner.toString())
|
|
||||||
.withoutPassphrase()
|
|
||||||
.build();
|
|
||||||
return generator;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,20 +1,30 @@
|
||||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileWriter;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpStore;
|
|
||||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||||
import org.jivesoftware.smackx.ox.Util;
|
import org.jivesoftware.smackx.ox.Util;
|
||||||
import org.jivesoftware.smackx.ox.callback.SecretKeyRestoreSelectionCallback;
|
import org.jivesoftware.smackx.ox.callback.SecretKeyRestoreSelectionCallback;
|
||||||
|
@ -26,18 +36,30 @@ import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||||
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 name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PGPHashAlgorithms;
|
||||||
|
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PGPSymmetricEncryptionAlgorithms;
|
||||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallback;
|
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallback;
|
||||||
|
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.InMemoryKeyring;
|
||||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfig;
|
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfig;
|
||||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfigs;
|
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfigs;
|
||||||
|
import org.bouncycastle.bcpg.HashAlgorithmTags;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||||
|
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
|
||||||
|
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
|
||||||
|
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
|
||||||
|
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
||||||
|
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
public class FileBasedBcOpenPgpStore implements BCOpenPgpStore {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(FileBasedBcOpenPgpStore.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(FileBasedBcOpenPgpStore.class.getName());
|
||||||
|
|
||||||
|
@ -66,68 +88,14 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
configCallback = passwordCallback;
|
configCallback = passwordCallback;
|
||||||
keyringConfig = KeyringConfigs.forGpgExportedKeys(configCallback);
|
keyringConfig = KeyringConfigs.forGpgExportedKeys(configCallback);
|
||||||
|
|
||||||
KeyringConfig load = KeyringConfigs.withKeyRingsFromFiles(pub, sec, passwordCallback);
|
addPublicKeysFromFile(keyringConfig, pub, configCallback);
|
||||||
for (PGPPublicKeyRing pubRing : load.getPublicKeyRings()) {
|
PGPPublicKey lastAdded = addSecretKeysFromFile(keyringConfig, sec, configCallback);
|
||||||
for (PGPPublicKey pubKey : pubRing) {
|
|
||||||
keyringConfig.addPublicKey(pubKey.getEncoded());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PGPPublicKey lastAdded = null;
|
|
||||||
|
|
||||||
for (PGPSecretKeyRing secRing : load.getSecretKeyRings()) {
|
|
||||||
for (PGPSecretKey secKey : secRing) {
|
|
||||||
keyringConfig.addSecretKey(secKey.getEncoded());
|
|
||||||
// Remember last added secret keys public key -> this will be the primary key
|
|
||||||
if (secKey.getPublicKey() != null) {
|
|
||||||
lastAdded = secKey.getPublicKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastAdded != null) {
|
if (lastAdded != null) {
|
||||||
primaryKeyFingerprint = BCOpenPgpProvider.getFingerprint(lastAdded);
|
primaryKeyFingerprint = BCOpenPgpProvider.getFingerprint(lastAdded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addPublicKeysFromFile(InMemoryKeyring keyring,
|
|
||||||
File pubring,
|
|
||||||
KeyringConfigCallback passwordCallback)
|
|
||||||
throws IOException, PGPException {
|
|
||||||
KeyringConfig source = KeyringConfigs.withKeyRingsFromFiles(pubring, null, passwordCallback);
|
|
||||||
for (PGPPublicKeyRing pubRing : source.getPublicKeyRings()) {
|
|
||||||
for (PGPPublicKey pubKey : pubRing) {
|
|
||||||
try {
|
|
||||||
keyring.addPublicKey(pubKey.getEncoded());
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
LOGGER.log(Level.INFO, "public key " + Long.toHexString(pubKey.getKeyID()) +
|
|
||||||
" already exists in keyring. Skip.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PGPPublicKey addSecretKeysFromFile(InMemoryKeyring keyring,
|
|
||||||
File secring,
|
|
||||||
KeyringConfigCallback passwordCallback)
|
|
||||||
throws IOException, PGPException {
|
|
||||||
KeyringConfig source = KeyringConfigs.withKeyRingsFromFiles(null, secring, passwordCallback);
|
|
||||||
PGPPublicKey lastAdded = null;
|
|
||||||
|
|
||||||
for (PGPSecretKeyRing secRing : source.getSecretKeyRings()) {
|
|
||||||
for (PGPSecretKey secKey : secRing) {
|
|
||||||
keyring.addSecretKey(secKey.getEncoded());
|
|
||||||
// Remember last added secret keys public key -> this will be the primary key
|
|
||||||
if (secKey.getPublicKey() != null) {
|
|
||||||
lastAdded = secKey.getPublicKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastAdded;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OpenPgpV4Fingerprint primaryOpenPgpKeyPairFingerprint() {
|
public OpenPgpV4Fingerprint primaryOpenPgpKeyPairFingerprint() {
|
||||||
return primaryKeyFingerprint;
|
return primaryKeyFingerprint;
|
||||||
|
@ -153,13 +121,13 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
Set<OpenPgpV4Fingerprint> announcedKeys = new HashSet<>();
|
Set<OpenPgpV4Fingerprint> announcedKeys = new HashSet<>();
|
||||||
File listPath = contactsList(contact);
|
File listPath = contactsList(contact);
|
||||||
if (listPath.exists() && listPath.isFile()) {
|
if (listPath.exists() && listPath.isFile()) {
|
||||||
FileReader fileReader = null;
|
BufferedReader reader = null;
|
||||||
try {
|
try {
|
||||||
fileReader = new FileReader(listPath);
|
reader = new BufferedReader(new InputStreamReader(
|
||||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
new FileInputStream(listPath), "UTF8"));
|
||||||
String line;
|
|
||||||
|
|
||||||
while ((line = bufferedReader.readLine()) != null) {
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
if (line.isEmpty()) {
|
if (line.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -172,11 +140,11 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
LOGGER.log(Level.INFO, "Skip malformed fingerprint " + line + " of " + contact.toString());
|
LOGGER.log(Level.INFO, "Skip malformed fingerprint " + line + " of " + contact.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bufferedReader.close();
|
reader.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (fileReader != null) {
|
if (reader != null) {
|
||||||
try {
|
try {
|
||||||
fileReader.close();
|
reader.close();
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
|
@ -187,9 +155,25 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeysFingerprints(BareJid contact) {
|
public Set<OpenPgpV4Fingerprint> availableOpenPgpPublicKeysFingerprints(BareJid contact)
|
||||||
|
throws CorruptedOpenPgpKeyException {
|
||||||
Set<OpenPgpV4Fingerprint> availableKeys = new HashSet<>();
|
Set<OpenPgpV4Fingerprint> availableKeys = new HashSet<>();
|
||||||
return null; // TODO
|
try {
|
||||||
|
Iterator<PGPPublicKeyRing> ringIterator = keyringConfig.getPublicKeyRings().getKeyRings("xmpp:" + contact.toString());
|
||||||
|
while (ringIterator.hasNext()) {
|
||||||
|
PGPPublicKeyRing ring = ringIterator.next();
|
||||||
|
Iterator<PGPPublicKey> keyIterator = ring.getPublicKeys();
|
||||||
|
while (keyIterator.hasNext()) {
|
||||||
|
PGPPublicKey key = keyIterator.next();
|
||||||
|
if (key.isEncryptionKey()) {
|
||||||
|
availableKeys.add(BCOpenPgpProvider.getFingerprint(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (PGPException | IOException e) {
|
||||||
|
throw new CorruptedOpenPgpKeyException(e);
|
||||||
|
}
|
||||||
|
return availableKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -199,17 +183,17 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
if (!listPath.exists()) {
|
if (!listPath.exists()) {
|
||||||
listPath.getParentFile().mkdirs();
|
listPath.getParentFile().mkdirs();
|
||||||
listPath.createNewFile();
|
listPath.createNewFile();
|
||||||
FileWriter writer = null;
|
BufferedWriter writer = null;
|
||||||
try {
|
try {
|
||||||
writer = new FileWriter(listPath);
|
writer = new BufferedWriter(new OutputStreamWriter(
|
||||||
BufferedWriter bufferedWriter = new BufferedWriter(writer);
|
new FileOutputStream(listPath), "UTF8"));
|
||||||
|
|
||||||
for (OpenPgpV4Fingerprint fingerprint : listElement.getMetadata().keySet()) {
|
for (OpenPgpV4Fingerprint fingerprint : listElement.getMetadata().keySet()) {
|
||||||
bufferedWriter.write(fingerprint.toString());
|
writer.write(fingerprint.toString());
|
||||||
bufferedWriter.newLine();
|
writer.newLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferedWriter.close();
|
writer.close();
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
|
@ -243,6 +227,7 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
byte[] base64decoded = Base64.decode(element.getDataElement().getB64Data());
|
byte[] base64decoded = Base64.decode(element.getDataElement().getB64Data());
|
||||||
try {
|
try {
|
||||||
keyringConfig.addPublicKey(base64decoded);
|
keyringConfig.addPublicKey(base64decoded);
|
||||||
|
writePublicKeysToFile(keyringConfig, publicKeyringPath());
|
||||||
} catch (PGPException | IOException e) {
|
} catch (PGPException | IOException e) {
|
||||||
throw new CorruptedOpenPgpKeyException(e);
|
throw new CorruptedOpenPgpKeyException(e);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
@ -254,13 +239,115 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
@Override
|
@Override
|
||||||
public SecretkeyElement createSecretkeyElement(Set<OpenPgpV4Fingerprint> fingerprints, String password)
|
public SecretkeyElement createSecretkeyElement(Set<OpenPgpV4Fingerprint> fingerprints, String password)
|
||||||
throws MissingOpenPgpKeyPairException, CorruptedOpenPgpKeyException {
|
throws MissingOpenPgpKeyPairException, CorruptedOpenPgpKeyException {
|
||||||
return null;
|
|
||||||
|
PGPDigestCalculator calculator;
|
||||||
|
try {
|
||||||
|
calculator = new JcaPGPDigestCalculatorProviderBuilder()
|
||||||
|
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||||
|
.build()
|
||||||
|
.get(HashAlgorithmTags.SHA1);
|
||||||
|
} catch (PGPException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
PBESecretKeyEncryptor encryptor = new JcePBESecretKeyEncryptorBuilder(
|
||||||
|
PGPSymmetricEncryptionAlgorithms.AES_256.getAlgorithmId())
|
||||||
|
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||||
|
.build(password.toCharArray());
|
||||||
|
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (OpenPgpV4Fingerprint fingerprint : fingerprints) {
|
||||||
|
// Our unencrypted secret key
|
||||||
|
PGPSecretKey secretKey = keyringConfig.getSecretKeyRings()
|
||||||
|
.getSecretKey(Util.keyIdFromFingerprint(fingerprint));
|
||||||
|
|
||||||
|
if (secretKey == null) {
|
||||||
|
// TODO: Close streams
|
||||||
|
throw new MissingOpenPgpKeyPairException(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPSecretKey encrypted = new PGPSecretKey(
|
||||||
|
secretKey.extractPrivateKey(null),
|
||||||
|
secretKey.getPublicKey(),
|
||||||
|
calculator,
|
||||||
|
true,
|
||||||
|
encryptor);
|
||||||
|
|
||||||
|
buffer.write(encrypted.getEncoded());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SecretkeyElement(Base64.encode(buffer.toByteArray()));
|
||||||
|
|
||||||
|
} catch (PGPException | IOException e) {
|
||||||
|
throw new CorruptedOpenPgpKeyException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restoreSecretKeyBackup(SecretkeyElement secretkeyElement, String password, SecretKeyRestoreSelectionCallback callback)
|
public void restoreSecretKeyBackup(SecretkeyElement secretkeyElement, String password, SecretKeyRestoreSelectionCallback callback)
|
||||||
throws CorruptedOpenPgpKeyException, InvalidBackupCodeException {
|
throws CorruptedOpenPgpKeyException, InvalidBackupCodeException {
|
||||||
|
byte[] base64Decoded = Base64.decode(secretkeyElement.getB64Data());
|
||||||
|
|
||||||
|
try {
|
||||||
|
PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
|
||||||
|
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(base64Decoded);
|
||||||
|
KeyringConfig keyring = KeyringConfigs.withKeyRingsFromStreams(null, inputStream,
|
||||||
|
KeyringConfigCallbacks.withPassword(password));
|
||||||
|
|
||||||
|
Map<OpenPgpV4Fingerprint, PGPSecretKey> availableKeys = new HashMap<>();
|
||||||
|
OpenPgpV4Fingerprint selectedKey;
|
||||||
|
|
||||||
|
for (PGPSecretKeyRing r : keyring.getSecretKeyRings()) {
|
||||||
|
PGPSecretKey s = r.getSecretKey();
|
||||||
|
PGPPrivateKey privateKey = s.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder(calculatorProvider).build(password.toCharArray()));
|
||||||
|
PGPPublicKey publicKey = s.getPublicKey();
|
||||||
|
PGPSecretKey secretKey = new PGPSecretKey(
|
||||||
|
privateKey,
|
||||||
|
publicKey,
|
||||||
|
calculatorProvider.get(PGPHashAlgorithms.SHA1.getAlgorithmId()),
|
||||||
|
true,
|
||||||
|
null);
|
||||||
|
availableKeys.put(BCOpenPgpProvider.getFingerprint(publicKey), secretKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedKey = callback.selectSecretKeyToRestore(availableKeys.keySet());
|
||||||
|
if (selectedKey != null) {
|
||||||
|
try {
|
||||||
|
keyringConfig.addSecretKey(availableKeys.get(selectedKey).getEncoded());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOGGER.log(Level.INFO, "Users secret key " + selectedKey.toString() + " is already in keyring. Skip.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
keyringConfig.addPublicKey(availableKeys.get(selectedKey).getPublicKey().getEncoded());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOGGER.log(Level.INFO, "Users public key " + selectedKey.toString() + " is already in keyring. Skip.");
|
||||||
|
}
|
||||||
|
primaryKeyFingerprint = selectedKey;
|
||||||
|
writePrivateKeysToFile(keyringConfig, secretKeyringPath());
|
||||||
|
}
|
||||||
|
} catch (PGPException | IOException e) {
|
||||||
|
throw new CorruptedOpenPgpKeyException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenPgpV4Fingerprint createOpenPgpKeyPair()
|
||||||
|
throws NoSuchAlgorithmException, NoSuchProviderException, CorruptedOpenPgpKeyException {
|
||||||
|
try {
|
||||||
|
PGPSecretKeyRing ourKey = BCOpenPgpProvider.generateKey(user).generateSecretKeyRing();
|
||||||
|
keyringConfig.addSecretKey(ourKey.getSecretKey().getEncoded());
|
||||||
|
keyringConfig.addPublicKey(ourKey.getPublicKey().getEncoded());
|
||||||
|
primaryKeyFingerprint = BCOpenPgpProvider.getFingerprint(ourKey.getPublicKey());
|
||||||
|
return primaryKeyFingerprint;
|
||||||
|
} catch (PGPException | IOException e) {
|
||||||
|
throw new CorruptedOpenPgpKeyException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private File secretKeyringPath() {
|
private File secretKeyringPath() {
|
||||||
|
@ -268,11 +355,7 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
private File publicKeyringPath() {
|
private File publicKeyringPath() {
|
||||||
return publicKeyringPath(user);
|
return new File(contactsPath(user), "pubring.pkr");
|
||||||
}
|
|
||||||
|
|
||||||
private File publicKeyringPath(BareJid contact) {
|
|
||||||
return new File(contactsPath(contact), "pubring.pkr");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private File contactsPath() {
|
private File contactsPath() {
|
||||||
|
@ -286,4 +369,87 @@ public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||||
private File contactsList(BareJid contact) {
|
private File contactsList(BareJid contact) {
|
||||||
return new File(contactsPath(contact), "metadata.list");
|
return new File(contactsPath(contact), "metadata.list");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addPublicKeysFromFile(InMemoryKeyring keyring,
|
||||||
|
File pubring,
|
||||||
|
KeyringConfigCallback passwordCallback)
|
||||||
|
throws IOException, PGPException {
|
||||||
|
if (!pubring.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream inputStream = new FileInputStream(pubring);
|
||||||
|
KeyringConfig source = KeyringConfigs.withKeyRingsFromStreams(inputStream, null, passwordCallback);
|
||||||
|
for (PGPPublicKeyRing pubRing : source.getPublicKeyRings()) {
|
||||||
|
for (PGPPublicKey pubKey : pubRing) {
|
||||||
|
try {
|
||||||
|
keyring.addPublicKey(pubKey.getEncoded());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOGGER.log(Level.INFO, "public key " + Long.toHexString(pubKey.getKeyID()) +
|
||||||
|
" already exists in keyring. Skip.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PGPPublicKey addSecretKeysFromFile(InMemoryKeyring keyring,
|
||||||
|
File secring,
|
||||||
|
KeyringConfigCallback passwordCallback)
|
||||||
|
throws IOException, PGPException {
|
||||||
|
if (!secring.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream inputStream = new FileInputStream(secring);
|
||||||
|
KeyringConfig source = KeyringConfigs.withKeyRingsFromStreams(null, inputStream, passwordCallback);
|
||||||
|
PGPPublicKey lastAdded = null;
|
||||||
|
|
||||||
|
for (PGPSecretKeyRing secRing : source.getSecretKeyRings()) {
|
||||||
|
for (PGPSecretKey secKey : secRing) {
|
||||||
|
keyring.addSecretKey(secKey.getEncoded());
|
||||||
|
// Remember last added secret keys public key -> this will be the primary key
|
||||||
|
if (secKey.getPublicKey() != null) {
|
||||||
|
lastAdded = secKey.getPublicKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writePublicKeysToFile(KeyringConfig keyring, File pubring)
|
||||||
|
throws IOException, PGPException {
|
||||||
|
writeBytesToFile(keyring.getPublicKeyRings().getEncoded(), pubring);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writePrivateKeysToFile(KeyringConfig keyring, File secring)
|
||||||
|
throws IOException, PGPException {
|
||||||
|
writeBytesToFile(keyring.getSecretKeyRings().getEncoded(), secring);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeBytesToFile(byte[] bytes, File file) throws IOException {
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
file.createNewFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputStream outputStream = null;
|
||||||
|
try {
|
||||||
|
outputStream = new FileOutputStream(file);
|
||||||
|
BufferedOutputStream bufferedStream = new BufferedOutputStream(outputStream);
|
||||||
|
|
||||||
|
bufferedStream.write(bytes);
|
||||||
|
outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (outputStream != null) {
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyringConfig getKeyringConfig() {
|
||||||
|
return keyringConfig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,8 +116,8 @@ public class BasicEncryptionTest extends SmackTestSuite {
|
||||||
throws IOException, PGPException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException {
|
throws IOException, PGPException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException {
|
||||||
final String alice = "alice@wonderland.lit";
|
final String alice = "alice@wonderland.lit";
|
||||||
final String bob = "bob@builder.tv";
|
final String bob = "bob@builder.tv";
|
||||||
PGPKeyRingGenerator g1 = BouncyCastleOpenPgpProvider.generateKey(JidCreate.bareFrom(alice));
|
PGPKeyRingGenerator g1 = BCOpenPgpProvider.generateKey(JidCreate.bareFrom(alice));
|
||||||
PGPKeyRingGenerator g2 = BouncyCastleOpenPgpProvider.generateKey(JidCreate.bareFrom(bob));
|
PGPKeyRingGenerator g2 = BCOpenPgpProvider.generateKey(JidCreate.bareFrom(bob));
|
||||||
PGPSecretKey s1 = g1.generateSecretKeyRing().getSecretKey();
|
PGPSecretKey s1 = g1.generateSecretKeyRing().getSecretKey();
|
||||||
PGPSecretKey s2 = g2.generateSecretKeyRing().getSecretKey();
|
PGPSecretKey s2 = g2.generateSecretKeyRing().getSecretKey();
|
||||||
PGPPublicKey p1 = g1.generatePublicKeyRing().getPublicKey();
|
PGPPublicKey p1 = g1.generatePublicKeyRing().getPublicKey();
|
||||||
|
|
|
@ -16,13 +16,25 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||||
|
|
||||||
import java.security.Security;
|
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.smack.test.util.SmackTestSuite;
|
||||||
|
import org.jivesoftware.smackx.ox.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.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.jxmpp.jid.BareJid;
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
|
||||||
public class BouncyCastleOpenPgpProviderTest extends SmackTestSuite {
|
public class BouncyCastleOpenPgpProviderTest extends SmackTestSuite {
|
||||||
|
@ -34,18 +46,18 @@ public class BouncyCastleOpenPgpProviderTest extends SmackTestSuite {
|
||||||
// Create providers for alice and the cat
|
// Create providers for alice and the cat
|
||||||
BareJid alice = JidCreate.bareFrom("alice@wonderland.lit");
|
BareJid alice = JidCreate.bareFrom("alice@wonderland.lit");
|
||||||
BareJid cheshire = JidCreate.bareFrom("cheshire@wonderland.lit");
|
BareJid cheshire = JidCreate.bareFrom("cheshire@wonderland.lit");
|
||||||
BouncyCastleOpenPgpProvider aliceProvider = new BouncyCastleOpenPgpProvider(alice);
|
BCOpenPgpProvider aliceProvider = new BCOpenPgpProvider(alice);
|
||||||
BouncyCastleOpenPgpProvider cheshireProvider = new BouncyCastleOpenPgpProvider(cheshire);
|
BCOpenPgpProvider cheshireProvider = new BCOpenPgpProvider(cheshire);
|
||||||
|
|
||||||
aliceProvider.createAndUseKey();
|
aliceProvider.createOpenPgpKeyPair();
|
||||||
cheshireProvider.createAndUseKey();
|
cheshireProvider.createOpenPgpKeyPair();
|
||||||
|
|
||||||
// dry exchange keys
|
// dry exchange keys
|
||||||
/*
|
|
||||||
PubkeyElement aliceKeys = aliceProvider.createPubkeyElement();
|
PubkeyElement aliceKeys = aliceProvider.createPubkeyElement(aliceProvider.primaryOpenPgpKeyPairFingerprint());
|
||||||
PubkeyElement cheshireKeys = cheshireProvider.createPubkeyElement();
|
PubkeyElement cheshireKeys = cheshireProvider.createPubkeyElement(cheshireProvider.primaryOpenPgpKeyPairFingerprint());
|
||||||
aliceProvider.storePublicKey(cheshireKeys, cheshire);
|
aliceProvider.storePublicKey(cheshire, cheshireProvider.primaryOpenPgpKeyPairFingerprint(), cheshireKeys);
|
||||||
cheshireProvider.storePublicKey(aliceKeys, alice);
|
cheshireProvider.storePublicKey(alice, aliceProvider.primaryOpenPgpKeyPairFingerprint(), aliceKeys);
|
||||||
|
|
||||||
// Create signed and encrypted message from alice to the cheshire cat
|
// Create signed and encrypted message from alice to the cheshire cat
|
||||||
SigncryptElement signcryptElement = new SigncryptElement(
|
SigncryptElement signcryptElement = new SigncryptElement(
|
||||||
|
@ -54,14 +66,14 @@ public class BouncyCastleOpenPgpProviderTest extends SmackTestSuite {
|
||||||
new Message.Body("en", "How do you know I’m mad?")));
|
new Message.Body("en", "How do you know I’m mad?")));
|
||||||
OpenPgpElement encrypted = aliceProvider.signAndEncrypt(
|
OpenPgpElement encrypted = aliceProvider.signAndEncrypt(
|
||||||
signcryptElement,
|
signcryptElement,
|
||||||
Collections.singleton(cheshire));
|
aliceProvider.primaryOpenPgpKeyPairFingerprint(),
|
||||||
|
Collections.singleton(cheshireProvider.primaryOpenPgpKeyPairFingerprint()));
|
||||||
|
|
||||||
// Decrypt the message as the cheshire cat
|
// Decrypt the message as the cheshire cat
|
||||||
OpenPgpMessage decrypted = cheshireProvider.decryptAndVerify(encrypted, alice);
|
OpenPgpMessage decrypted = cheshireProvider.decryptAndVerify(encrypted, Collections.singleton(aliceProvider.primaryOpenPgpKeyPairFingerprint()));
|
||||||
OpenPgpContentElement content = decrypted.getOpenPgpContentElement();
|
OpenPgpContentElement content = decrypted.getOpenPgpContentElement();
|
||||||
|
|
||||||
assertTrue(content instanceof SigncryptElement);
|
assertTrue(content instanceof SigncryptElement);
|
||||||
assertXMLEqual(signcryptElement.toXML(null).toString(), content.toXML(null).toString());
|
assertXMLEqual(signcryptElement.toXML(null).toString(), content.toXML(null).toString());
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class BouncyCastle_OpenPgpV4FingerprintTest extends SmackTestSuite {
|
||||||
keyringJuliet.addPublicKey(TestKeys.JULIET_PUB.getBytes(UTF8));
|
keyringJuliet.addPublicKey(TestKeys.JULIET_PUB.getBytes(UTF8));
|
||||||
PGPPublicKey publicKey = keyringJuliet.getPublicKeyRings().iterator().next().getPublicKey();
|
PGPPublicKey publicKey = keyringJuliet.getPublicKeyRings().iterator().next().getPublicKey();
|
||||||
|
|
||||||
OpenPgpV4Fingerprint fp = BouncyCastleOpenPgpProvider.getFingerprint(publicKey);
|
OpenPgpV4Fingerprint fp = BCOpenPgpProvider.getFingerprint(publicKey);
|
||||||
assertEquals(publicKey.getKeyID(), Util.keyIdFromFingerprint(fp));
|
assertEquals(publicKey.getKeyID(), Util.keyIdFromFingerprint(fp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class KeyGenerationTest {
|
||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
public void createSecretKey() throws Exception {
|
public void createSecretKey() throws Exception {
|
||||||
PGPSecretKey secretKey = BouncyCastleOpenPgpProvider
|
PGPSecretKey secretKey = BCOpenPgpProvider
|
||||||
.generateKey(JidCreate.bareFrom("alice@wonderland.lit"))
|
.generateKey(JidCreate.bareFrom("alice@wonderland.lit"))
|
||||||
.generateSecretKeyRing()
|
.generateSecretKeyRing()
|
||||||
.getSecretKey();
|
.getSecretKey();
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.ox;
|
package org.jivesoftware.smackx.ox;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.ox.element.CryptElement;
|
import org.jivesoftware.smackx.ox.element.CryptElement;
|
||||||
|
@ -27,8 +25,6 @@ import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||||
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.jxmpp.jid.BareJid;
|
|
||||||
|
|
||||||
public interface OpenPgpProvider extends OpenPgpStore {
|
public interface OpenPgpProvider extends OpenPgpStore {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,16 +134,4 @@ public interface OpenPgpProvider extends OpenPgpStore {
|
||||||
*/
|
*/
|
||||||
OpenPgpMessage decrypt(OpenPgpElement element)
|
OpenPgpMessage decrypt(OpenPgpElement element)
|
||||||
throws MissingOpenPgpKeyPairException;
|
throws MissingOpenPgpKeyPairException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a fresh OpenPGP key pair with the {@link BareJid} of the user prefixed by "xmpp:" as user-id
|
|
||||||
* (example: {@code "xmpp:juliet@capulet.lit"}).
|
|
||||||
* Store the key pair in persistent storage and return the public keys {@link OpenPgpV4Fingerprint}.
|
|
||||||
*
|
|
||||||
* @throws NoSuchAlgorithmException if a Hash algorithm is not available
|
|
||||||
* @throws NoSuchProviderException id no suitable cryptographic provider (for example BouncyCastleProvider)
|
|
||||||
* is registered.
|
|
||||||
*/
|
|
||||||
OpenPgpV4Fingerprint createOpenPgpKeyPair()
|
|
||||||
throws NoSuchAlgorithmException, NoSuchProviderException;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package org.jivesoftware.smackx.ox;
|
package org.jivesoftware.smackx.ox;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smackx.ox.callback.SecretKeyRestoreSelectionCallback;
|
import org.jivesoftware.smackx.ox.callback.SecretKeyRestoreSelectionCallback;
|
||||||
import org.jivesoftware.smackx.ox.element.PubkeyElement;
|
import org.jivesoftware.smackx.ox.element.PubkeyElement;
|
||||||
|
@ -41,7 +42,7 @@ public interface OpenPgpStore {
|
||||||
* <br>
|
* <br>
|
||||||
* Note: Those are the keys announced in the latest received metadata update.
|
* Note: Those are the keys announced in the latest received metadata update.
|
||||||
* This returns a {@link Set} which might be different from the result of
|
* This returns a {@link Set} which might be different from the result of
|
||||||
* {@link #availableOpenPgpKeysFingerprints(BareJid)}.
|
* {@link #availableOpenPgpPublicKeysFingerprints(BareJid)}.
|
||||||
* Messages should be encrypted to the intersection of both sets.
|
* Messages should be encrypted to the intersection of both sets.
|
||||||
*
|
*
|
||||||
* @param contact contact.
|
* @param contact contact.
|
||||||
|
@ -54,13 +55,14 @@ public interface OpenPgpStore {
|
||||||
* contact, which we have locally available.
|
* contact, which we have locally available.
|
||||||
* <br>
|
* <br>
|
||||||
* Note: This returns a {@link Set} that might be different from the result of
|
* Note: This returns a {@link Set} that might be different from the result of
|
||||||
* {@link #availableOpenPgpKeysFingerprints(BareJid)}.
|
* {@link #availableOpenPgpPublicKeysFingerprints(BareJid)}.
|
||||||
* Messages should be encrypted to the intersection of both sets.
|
* Messages should be encrypted to the intersection of both sets.
|
||||||
*
|
*
|
||||||
* @param contact contact.
|
* @param contact contact.
|
||||||
* @return list of contacts locally available public keys.
|
* @return list of contacts locally available public keys.
|
||||||
*/
|
*/
|
||||||
Set<OpenPgpV4Fingerprint> availableOpenPgpKeysFingerprints(BareJid contact);
|
Set<OpenPgpV4Fingerprint> availableOpenPgpPublicKeysFingerprints(BareJid contact)
|
||||||
|
throws CorruptedOpenPgpKeyException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store incoming update to the OpenPGP metadata node in persistent storage.
|
* Store incoming update to the OpenPGP metadata node in persistent storage.
|
||||||
|
@ -68,13 +70,22 @@ public interface OpenPgpStore {
|
||||||
* @param connection authenticated {@link XMPPConnection} of the user.
|
* @param connection authenticated {@link XMPPConnection} of the user.
|
||||||
* @param listElement {@link PublicKeysListElement} which contains a list of the keys of {@code owner}.
|
* @param listElement {@link PublicKeysListElement} which contains a list of the keys of {@code owner}.
|
||||||
* @param owner {@link BareJid} of the owner of the announced public keys.
|
* @param owner {@link BareJid} of the owner of the announced public keys.
|
||||||
* @throws CorruptedOpenPgpKeyException
|
|
||||||
* @throws InterruptedException
|
|
||||||
* @throws SmackException.NotConnectedException
|
|
||||||
* @throws SmackException.NoResponseException
|
|
||||||
*/
|
*/
|
||||||
void storePublicKeysList(XMPPConnection connection, PublicKeysListElement listElement, BareJid owner);
|
void storePublicKeysList(XMPPConnection connection, PublicKeysListElement listElement, BareJid owner);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a fresh OpenPGP key pair with the {@link BareJid} of the user prefixed by "xmpp:" as user-id
|
||||||
|
* (example: {@code "xmpp:juliet@capulet.lit"}).
|
||||||
|
* Store the key pair in persistent storage and return the public keys {@link OpenPgpV4Fingerprint}.
|
||||||
|
*
|
||||||
|
* @throws NoSuchAlgorithmException if a Hash algorithm is not available
|
||||||
|
* @throws NoSuchProviderException id no suitable cryptographic provider (for example BouncyCastleProvider)
|
||||||
|
* is registered.
|
||||||
|
* @throws CorruptedOpenPgpKeyException if the generated key cannot be added to the keyring for some reason.
|
||||||
|
*/
|
||||||
|
OpenPgpV4Fingerprint createOpenPgpKeyPair()
|
||||||
|
throws NoSuchAlgorithmException, NoSuchProviderException, CorruptedOpenPgpKeyException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a {@link PubkeyElement} which contains our exported OpenPGP public key.
|
* Create a {@link PubkeyElement} which contains our exported OpenPGP public key.
|
||||||
* The element can for example be published.
|
* The element can for example be published.
|
||||||
|
|
Loading…
Reference in a new issue