mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-12-08 20:11:08 +01:00
Warning: Construction Site!
This commit is contained in:
parent
365a4d20d0
commit
2b7738cc9c
34 changed files with 1635 additions and 802 deletions
|
|
@ -0,0 +1,136 @@
|
|||
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||
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.InvalidBackupCodeException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public class BCOpenPgpProvider implements OpenPgpProvider {
|
||||
|
||||
private final BareJid user;
|
||||
private OpenPgpV4Fingerprint primaryKeyPair;
|
||||
|
||||
|
||||
public BCOpenPgpProvider(BareJid user) {
|
||||
this.user = user;
|
||||
this.primaryKeyPair = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpV4Fingerprint primaryOpenPgpKeyPairFingerprint() {
|
||||
return primaryKeyPair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeyPairFingerprints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<OpenPgpV4Fingerprint> announcedOpenPgpKeyFingerprints(BareJid contact) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpElement signAndEncrypt(SigncryptElement element, OpenPgpV4Fingerprint signingKey, Set<OpenPgpV4Fingerprint> encryptionKeys)
|
||||
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpMessage decryptAndVerify(OpenPgpElement element, Set<OpenPgpV4Fingerprint> sendersKeys)
|
||||
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PubkeyElement createPubkeyElement(OpenPgpV4Fingerprint fingerprint)
|
||||
throws MissingOpenPgpPublicKeyException, CorruptedOpenPgpKeyException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePublicKey(BareJid owner, OpenPgpV4Fingerprint fingerprint, PubkeyElement element)
|
||||
throws CorruptedOpenPgpKeyException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePublicKeysList(XMPPConnection connection, PublicKeysListElement listElement, BareJid owner)
|
||||
throws CorruptedOpenPgpKeyException, InterruptedException, SmackException.NotConnectedException,
|
||||
SmackException.NoResponseException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretkeyElement createSecretkeyElement(Set<OpenPgpV4Fingerprint> fingerprints, String password)
|
||||
throws MissingOpenPgpKeyPairException, CorruptedOpenPgpKeyException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeysFingerprints(BareJid contact) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreSecretKeyBackup(SecretkeyElement secretkeyElement, String password, SecretKeyRestoreSelectionCallback callback)
|
||||
throws CorruptedOpenPgpKeyException, InvalidBackupCodeException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpV4Fingerprint createOpenPgpKeyPair()
|
||||
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) {
|
||||
byte[] hex = Hex.encode(publicKey.getFingerprint());
|
||||
return new OpenPgpV4Fingerprint(hex);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public interface BouncyCastleIdentityStore {
|
||||
|
||||
void storeActivePubkeyList(BareJid jid, PublicKeysListElement list) throws FileNotFoundException, IOException;
|
||||
|
||||
PublicKeysListElement loadActivePubkeyList(BareJid jid) throws FileNotFoundException, IOException;
|
||||
|
||||
void storePublicKeys(BareJid jid, PGPPublicKeyRingCollection keys);
|
||||
|
||||
PGPPublicKeyRingCollection loadPublicKeys(BareJid jid);
|
||||
|
||||
void storeSecretKeys(PGPSecretKeyRingCollection secretKeys);
|
||||
|
||||
PGPSecretKeyRingCollection loadSecretKeys();
|
||||
|
||||
}
|
||||
|
|
@ -16,22 +16,22 @@
|
|||
*/
|
||||
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.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.SmackException;
|
||||
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;
|
||||
|
|
@ -40,49 +40,41 @@ 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.PGPHashAlgorithms;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PGPSymmetricEncryptionAlgorithms;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PublicKeySize;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallbacks;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.XmppKeySelectionStrategy;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.InMemoryKeyring;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfig;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfigs;
|
||||
import org.bouncycastle.bcpg.HashAlgorithmTags;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPKeyRingGenerator;
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
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.bouncycastle.util.encoders.Hex;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
||||
|
||||
private final BareJid ourJid;
|
||||
private InMemoryKeyring ourKeys;
|
||||
private Long ourKeyId;
|
||||
private final Map<BareJid, InMemoryKeyring> theirKeys = new HashMap<>();
|
||||
private static final Logger LOGGER = Logger.getLogger(BouncyCastleOpenPgpProvider.class.getName());
|
||||
|
||||
public BouncyCastleOpenPgpProvider(BareJid ourJid) throws IOException, PGPException, NoSuchAlgorithmException {
|
||||
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() throws CorruptedOpenPgpKeyException {
|
||||
public PubkeyElement createPubkeyElement(OpenPgpV4Fingerprint keyFingerprint)
|
||||
throws MissingOpenPgpPublicKeyException, CorruptedOpenPgpKeyException {
|
||||
// TODO: throw missing key exception
|
||||
try {
|
||||
PGPPublicKey pubKey = ourKeys.getPublicKeyRings().getPublicKey(ourKeyId);
|
||||
PGPPublicKey pubKey = keyring.getPublicKeyRings().getPublicKey(Util.keyIdFromFingerprint(keyFingerprint));
|
||||
PubkeyElement.PubkeyDataElement dataElement = new PubkeyElement.PubkeyDataElement(
|
||||
Base64.encode(pubKey.getEncoded()));
|
||||
return new PubkeyElement(dataElement, new Date());
|
||||
|
|
@ -91,20 +83,29 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public SecretkeyElement createSecretkeyElement(String password) throws CorruptedOpenPgpKeyException {
|
||||
public SecretkeyElement createSecretkeyElement(Set<OpenPgpV4Fingerprint> fingerprints, String password) throws MissingOpenPgpKeyPairException, CorruptedOpenPgpKeyException {
|
||||
/*
|
||||
try {
|
||||
// Our unencrypted secret key
|
||||
PGPSecretKey secretKey = ourKeys.getSecretKeyRings().getSecretKey(ourKeyId);
|
||||
PGPSecretKey secretKey;
|
||||
try {
|
||||
secretKey = ourKeys.getSecretKeyRings().getSecretKey(ourKeyId);
|
||||
} catch (NullPointerException e) {
|
||||
throw new MissingOpenPgpKeyPairException(ourJid);
|
||||
}
|
||||
|
||||
PGPDigestCalculator calculator = new JcaPGPDigestCalculatorProviderBuilder()
|
||||
.setProvider(BouncyGPG.getProvider())
|
||||
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||
.build()
|
||||
.get(HashAlgorithmTags.SHA1);
|
||||
|
||||
PBESecretKeyEncryptor encryptor = new JcePBESecretKeyEncryptorBuilder(
|
||||
PGPSymmetricEncryptionAlgorithms.AES_256.getAlgorithmId())
|
||||
.setProvider(BouncyGPG.getProvider())
|
||||
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||
.build(password.toCharArray());
|
||||
|
||||
PGPSecretKey encrypted = new PGPSecretKey(
|
||||
|
|
@ -121,10 +122,16 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|||
} catch (PGPException | IOException e) {
|
||||
throw new CorruptedOpenPgpKeyException(e);
|
||||
}
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void processPubkeyElement(PubkeyElement element, BareJid owner) throws CorruptedOpenPgpKeyException {
|
||||
public void storePublicKey(BareJid owner, OpenPgpV4Fingerprint fingerprint, PubkeyElement element) throws CorruptedOpenPgpKeyException {
|
||||
/*
|
||||
byte[] decoded = Base64.decode(element.getDataElement().getB64Data());
|
||||
|
||||
try {
|
||||
|
|
@ -138,21 +145,49 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|||
} catch (IOException | PGPException e) {
|
||||
throw new CorruptedOpenPgpKeyException(e);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void processPublicKeysListElement(PublicKeysListElement listElement, BareJid owner) throws Exception {
|
||||
|
||||
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 restoreSecretKeyElement(SecretkeyElement secretkeyElement, String password)
|
||||
public void restoreSecretKeyBackup(SecretkeyElement secretkeyElement, String password, SecretKeyRestoreSelectionCallback callback)
|
||||
throws CorruptedOpenPgpKeyException {
|
||||
/*
|
||||
byte[] encoded = Base64.decode(secretkeyElement.getB64Data());
|
||||
|
||||
try {
|
||||
PGPDigestCalculatorProvider calculatorProvider = new JcaPGPDigestCalculatorProviderBuilder()
|
||||
.setProvider(BouncyGPG.getProvider())
|
||||
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
|
||||
.build();
|
||||
|
||||
InMemoryKeyring keyring = KeyringConfigs.forGpgExportedKeys(
|
||||
|
|
@ -187,12 +222,48 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|||
} 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 OpenPgpElement signAndEncrypt(SigncryptElement element, Set<BareJid> recipients)
|
||||
throws Exception {
|
||||
if (recipients.isEmpty()) {
|
||||
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");
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +300,7 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|||
.withKeySelectionStrategy(new XmppKeySelectionStrategy(new Date()))
|
||||
.withOxAlgorithms()
|
||||
.toRecipients(recipientUIDs)
|
||||
.andSignWith("xmpp:" + ourJid.toString())
|
||||
.andSignWith(ourKeyId)
|
||||
.binaryOutput()
|
||||
.andWriteTo(encryptedOut);
|
||||
|
||||
|
|
@ -239,36 +310,16 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|||
String base64 = Base64.encodeToString(encryptedOut.toByteArray());
|
||||
|
||||
return new OpenPgpElement(base64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpElement sign(SignElement element) throws Exception {
|
||||
|
||||
throw new SmackException.FeatureNotSupportedException("Feature not implemented for now.");
|
||||
/*
|
||||
InMemoryKeyring signingConfig = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys());
|
||||
|
||||
// Add our secret keys to signing config
|
||||
for (PGPSecretKeyRing s : ourKeys.getSecretKeyRings()) {
|
||||
signingConfig.addSecretKey(s.getSecretKey().getEncoded());
|
||||
}
|
||||
|
||||
InputStream inputStream = element.toInputStream();
|
||||
// TODO: Implement
|
||||
|
||||
*/
|
||||
return null;
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OpenPgpMessage verify(OpenPgpElement element, BareJid sender) throws Exception {
|
||||
// TODO: Implement
|
||||
throw new SmackException.FeatureNotSupportedException("Feature not implemented for now.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpMessage decrypt(OpenPgpElement element) throws Exception {
|
||||
throw new SmackException.FeatureNotSupportedException("Feature not implemented for now.");
|
||||
public OpenPgpMessage decryptAndVerify(OpenPgpElement element, Set<OpenPgpV4Fingerprint> possibleSigningKeys)
|
||||
throws MissingOpenPgpPublicKeyException, MissingOpenPgpKeyPairException {
|
||||
/*
|
||||
InMemoryKeyring decryptionConfig = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withUnprotectedKeys());
|
||||
|
||||
|
|
@ -277,83 +328,6 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|||
decryptionConfig.addSecretKey(s.getSecretKey().getEncoded());
|
||||
}
|
||||
|
||||
ByteArrayInputStream encryptedIn = new ByteArrayInputStream(
|
||||
element.getEncryptedBase64MessageContent().getBytes(Charset.forName("UTF-8")));
|
||||
|
||||
InputStream decrypted = BouncyGPG.decryptAndVerifyStream()
|
||||
.withConfig(decryptionConfig)
|
||||
.withKeySelectionStrategy(new XmppKeySelectionStrategy(new Date()))
|
||||
.andIgnoreSignatures()
|
||||
.fromEncryptedInputStream(encryptedIn);
|
||||
|
||||
ByteArrayOutputStream decryptedOut = new ByteArrayOutputStream();
|
||||
|
||||
Streams.pipeAll(decrypted, decryptedOut);
|
||||
|
||||
return new OpenPgpMessage(OpenPgpMessage.State.crypt, new String(decryptedOut.toByteArray(), Charset.forName("UTF-8")));
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpElement encrypt(CryptElement element, Set<BareJid> recipients) throws Exception {
|
||||
throw new SmackException.FeatureNotSupportedException("Feature not implemented for now.");
|
||||
/*
|
||||
if (recipients.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 keys to encryption config
|
||||
for (PGPPublicKeyRing p : ourKeys.getPublicKeyRings()) {
|
||||
encryptionConfig.addPublicKey(p.getPublicKey().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)
|
||||
.andDoNotSign()
|
||||
.binaryOutput()
|
||||
.andWriteTo(encryptedOut);
|
||||
|
||||
Streams.pipeAll(inputStream, encryptor);
|
||||
encryptor.close();
|
||||
|
||||
String base64 = Base64.encodeToString(encryptedOut.toByteArray());
|
||||
|
||||
return new OpenPgpElement(base64);
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenPgpMessage decryptAndVerify(OpenPgpElement element, BareJid sender) throws Exception {
|
||||
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());
|
||||
|
|
@ -374,33 +348,60 @@ public class BouncyCastleOpenPgpProvider implements OpenPgpProvider {
|
|||
Streams.pipeAll(decrypted, decryptedOut);
|
||||
|
||||
return new OpenPgpMessage(OpenPgpMessage.State.signcrypt, new String(decryptedOut.toByteArray(), Charset.forName("UTF-8")));
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFingerprint() throws CorruptedOpenPgpKeyException {
|
||||
try {
|
||||
return new String(Hex.encode(ourKeys.getKeyFingerPrintCalculator()
|
||||
.calculateFingerprint(ourKeys.getPublicKeyRings().getPublicKey(ourKeyId)
|
||||
.getPublicKeyPacket())), Charset.forName("UTF-8")).toUpperCase();
|
||||
} catch (IOException | PGPException e) {
|
||||
throw new CorruptedOpenPgpKeyException(e);
|
||||
}
|
||||
public OpenPgpElement sign(SignElement element, OpenPgpV4Fingerprint singingKeyFingerprint)
|
||||
throws MissingOpenPgpKeyPairException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAndUseKey() throws CorruptedOpenPgpKeyException, NoSuchAlgorithmException {
|
||||
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();
|
||||
ourKeyId = ourKey.getPublicKey().getKeyID();
|
||||
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 {
|
||||
public static PGPKeyRingGenerator generateKey(BareJid owner)
|
||||
throws NoSuchAlgorithmException, PGPException, NoSuchProviderException {
|
||||
PGPKeyRingGenerator generator = BouncyGPG.createKeyPair()
|
||||
.withRSAKeys()
|
||||
.ofSize(PublicKeySize.RSA._2048)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,289 @@
|
|||
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.util.stringencoder.Base64;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpStore;
|
||||
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.PubkeyElement;
|
||||
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
|
||||
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||
import org.jivesoftware.smackx.ox.exception.CorruptedOpenPgpKeyException;
|
||||
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyPairException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException;
|
||||
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallback;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.InMemoryKeyring;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfig;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfigs;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public class FileBasedBcOpenPgpStore implements OpenPgpStore {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(FileBasedBcOpenPgpStore.class.getName());
|
||||
|
||||
private final File basePath;
|
||||
private final BareJid user;
|
||||
private final InMemoryKeyring keyringConfig;
|
||||
private final KeyringConfigCallback configCallback;
|
||||
private OpenPgpV4Fingerprint primaryKeyFingerprint;
|
||||
|
||||
public FileBasedBcOpenPgpStore(File basePath, BareJid user, KeyringConfigCallback passwordCallback)
|
||||
throws IOException, PGPException {
|
||||
this.basePath = basePath;
|
||||
this.user = user;
|
||||
|
||||
File pub = publicKeyringPath();
|
||||
if (!pub.exists()) {
|
||||
pub.getParentFile().mkdirs();
|
||||
pub.createNewFile();
|
||||
}
|
||||
|
||||
File sec = secretKeyringPath();
|
||||
if (!sec.exists()) {
|
||||
sec.createNewFile();
|
||||
}
|
||||
|
||||
configCallback = passwordCallback;
|
||||
keyringConfig = KeyringConfigs.forGpgExportedKeys(configCallback);
|
||||
|
||||
KeyringConfig load = KeyringConfigs.withKeyRingsFromFiles(pub, sec, passwordCallback);
|
||||
for (PGPPublicKeyRing pubRing : load.getPublicKeyRings()) {
|
||||
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) {
|
||||
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
|
||||
public OpenPgpV4Fingerprint primaryOpenPgpKeyPairFingerprint() {
|
||||
return primaryKeyFingerprint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeyPairFingerprints() {
|
||||
Set<OpenPgpV4Fingerprint> availableKeyPairs = new HashSet<>();
|
||||
try {
|
||||
for (PGPSecretKeyRing secRing : keyringConfig.getSecretKeyRings()) {
|
||||
for (PGPSecretKey secKey : secRing) {
|
||||
availableKeyPairs.add(BCOpenPgpProvider.getFingerprint(secKey.getPublicKey()));
|
||||
}
|
||||
}
|
||||
} catch (IOException | PGPException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error going through available key pair.", e);
|
||||
}
|
||||
return availableKeyPairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<OpenPgpV4Fingerprint> announcedOpenPgpKeyFingerprints(BareJid contact) {
|
||||
Set<OpenPgpV4Fingerprint> announcedKeys = new HashSet<>();
|
||||
File listPath = contactsList(contact);
|
||||
if (listPath.exists() && listPath.isFile()) {
|
||||
FileReader fileReader = null;
|
||||
try {
|
||||
fileReader = new FileReader(listPath);
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
||||
String line;
|
||||
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(line);
|
||||
announcedKeys.add(fingerprint);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.log(Level.INFO, "Skip malformed fingerprint " + line + " of " + contact.toString());
|
||||
}
|
||||
}
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
if (fileReader != null) {
|
||||
try {
|
||||
fileReader.close();
|
||||
} catch (IOException e1) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return announcedKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<OpenPgpV4Fingerprint> availableOpenPgpKeysFingerprints(BareJid contact) {
|
||||
Set<OpenPgpV4Fingerprint> availableKeys = new HashSet<>();
|
||||
return null; // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePublicKeysList(XMPPConnection connection, PublicKeysListElement listElement, BareJid owner) {
|
||||
File listPath = contactsList(owner);
|
||||
try {
|
||||
if (!listPath.exists()) {
|
||||
listPath.getParentFile().mkdirs();
|
||||
listPath.createNewFile();
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
writer = new FileWriter(listPath);
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(writer);
|
||||
|
||||
for (OpenPgpV4Fingerprint fingerprint : listElement.getMetadata().keySet()) {
|
||||
bufferedWriter.write(fingerprint.toString());
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
|
||||
bufferedWriter.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
if (writer != null) {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.log(Level.WARNING, "Error writing list of announced keys for " + owner.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PubkeyElement createPubkeyElement(OpenPgpV4Fingerprint fingerprint)
|
||||
throws MissingOpenPgpPublicKeyException, CorruptedOpenPgpKeyException {
|
||||
try {
|
||||
PGPPublicKey publicKey = keyringConfig.getPublicKeyRings().getPublicKey(Util.keyIdFromFingerprint(fingerprint));
|
||||
if (publicKey == null) {
|
||||
throw new MissingOpenPgpPublicKeyException(user, fingerprint);
|
||||
}
|
||||
byte[] base64 = Base64.encode(publicKey.getEncoded());
|
||||
return new PubkeyElement(new PubkeyElement.PubkeyDataElement(base64), new Date());
|
||||
} catch (PGPException | IOException e) {
|
||||
throw new CorruptedOpenPgpKeyException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePublicKey(BareJid owner, OpenPgpV4Fingerprint fingerprint, PubkeyElement element)
|
||||
throws CorruptedOpenPgpKeyException {
|
||||
byte[] base64decoded = Base64.decode(element.getDataElement().getB64Data());
|
||||
try {
|
||||
keyringConfig.addPublicKey(base64decoded);
|
||||
} catch (PGPException | IOException e) {
|
||||
throw new CorruptedOpenPgpKeyException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOGGER.log(Level.WARNING, "Public Key with ID " + fingerprint.toString() + " of " +
|
||||
owner + " is already in memory. Skip.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretkeyElement createSecretkeyElement(Set<OpenPgpV4Fingerprint> fingerprints, String password)
|
||||
throws MissingOpenPgpKeyPairException, CorruptedOpenPgpKeyException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreSecretKeyBackup(SecretkeyElement secretkeyElement, String password, SecretKeyRestoreSelectionCallback callback)
|
||||
throws CorruptedOpenPgpKeyException, InvalidBackupCodeException {
|
||||
|
||||
}
|
||||
|
||||
private File secretKeyringPath() {
|
||||
return new File(contactsPath(user), "secring.skr");
|
||||
}
|
||||
|
||||
private File publicKeyringPath() {
|
||||
return publicKeyringPath(user);
|
||||
}
|
||||
|
||||
private File publicKeyringPath(BareJid contact) {
|
||||
return new File(contactsPath(contact), "pubring.pkr");
|
||||
}
|
||||
|
||||
private File contactsPath() {
|
||||
return new File(basePath, "users");
|
||||
}
|
||||
|
||||
private File contactsPath(BareJid contact) {
|
||||
return new File(contactsPath(), contact.toString());
|
||||
}
|
||||
|
||||
private File contactsList(BareJid contact) {
|
||||
return new File(contactsPath(contact), "metadata.list");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.util.XmppDateTime;
|
||||
|
||||
public class FileBasedBouncyCastleIdentityStore implements BouncyCastleIdentityStore {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(FileBasedBouncyCastleIdentityStore.class.getName());
|
||||
|
||||
private final File baseDirectory;
|
||||
|
||||
public FileBasedBouncyCastleIdentityStore(File path) {
|
||||
// Check if path is not null, not a file and directory exists
|
||||
if (!Objects.requireNonNull(path).exists()) {
|
||||
path.mkdirs();
|
||||
} else if (path.isFile()) {
|
||||
throw new IllegalArgumentException("Path MUST point to a directory, not a file.");
|
||||
}
|
||||
|
||||
this.baseDirectory = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeActivePubkeyList(BareJid jid, PublicKeysListElement list) throws IOException {
|
||||
File contactsDir = contactsDir(jid);
|
||||
File destination = new File(contactsDir, "pubkey_list");
|
||||
DataOutputStream dataOut = new DataOutputStream(new FileOutputStream(destination));
|
||||
|
||||
for (String key : list.getMetadata().keySet()) {
|
||||
PublicKeysListElement.PubkeyMetadataElement value = list.getMetadata().get(key);
|
||||
dataOut.writeUTF(value.getV4Fingerprint());
|
||||
dataOut.writeUTF(XmppDateTime.formatXEP0082Date(value.getDate()));
|
||||
}
|
||||
|
||||
dataOut.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublicKeysListElement loadActivePubkeyList(BareJid jid) throws IOException {
|
||||
File contactsDir = contactsDir(jid);
|
||||
File source = new File(contactsDir, "pubkey_list");
|
||||
if (!source.exists()) {
|
||||
LOGGER.log(Level.FINE, "File " + source.getAbsolutePath() + " does not exist. Returning null.");
|
||||
return null;
|
||||
}
|
||||
DataInputStream dataIn = new DataInputStream(new FileInputStream(source));
|
||||
|
||||
PublicKeysListElement.Builder builder = PublicKeysListElement.builder();
|
||||
while (true) {
|
||||
try {
|
||||
String fingerprint = dataIn.readUTF();
|
||||
String d = dataIn.readUTF();
|
||||
Date date = XmppDateTime.parseXEP0082Date(d);
|
||||
builder.addMetadata(new PublicKeysListElement.PubkeyMetadataElement(fingerprint, date));
|
||||
} catch (ParseException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not parse date.", e);
|
||||
} catch (EOFException e) {
|
||||
LOGGER.log(Level.INFO, "Reached EOF.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePublicKeys(BareJid jid, PGPPublicKeyRingCollection keys) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPPublicKeyRingCollection loadPublicKeys(BareJid jid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeSecretKeys(PGPSecretKeyRingCollection secretKeys) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPSecretKeyRingCollection loadSecretKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private File contactsDir(BareJid contact) {
|
||||
File f = new File(baseDirectory, "contacts/" + contact.toString());
|
||||
if (!f.exists()) {
|
||||
f.mkdirs();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ import org.bouncycastle.openpgp.PGPKeyRingGenerator;
|
|||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.Test;
|
||||
import org.junit.Ignore;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
||||
public class BasicEncryptionTest extends SmackTestSuite {
|
||||
|
|
@ -72,7 +72,7 @@ public class BasicEncryptionTest extends SmackTestSuite {
|
|||
((InMemoryKeyring) keyringRomeo).addPublicKey(TestKeys.JULIET_PUB.getBytes(UTF8));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void encryptionTest()
|
||||
throws IOException, PGPException, NoSuchAlgorithmException, SignatureException, NoSuchProviderException {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
|
|
@ -111,7 +111,7 @@ public class BasicEncryptionTest extends SmackTestSuite {
|
|||
assertTrue(Arrays.equals(message, message2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void encryptionWithFreshKeysTest()
|
||||
throws IOException, PGPException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException {
|
||||
final String alice = "alice@wonderland.lit";
|
||||
|
|
|
|||
|
|
@ -16,30 +16,18 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||
|
||||
import java.security.Security;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpContentElement;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
||||
import org.jivesoftware.smackx.ox.element.PubkeyElement;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.junit.Test;
|
||||
import org.junit.Ignore;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
||||
public class BouncyCastleOpenPgpProviderTest extends SmackTestSuite {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void encryptAndSign_decryptAndVerifyElementTest() throws Exception {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
|
|
@ -53,10 +41,11 @@ public class BouncyCastleOpenPgpProviderTest extends SmackTestSuite {
|
|||
cheshireProvider.createAndUseKey();
|
||||
|
||||
// dry exchange keys
|
||||
/*
|
||||
PubkeyElement aliceKeys = aliceProvider.createPubkeyElement();
|
||||
PubkeyElement cheshireKeys = cheshireProvider.createPubkeyElement();
|
||||
aliceProvider.processPubkeyElement(cheshireKeys, cheshire);
|
||||
cheshireProvider.processPubkeyElement(aliceKeys, alice);
|
||||
aliceProvider.storePublicKey(cheshireKeys, cheshire);
|
||||
cheshireProvider.storePublicKey(aliceKeys, alice);
|
||||
|
||||
// Create signed and encrypted message from alice to the cheshire cat
|
||||
SigncryptElement signcryptElement = new SigncryptElement(
|
||||
|
|
@ -73,5 +62,6 @@ public class BouncyCastleOpenPgpProviderTest extends SmackTestSuite {
|
|||
|
||||
assertTrue(content instanceof SigncryptElement);
|
||||
assertXMLEqual(signcryptElement.toXML(null).toString(), content.toXML(null).toString());
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static org.jivesoftware.smack.util.StringUtils.UTF8;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
|
||||
import org.jivesoftware.smackx.ox.TestKeys;
|
||||
import org.jivesoftware.smackx.ox.Util;
|
||||
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallbacks;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.InMemoryKeyring;
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfigs;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.junit.Test;
|
||||
|
||||
public class BouncyCastle_OpenPgpV4FingerprintTest extends SmackTestSuite {
|
||||
|
||||
@Test
|
||||
public void keyIdFromFingerprintTest() throws IOException, PGPException {
|
||||
// Parse the key
|
||||
InMemoryKeyring keyringJuliet = KeyringConfigs.forGpgExportedKeys(
|
||||
KeyringConfigCallbacks.withUnprotectedKeys());
|
||||
keyringJuliet.addPublicKey(TestKeys.JULIET_PUB.getBytes(UTF8));
|
||||
PGPPublicKey publicKey = keyringJuliet.getPublicKeyRings().iterator().next().getPublicKey();
|
||||
|
||||
OpenPgpV4Fingerprint fp = BouncyCastleOpenPgpProvider.getFingerprint(publicKey);
|
||||
assertEquals(publicKey.getKeyID(), Util.keyIdFromFingerprint(fp));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox.bouncycastle;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.util.FileUtils;
|
||||
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.util.XmppDateTime;
|
||||
|
||||
public class FileBasedBouncyCastleIdentityStoreTest extends SmackTestSuite {
|
||||
|
||||
public static File storePath;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
String userHome = System.getProperty("user.home");
|
||||
if (userHome != null) {
|
||||
File f = new File(userHome);
|
||||
storePath = new File(f, ".config/smack-integration-test/ox_store");
|
||||
} else {
|
||||
storePath = new File("int_test_ox_store");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeReadPublicKeysLists() throws ParseException, IOException {
|
||||
BareJid jid = JidCreate.bareFrom("edward@snowden.org");
|
||||
String fp1 = "1357B01865B2503C18453D208CAC2A9678548E35";
|
||||
String fp2 = "67819B343B2AB70DED9320872C6464AF2A8E4C02";
|
||||
Date d1 = XmppDateTime.parseDate("2018-03-01T15:26:12Z");
|
||||
Date d2 = XmppDateTime.parseDate("1953-05-16T12:00:00Z");
|
||||
|
||||
PublicKeysListElement list = PublicKeysListElement.builder()
|
||||
.addMetadata(new PublicKeysListElement.PubkeyMetadataElement(fp1, d1))
|
||||
.addMetadata(new PublicKeysListElement.PubkeyMetadataElement(fp2, d2))
|
||||
.build();
|
||||
|
||||
FileBasedBouncyCastleIdentityStore store = new FileBasedBouncyCastleIdentityStore(storePath);
|
||||
|
||||
PublicKeysListElement shouldBeNull = store.loadActivePubkeyList(jid);
|
||||
assertNull(shouldBeNull);
|
||||
store.storeActivePubkeyList(jid, list);
|
||||
|
||||
PublicKeysListElement retrieved = store.loadActivePubkeyList(jid);
|
||||
assertEquals(list.getMetadata(), retrieved.getMetadata());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
deleteStore();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
deleteStore();
|
||||
}
|
||||
|
||||
public void deleteStore() {
|
||||
FileUtils.deleteDirectory(storePath);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,12 +21,12 @@ import static junit.framework.TestCase.assertTrue;
|
|||
|
||||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PublicKeyType;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.junit.Test;
|
||||
import org.junit.Ignore;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
||||
public class KeyGenerationTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void createSecretKey() throws Exception {
|
||||
PGPSecretKey secretKey = BouncyCastleOpenPgpProvider
|
||||
.generateKey(JidCreate.bareFrom("alice@wonderland.lit"))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue