mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-12-05 18:41:11 +01:00
XEP-0373, XEP-0374: OpenPGP for XMPP: Instant Messaging
Fixes SMACK-826
This commit is contained in:
parent
f3262c9d58
commit
f0af00ee43
97 changed files with 8582 additions and 1 deletions
|
|
@ -0,0 +1,185 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
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.TestUtils;
|
||||
import org.jivesoftware.smackx.ox.element.CryptElement;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
||||
import org.jivesoftware.smackx.ox.element.SignElement;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
import org.jivesoftware.smackx.ox.provider.OpenPgpContentElementProvider;
|
||||
import org.jivesoftware.smackx.ox.provider.OpenPgpElementProvider;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
public class OpenPgpElementTest extends SmackTestSuite {
|
||||
|
||||
private final Set<Jid> recipients;
|
||||
|
||||
// 2014-07-10T15:06:00.000+00:00
|
||||
private static final Date testDate = new Date(1405004760000L);
|
||||
|
||||
public OpenPgpElementTest() throws XmppStringprepException {
|
||||
super();
|
||||
Set<Jid> jids = new HashSet<>();
|
||||
jids.add(JidCreate.bareFrom("alice@wonderland.lit"));
|
||||
jids.add(JidCreate.bareFrom("bob@builder.lit"));
|
||||
this.recipients = Collections.unmodifiableSet(jids);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providerTest() throws Exception {
|
||||
String expected =
|
||||
"<openpgp xmlns='urn:xmpp:openpgp:0'>" +
|
||||
"BASE64_OPENPGP_MESSAGE" +
|
||||
"</openpgp>";
|
||||
|
||||
OpenPgpElement element = new OpenPgpElement("BASE64_OPENPGP_MESSAGE");
|
||||
|
||||
assertXMLEqual(expected, element.toXML(null).toString());
|
||||
|
||||
XmlPullParser parser = TestUtils.getParser(expected);
|
||||
OpenPgpElement parsed = OpenPgpElementProvider.TEST_INSTANCE.parse(parser);
|
||||
assertEquals(element.getEncryptedBase64MessageContent(), parsed.getEncryptedBase64MessageContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simplifiedConstructorTest() {
|
||||
ArrayList<ExtensionElement> payload = new ArrayList<>();
|
||||
payload.add(new Message.Body("de", "Hallo Welt!"));
|
||||
CryptElement element = new CryptElement(recipients, payload);
|
||||
|
||||
assertNotNull(element.getTimestamp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signElementProviderTest() throws Exception {
|
||||
String expected =
|
||||
"<sign xmlns='urn:xmpp:openpgp:0'>" +
|
||||
"<to jid='alice@wonderland.lit'/>" +
|
||||
"<to jid='bob@builder.lit'/>" +
|
||||
"<time stamp='2014-07-10T15:06:00.000+00:00'/>" +
|
||||
"<payload>" +
|
||||
"<body xmlns='jabber:client' xml:lang='en'>Hello World!</body>" +
|
||||
"</payload>" +
|
||||
"</sign>";
|
||||
|
||||
List<ExtensionElement> payload = new ArrayList<>();
|
||||
payload.add(new Message.Body("en", "Hello World!"));
|
||||
SignElement element = new SignElement(recipients, testDate, payload);
|
||||
|
||||
assertXMLEqual(expected, element.toXML(null).toString());
|
||||
|
||||
XmlPullParser parser = TestUtils.getParser(expected);
|
||||
SignElement parsed = (SignElement) OpenPgpContentElementProvider.parseOpenPgpContentElement(parser);
|
||||
|
||||
assertEquals(element.getTimestamp(), parsed.getTimestamp());
|
||||
assertEquals(element.getTo(), parsed.getTo());
|
||||
assertEquals(element.getExtensions(), parsed.getExtensions());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cryptElementProviderTest() throws Exception {
|
||||
String expected =
|
||||
"<crypt xmlns='urn:xmpp:openpgp:0'>" +
|
||||
"<to jid='alice@wonderland.lit'/>" +
|
||||
"<time stamp='2014-07-10T15:06:00.000+00:00'/>" +
|
||||
"<payload>" +
|
||||
"<body xmlns='jabber:client' xml:lang='en'>The cake is a lie.</body>" +
|
||||
"</payload>" +
|
||||
"<rpad>f0rm1l4n4-mT8y33j!Y%fRSrcd^ZE4Q7VDt1L%WEgR!kv</rpad>" +
|
||||
"</crypt>";
|
||||
List<ExtensionElement> payload = new ArrayList<>();
|
||||
payload.add(new Message.Body("en", "The cake is a lie."));
|
||||
Set<Jid> to = new HashSet<>();
|
||||
to.add(JidCreate.bareFrom("alice@wonderland.lit"));
|
||||
CryptElement element = new CryptElement(to,
|
||||
"f0rm1l4n4-mT8y33j!Y%fRSrcd^ZE4Q7VDt1L%WEgR!kv",
|
||||
testDate,
|
||||
payload);
|
||||
|
||||
assertXMLEqual(expected, element.toXML(null).toString());
|
||||
|
||||
XmlPullParser parser = TestUtils.getParser(expected);
|
||||
CryptElement parsed = (CryptElement) OpenPgpContentElementProvider.parseOpenPgpContentElement(parser);
|
||||
|
||||
assertEquals(element.getTimestamp(), parsed.getTimestamp());
|
||||
assertEquals(element.getTo(), parsed.getTo());
|
||||
assertEquals(element.getExtensions(), parsed.getExtensions());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signcryptElementProviderTest() throws Exception {
|
||||
String expected =
|
||||
"<signcrypt xmlns='urn:xmpp:openpgp:0'>" +
|
||||
"<to jid='juliet@example.org'/>" +
|
||||
"<time stamp='2014-07-10T15:06:00.000+00:00'/>" +
|
||||
"<payload>" +
|
||||
"<body xmlns='jabber:client' xml:lang='en'>This is a secret message.</body>" +
|
||||
"</payload>" +
|
||||
"<rpad>f0rm1l4n4-mT8y33j!Y%fRSrcd^ZE4Q7VDt1L%WEgR!kv</rpad>" +
|
||||
"</signcrypt>";
|
||||
|
||||
List<ExtensionElement> payload = new ArrayList<>();
|
||||
payload.add(new Message.Body("en", "This is a secret message."));
|
||||
Set<Jid> jids = new HashSet<>();
|
||||
jids.add(JidCreate.bareFrom("juliet@example.org"));
|
||||
SigncryptElement element = new SigncryptElement(jids,
|
||||
"f0rm1l4n4-mT8y33j!Y%fRSrcd^ZE4Q7VDt1L%WEgR!kv",
|
||||
testDate, payload);
|
||||
|
||||
assertXMLEqual(expected, element.toXML(null).toString());
|
||||
|
||||
XmlPullParser parser = TestUtils.getParser(expected);
|
||||
SigncryptElement parsed = (SigncryptElement) OpenPgpContentElementProvider.parseOpenPgpContentElement(parser);
|
||||
|
||||
assertEquals(element.getTimestamp(), parsed.getTimestamp());
|
||||
assertEquals(element.getTo(), parsed.getTo());
|
||||
assertEquals(element.getExtensions(), parsed.getExtensions());
|
||||
assertEquals(payload.get(0), element.getExtension(Message.Body.NAMESPACE));
|
||||
assertEquals(payload.get(0), element.getExtension(Message.Body.ELEMENT, Message.Body.NAMESPACE));
|
||||
}
|
||||
|
||||
@Test(expected = XmlPullParserException.class)
|
||||
public void openPgpContentElementProvider_invalidElementTest() throws IOException, XmlPullParserException {
|
||||
String invalidElementXML = "<payload>" +
|
||||
"<body xmlns='jabber:client' xml:lang='en'>This is a secret message.</body>" +
|
||||
"</payload>";
|
||||
OpenPgpContentElementProvider.parseOpenPgpContentElement(invalidElementXML);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.Security;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.util.FileUtils;
|
||||
import org.jivesoftware.smackx.ox.callback.SecretKeyPassphraseCallback;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
|
||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpTrustStore;
|
||||
import org.jivesoftware.smackx.ox.store.filebased.FileBasedOpenPgpStore;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.JidTestUtil;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.pgpainless.key.collection.PGPKeyRing;
|
||||
import org.pgpainless.key.protection.UnprotectedKeysProtector;
|
||||
import org.pgpainless.util.Passphrase;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class OpenPgpStoreTest extends SmackTestSuite {
|
||||
|
||||
private static File storagePath;
|
||||
|
||||
private static final BareJid alice = JidTestUtil.BARE_JID_1;
|
||||
private static final BareJid bob = JidTestUtil.BARE_JID_2;
|
||||
|
||||
private static final OpenPgpV4Fingerprint finger1 = new OpenPgpV4Fingerprint("DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF");
|
||||
private static final OpenPgpV4Fingerprint finger2 = new OpenPgpV4Fingerprint("C0FFEEC0FFEEC0FFEEC0FFEEC0FFEEC0FFEE1234");
|
||||
private static final OpenPgpV4Fingerprint finger3 = new OpenPgpV4Fingerprint("0123012301230123012301230123012301230123");
|
||||
|
||||
private final OpenPgpStore openPgpStoreInstance1;
|
||||
private final OpenPgpStore openPgpStoreInstance2;
|
||||
|
||||
static {
|
||||
storagePath = FileUtils.getTempDir("storeTest");
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static Collection<OpenPgpStore[]> data() {
|
||||
return Arrays.asList(
|
||||
new OpenPgpStore[][] {
|
||||
{new FileBasedOpenPgpStore(storagePath), new FileBasedOpenPgpStore(storagePath)}
|
||||
});
|
||||
}
|
||||
|
||||
public OpenPgpStoreTest(OpenPgpStore firstInstance, OpenPgpStore secondInstance) {
|
||||
if (firstInstance == secondInstance || !firstInstance.getClass().equals(secondInstance.getClass())) {
|
||||
throw new IllegalArgumentException("firstInstance must be another instance of the same class as secondInstance.");
|
||||
}
|
||||
this.openPgpStoreInstance1 = firstInstance;
|
||||
this.openPgpStoreInstance2 = secondInstance;
|
||||
}
|
||||
|
||||
@Before
|
||||
@After
|
||||
public void deletePath() {
|
||||
FileUtils.deleteDirectory(storagePath);
|
||||
}
|
||||
|
||||
/*
|
||||
Generic
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void t00_store_protectorGetSet() {
|
||||
openPgpStoreInstance1.setKeyRingProtector(new UnprotectedKeysProtector());
|
||||
assertNotNull(openPgpStoreInstance1.getKeyRingProtector());
|
||||
// TODO: Test method below
|
||||
openPgpStoreInstance1.setSecretKeyPassphraseCallback(new SecretKeyPassphraseCallback() {
|
||||
@Override
|
||||
public Passphrase onPassphraseNeeded(OpenPgpV4Fingerprint fingerprint) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
OpenPgpKeyStore
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void t00_deleteTest() throws IOException, PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, MissingUserIdOnKeyException {
|
||||
assertNull(openPgpStoreInstance1.getSecretKeysOf(alice));
|
||||
assertNull(openPgpStoreInstance1.getPublicKeysOf(alice));
|
||||
|
||||
PGPKeyRing keys = openPgpStoreInstance1.generateKeyRing(alice);
|
||||
openPgpStoreInstance1.importSecretKey(alice, keys.getSecretKeys());
|
||||
openPgpStoreInstance1.importPublicKey(alice, keys.getPublicKeys());
|
||||
|
||||
assertNotNull(openPgpStoreInstance1.getSecretKeysOf(alice));
|
||||
assertNotNull(openPgpStoreInstance1.getPublicKeysOf(alice));
|
||||
|
||||
openPgpStoreInstance1.deleteSecretKeyRing(alice, new OpenPgpV4Fingerprint(keys.getSecretKeys()));
|
||||
openPgpStoreInstance1.deletePublicKeyRing(alice, new OpenPgpV4Fingerprint(keys.getSecretKeys()));
|
||||
|
||||
assertNull(openPgpStoreInstance1.getPublicKeysOf(alice));
|
||||
assertNull(openPgpStoreInstance1.getSecretKeysOf(alice));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t01_key_emptyStoreTest() throws IOException, PGPException {
|
||||
assertNull(openPgpStoreInstance1.getPublicKeysOf(alice));
|
||||
assertNull(openPgpStoreInstance1.getSecretKeysOf(alice));
|
||||
assertNull(openPgpStoreInstance1.getPublicKeyRing(alice, finger1));
|
||||
assertNull(openPgpStoreInstance1.getSecretKeyRing(alice, finger1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t02_key_importKeysTest() throws IOException, PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, MissingUserIdOnKeyException {
|
||||
// Test for nullity of all possible values.
|
||||
|
||||
PGPKeyRing keys = openPgpStoreInstance1.generateKeyRing(alice);
|
||||
|
||||
PGPSecretKeyRing secretKeys = keys.getSecretKeys();
|
||||
PGPPublicKeyRing publicKeys = keys.getPublicKeys();
|
||||
assertNotNull(secretKeys);
|
||||
assertNotNull(publicKeys);
|
||||
|
||||
OpenPgpContact cAlice = openPgpStoreInstance1.getOpenPgpContact(alice);
|
||||
assertNull(cAlice.getAnyPublicKeys());
|
||||
|
||||
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(publicKeys);
|
||||
assertEquals(fingerprint, new OpenPgpV4Fingerprint(secretKeys));
|
||||
|
||||
assertNull(openPgpStoreInstance1.getPublicKeysOf(alice));
|
||||
assertNull(openPgpStoreInstance1.getSecretKeysOf(alice));
|
||||
|
||||
openPgpStoreInstance1.importPublicKey(alice, publicKeys);
|
||||
assertTrue(Arrays.equals(publicKeys.getEncoded(), openPgpStoreInstance1.getPublicKeysOf(alice).getEncoded()));
|
||||
assertNotNull(openPgpStoreInstance1.getPublicKeyRing(alice, fingerprint));
|
||||
assertNull(openPgpStoreInstance1.getSecretKeysOf(alice));
|
||||
|
||||
cAlice = openPgpStoreInstance1.getOpenPgpContact(alice);
|
||||
assertNotNull(cAlice.getAnyPublicKeys());
|
||||
|
||||
// Import keys a second time -> No change expected.
|
||||
openPgpStoreInstance1.importPublicKey(alice, publicKeys);
|
||||
assertTrue(Arrays.equals(publicKeys.getEncoded(), openPgpStoreInstance1.getPublicKeysOf(alice).getEncoded()));
|
||||
openPgpStoreInstance1.importSecretKey(alice, secretKeys);
|
||||
assertTrue(Arrays.equals(secretKeys.getEncoded(), openPgpStoreInstance1.getSecretKeysOf(alice).getEncoded()));
|
||||
|
||||
openPgpStoreInstance1.importSecretKey(alice, secretKeys);
|
||||
assertNotNull(openPgpStoreInstance1.getSecretKeysOf(alice));
|
||||
assertTrue(Arrays.equals(secretKeys.getEncoded(), openPgpStoreInstance1.getSecretKeysOf(alice).getEncoded()));
|
||||
assertNotNull(openPgpStoreInstance1.getSecretKeyRing(alice, fingerprint));
|
||||
|
||||
assertTrue(Arrays.equals(secretKeys.getEncoded(), openPgpStoreInstance1.getSecretKeyRing(alice, fingerprint).getEncoded()));
|
||||
assertTrue(Arrays.equals(publicKeys.getEncoded(), openPgpStoreInstance1.getPublicKeyRing(alice, fingerprint).getEncoded()));
|
||||
|
||||
// Clean up
|
||||
openPgpStoreInstance1.deletePublicKeyRing(alice, fingerprint);
|
||||
openPgpStoreInstance1.deleteSecretKeyRing(alice, fingerprint);
|
||||
}
|
||||
|
||||
@Test(expected = MissingUserIdOnKeyException.class)
|
||||
public void t04_key_wrongBareJidOnSecretKeyImportTest() throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, IOException, MissingUserIdOnKeyException {
|
||||
PGPSecretKeyRing secretKeys = openPgpStoreInstance1.generateKeyRing(alice).getSecretKeys();
|
||||
|
||||
openPgpStoreInstance1.importSecretKey(bob, secretKeys);
|
||||
}
|
||||
|
||||
@Test(expected = MissingUserIdOnKeyException.class)
|
||||
public void t05_key_wrongBareJidOnPublicKeyImportTest() throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, IOException, MissingUserIdOnKeyException {
|
||||
PGPPublicKeyRing publicKeys = openPgpStoreInstance1.generateKeyRing(alice).getPublicKeys();
|
||||
|
||||
openPgpStoreInstance1.importPublicKey(bob, publicKeys);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t06_key_keyReloadTest() throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, IOException, MissingUserIdOnKeyException {
|
||||
PGPKeyRing keys = openPgpStoreInstance1.generateKeyRing(alice);
|
||||
PGPSecretKeyRing secretKeys = keys.getSecretKeys();
|
||||
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(secretKeys);
|
||||
PGPPublicKeyRing publicKeys = keys.getPublicKeys();
|
||||
|
||||
openPgpStoreInstance1.importSecretKey(alice, secretKeys);
|
||||
openPgpStoreInstance1.importPublicKey(alice, publicKeys);
|
||||
|
||||
assertNotNull(openPgpStoreInstance2.getSecretKeysOf(alice));
|
||||
assertNotNull(openPgpStoreInstance2.getPublicKeysOf(alice));
|
||||
|
||||
// Clean up
|
||||
openPgpStoreInstance1.deletePublicKeyRing(alice, fingerprint);
|
||||
openPgpStoreInstance1.deleteSecretKeyRing(alice, fingerprint);
|
||||
openPgpStoreInstance2.deletePublicKeyRing(alice, fingerprint);
|
||||
openPgpStoreInstance2.deleteSecretKeyRing(alice, fingerprint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t07_multipleKeysTest() throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, IOException, MissingUserIdOnKeyException {
|
||||
PGPKeyRing one = openPgpStoreInstance1.generateKeyRing(alice);
|
||||
PGPKeyRing two = openPgpStoreInstance1.generateKeyRing(alice);
|
||||
|
||||
OpenPgpV4Fingerprint fingerprint1 = new OpenPgpV4Fingerprint(one.getSecretKeys());
|
||||
OpenPgpV4Fingerprint fingerprint2 = new OpenPgpV4Fingerprint(two.getSecretKeys());
|
||||
|
||||
openPgpStoreInstance1.importSecretKey(alice, one.getSecretKeys());
|
||||
openPgpStoreInstance1.importSecretKey(alice, two.getSecretKeys());
|
||||
openPgpStoreInstance1.importPublicKey(alice, one.getPublicKeys());
|
||||
openPgpStoreInstance1.importPublicKey(alice, two.getPublicKeys());
|
||||
|
||||
assertTrue(Arrays.equals(one.getSecretKeys().getEncoded(), openPgpStoreInstance1.getSecretKeyRing(alice, fingerprint1).getEncoded()));
|
||||
assertTrue(Arrays.equals(two.getSecretKeys().getEncoded(), openPgpStoreInstance1.getSecretKeyRing(alice, fingerprint2).getEncoded()));
|
||||
|
||||
assertTrue(Arrays.equals(one.getSecretKeys().getEncoded(), openPgpStoreInstance1.getSecretKeysOf(alice).getSecretKeyRing(fingerprint1.getKeyId()).getEncoded()));
|
||||
|
||||
assertTrue(Arrays.equals(one.getPublicKeys().getEncoded(),
|
||||
openPgpStoreInstance1.getPublicKeyRing(alice, fingerprint1).getEncoded()));
|
||||
|
||||
// Cleanup
|
||||
openPgpStoreInstance1.deletePublicKeyRing(alice, fingerprint1);
|
||||
openPgpStoreInstance1.deletePublicKeyRing(alice, fingerprint2);
|
||||
openPgpStoreInstance1.deleteSecretKeyRing(alice, fingerprint1);
|
||||
openPgpStoreInstance1.deleteSecretKeyRing(alice, fingerprint2);
|
||||
}
|
||||
|
||||
/*
|
||||
OpenPgpTrustStore
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void t08_trust_emptyStoreTest() throws IOException {
|
||||
|
||||
assertEquals(OpenPgpTrustStore.Trust.undecided, openPgpStoreInstance1.getTrust(alice, finger2));
|
||||
openPgpStoreInstance1.setTrust(alice, finger2, OpenPgpTrustStore.Trust.trusted);
|
||||
assertEquals(OpenPgpTrustStore.Trust.trusted, openPgpStoreInstance1.getTrust(alice, finger2));
|
||||
// Set trust a second time -> no change
|
||||
openPgpStoreInstance1.setTrust(alice, finger2, OpenPgpTrustStore.Trust.trusted);
|
||||
assertEquals(OpenPgpTrustStore.Trust.trusted, openPgpStoreInstance1.getTrust(alice, finger2));
|
||||
|
||||
assertEquals(OpenPgpTrustStore.Trust.undecided, openPgpStoreInstance1.getTrust(alice, finger3));
|
||||
|
||||
openPgpStoreInstance1.setTrust(bob, finger2, OpenPgpTrustStore.Trust.untrusted);
|
||||
assertEquals(OpenPgpTrustStore.Trust.untrusted, openPgpStoreInstance1.getTrust(bob, finger2));
|
||||
assertEquals(OpenPgpTrustStore.Trust.trusted, openPgpStoreInstance1.getTrust(alice, finger2));
|
||||
|
||||
// clean up
|
||||
openPgpStoreInstance1.setTrust(alice, finger2, OpenPgpTrustStore.Trust.undecided);
|
||||
openPgpStoreInstance1.setTrust(bob, finger2, OpenPgpTrustStore.Trust.undecided);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t09_trust_reloadTest() throws IOException {
|
||||
openPgpStoreInstance1.setTrust(alice, finger1, OpenPgpTrustStore.Trust.trusted);
|
||||
assertEquals(OpenPgpTrustStore.Trust.trusted, openPgpStoreInstance2.getTrust(alice, finger1));
|
||||
|
||||
// cleanup
|
||||
openPgpStoreInstance1.setTrust(alice, finger1, OpenPgpTrustStore.Trust.undecided);
|
||||
openPgpStoreInstance2.setTrust(alice, finger1, OpenPgpTrustStore.Trust.undecided);
|
||||
}
|
||||
|
||||
/*
|
||||
OpenPgpMetadataStore
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void t10_meta_emptyStoreTest() throws IOException {
|
||||
assertNotNull(openPgpStoreInstance1.getAnnouncedFingerprintsOf(alice));
|
||||
assertTrue(openPgpStoreInstance1.getAnnouncedFingerprintsOf(alice).isEmpty());
|
||||
|
||||
Map<OpenPgpV4Fingerprint, Date> map = new HashMap<>();
|
||||
Date date1 = new Date(12354563423L);
|
||||
Date date2 = new Date(8274729879812L);
|
||||
map.put(finger1, date1);
|
||||
map.put(finger2, date2);
|
||||
|
||||
openPgpStoreInstance1.setAnnouncedFingerprintsOf(alice, map);
|
||||
assertFalse(openPgpStoreInstance1.getAnnouncedFingerprintsOf(alice).isEmpty());
|
||||
assertEquals(map, openPgpStoreInstance1.getAnnouncedFingerprintsOf(alice));
|
||||
|
||||
assertTrue(openPgpStoreInstance1.getAnnouncedFingerprintsOf(bob).isEmpty());
|
||||
|
||||
assertFalse(openPgpStoreInstance2.getAnnouncedFingerprintsOf(alice).isEmpty());
|
||||
assertEquals(map, openPgpStoreInstance2.getAnnouncedFingerprintsOf(alice));
|
||||
|
||||
openPgpStoreInstance1.setAnnouncedFingerprintsOf(alice, Collections.<OpenPgpV4Fingerprint, Date>emptyMap());
|
||||
openPgpStoreInstance2.setAnnouncedFingerprintsOf(alice, Collections.<OpenPgpV4Fingerprint, Date>emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void t11_key_fetchDateTest() throws IOException {
|
||||
|
||||
Map<OpenPgpV4Fingerprint, Date> fetchDates1 = openPgpStoreInstance1.getPublicKeyFetchDates(alice);
|
||||
assertNotNull(fetchDates1);
|
||||
assertTrue(fetchDates1.isEmpty());
|
||||
|
||||
Date date1 = new Date(85092830954L);
|
||||
fetchDates1.put(finger1, date1);
|
||||
openPgpStoreInstance1.setPublicKeyFetchDates(alice, fetchDates1);
|
||||
|
||||
Map<OpenPgpV4Fingerprint, Date> fetchDates2 = openPgpStoreInstance1.getPublicKeyFetchDates(alice);
|
||||
assertNotNull(fetchDates2);
|
||||
assertFalse(fetchDates2.isEmpty());
|
||||
assertEquals(fetchDates1, fetchDates2);
|
||||
|
||||
Map<OpenPgpV4Fingerprint, Date> fetchDates3 = openPgpStoreInstance2.getPublicKeyFetchDates(alice);
|
||||
assertNotNull(fetchDates3);
|
||||
assertEquals(fetchDates1, fetchDates3);
|
||||
|
||||
openPgpStoreInstance1.setPublicKeyFetchDates(alice, null);
|
||||
openPgpStoreInstance2.setPublicKeyFetchDates(alice, null);
|
||||
|
||||
assertNotNull(openPgpStoreInstance1.getPublicKeyFetchDates(alice));
|
||||
assertTrue(openPgpStoreInstance1.getPublicKeyFetchDates(alice).isEmpty());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smack.DummyConnection;
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.util.FileUtils;
|
||||
import org.jivesoftware.smackx.ox.crypto.OpenPgpElementAndMetadata;
|
||||
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.element.CryptElement;
|
||||
import org.jivesoftware.smackx.ox.element.SignElement;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||
import org.jivesoftware.smackx.ox.store.definition.OpenPgpStore;
|
||||
import org.jivesoftware.smackx.ox.store.filebased.FileBasedOpenPgpStore;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.jxmpp.jid.JidTestUtil;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.pgpainless.key.collection.PGPKeyRing;
|
||||
import org.pgpainless.key.protection.UnprotectedKeysProtector;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
public class PainlessOpenPgpProviderTest extends SmackTestSuite {
|
||||
|
||||
private static final File storagePath;
|
||||
private static final BareJid alice = JidTestUtil.BARE_JID_1;
|
||||
private static final BareJid bob = JidTestUtil.BARE_JID_2;
|
||||
|
||||
static {
|
||||
storagePath = FileUtils.getTempDir("smack-painlessprovidertest");
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
@AfterClass
|
||||
public static void deletePath() {
|
||||
FileUtils.deleteDirectory(storagePath);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encryptDecryptTest() throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, IOException, MissingUserIdOnKeyException, XmlPullParserException {
|
||||
|
||||
// Initialize
|
||||
|
||||
OpenPgpStore aliceStore = new FileBasedOpenPgpStore(storagePath);
|
||||
OpenPgpStore bobStore = new FileBasedOpenPgpStore(storagePath);
|
||||
|
||||
aliceStore.setKeyRingProtector(new UnprotectedKeysProtector());
|
||||
bobStore.setKeyRingProtector(new UnprotectedKeysProtector());
|
||||
|
||||
PainlessOpenPgpProvider aliceProvider = new PainlessOpenPgpProvider(new DummyConnection(), aliceStore);
|
||||
PainlessOpenPgpProvider bobProvider = new PainlessOpenPgpProvider(new DummyConnection(), bobStore);
|
||||
|
||||
PGPKeyRing aliceKeys = aliceStore.generateKeyRing(alice);
|
||||
PGPKeyRing bobKeys = bobStore.generateKeyRing(bob);
|
||||
|
||||
OpenPgpV4Fingerprint aliceFingerprint = new OpenPgpV4Fingerprint(aliceKeys.getPublicKeys());
|
||||
OpenPgpV4Fingerprint bobFingerprint = new OpenPgpV4Fingerprint(bobKeys.getPublicKeys());
|
||||
|
||||
aliceStore.importSecretKey(alice, aliceKeys.getSecretKeys());
|
||||
bobStore.importSecretKey(bob, bobKeys.getSecretKeys());
|
||||
|
||||
aliceStore.setAnnouncedFingerprintsOf(alice, Collections.singletonMap(new OpenPgpV4Fingerprint(aliceKeys.getPublicKeys()), new Date()));
|
||||
bobStore.setAnnouncedFingerprintsOf(bob, Collections.singletonMap(new OpenPgpV4Fingerprint(bobKeys.getPublicKeys()), new Date()));
|
||||
|
||||
OpenPgpSelf aliceSelf = new OpenPgpSelf(alice, aliceStore);
|
||||
aliceSelf.trust(aliceFingerprint);
|
||||
OpenPgpSelf bobSelf = new OpenPgpSelf(bob, bobStore);
|
||||
bobSelf.trust(bobFingerprint);
|
||||
|
||||
// Exchange keys
|
||||
|
||||
aliceStore.importPublicKey(bob, bobKeys.getPublicKeys());
|
||||
bobStore.importPublicKey(alice, aliceKeys.getPublicKeys());
|
||||
|
||||
aliceStore.setAnnouncedFingerprintsOf(bob, Collections.singletonMap(new OpenPgpV4Fingerprint(bobKeys.getPublicKeys()), new Date()));
|
||||
bobStore.setAnnouncedFingerprintsOf(alice, Collections.singletonMap(new OpenPgpV4Fingerprint(aliceKeys.getPublicKeys()), new Date()));
|
||||
|
||||
OpenPgpContact aliceForBob = new OpenPgpContact(alice, bobStore);
|
||||
aliceForBob.trust(aliceFingerprint);
|
||||
OpenPgpContact bobForAlice = new OpenPgpContact(bob, aliceStore);
|
||||
bobForAlice.trust(bobFingerprint);
|
||||
|
||||
// Prepare message
|
||||
|
||||
Message.Body body = new Message.Body(null, "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
|
||||
List<ExtensionElement> payload = Collections.<ExtensionElement>singletonList(body);
|
||||
|
||||
|
||||
OpenPgpElementAndMetadata encrypted;
|
||||
OpenPgpMessage decrypted;
|
||||
|
||||
/*
|
||||
test signcrypt
|
||||
*/
|
||||
|
||||
SigncryptElement signcryptElement = new SigncryptElement(Collections.<Jid>singleton(bob), payload);
|
||||
|
||||
// Encrypt and Sign
|
||||
encrypted = aliceProvider.signAndEncrypt(signcryptElement, aliceSelf, Collections.singleton(bobForAlice));
|
||||
|
||||
// Decrypt and Verify
|
||||
decrypted = bobProvider.decryptAndOrVerify(encrypted.getElement(), bobSelf, aliceForBob);
|
||||
|
||||
OpenPgpV4Fingerprint decryptionFingerprint = decrypted.getMetadata().getDecryptionFingerprint();
|
||||
assertTrue(bobSelf.getSecretKeys().contains(decryptionFingerprint.getKeyId()));
|
||||
assertTrue(decrypted.getMetadata().getVerifiedSignaturesFingerprints().contains(aliceFingerprint));
|
||||
|
||||
assertEquals(OpenPgpMessage.State.signcrypt, decrypted.getState());
|
||||
SigncryptElement decryptedSignCrypt = (SigncryptElement) decrypted.getOpenPgpContentElement();
|
||||
|
||||
assertEquals(body.getMessage(), decryptedSignCrypt.<Message.Body>getExtension(Message.Body.ELEMENT, Message.Body.NAMESPACE).getMessage());
|
||||
|
||||
/*
|
||||
test crypt
|
||||
*/
|
||||
|
||||
CryptElement cryptElement = new CryptElement(Collections.<Jid>singleton(bob), payload);
|
||||
|
||||
// Encrypt
|
||||
encrypted = aliceProvider.encrypt(cryptElement, aliceSelf, Collections.singleton(bobForAlice));
|
||||
|
||||
decrypted = bobProvider.decryptAndOrVerify(encrypted.getElement(), bobSelf, aliceForBob);
|
||||
|
||||
decryptionFingerprint = decrypted.getMetadata().getDecryptionFingerprint();
|
||||
assertTrue(bobSelf.getSecretKeys().contains(decryptionFingerprint.getKeyId()));
|
||||
assertTrue(decrypted.getMetadata().getVerifiedSignaturesFingerprints().isEmpty());
|
||||
|
||||
assertEquals(OpenPgpMessage.State.crypt, decrypted.getState());
|
||||
CryptElement decryptedCrypt = (CryptElement) decrypted.getOpenPgpContentElement();
|
||||
|
||||
assertEquals(body.getMessage(), decryptedCrypt.<Message.Body>getExtension(Message.Body.ELEMENT, Message.Body.NAMESPACE).getMessage());
|
||||
|
||||
/*
|
||||
test sign
|
||||
*/
|
||||
|
||||
SignElement signElement = new SignElement(Collections.<Jid>singleton(bob), new Date(), payload);
|
||||
|
||||
// Sign
|
||||
encrypted = aliceProvider.sign(signElement, aliceSelf);
|
||||
|
||||
decrypted = bobProvider.decryptAndOrVerify(encrypted.getElement(), bobSelf, aliceForBob);
|
||||
|
||||
assertNull(decrypted.getMetadata().getDecryptionFingerprint());
|
||||
assertTrue(decrypted.getMetadata().getVerifiedSignaturesFingerprints().contains(aliceFingerprint));
|
||||
|
||||
assertEquals(OpenPgpMessage.State.sign, decrypted.getState());
|
||||
SignElement decryptedSign = (SignElement) decrypted.getOpenPgpContentElement();
|
||||
|
||||
assertEquals(body.getMessage(), decryptedSign.<Message.Body>getExtension(Message.Body.ELEMENT, Message.Body.NAMESPACE).getMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.junit.Test;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
|
||||
public class PubSubDelegateTest extends SmackTestSuite {
|
||||
|
||||
@Test
|
||||
public void pubkeyNodeNameTest() throws PGPException {
|
||||
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint("486f7065207520646f6e2068617665204f43640a");
|
||||
assertEquals("urn:xmpp:openpgp:0:public-keys:486F7065207520646F6E2068617665204F43640A",
|
||||
OpenPgpPubSubUtil.PEP_NODE_PUBLIC_KEY(fingerprint));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.test.util.TestUtils;
|
||||
import org.jivesoftware.smackx.ox.element.PubkeyElement;
|
||||
import org.jivesoftware.smackx.ox.provider.PubkeyElementProvider;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.jxmpp.util.XmppDateTime;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public class PubkeyElementTest extends SmackTestSuite {
|
||||
|
||||
@Test
|
||||
public void providerTest() throws Exception {
|
||||
String expected =
|
||||
"<pubkey xmlns='urn:xmpp:openpgp:0' date='2018-01-21T10:46:21.000+00:00'>" +
|
||||
"<data>" +
|
||||
"BASE64_OPENPGP_PUBLIC_KEY" +
|
||||
"</data>" +
|
||||
"</pubkey>";
|
||||
|
||||
Date date = XmppDateTime.parseXEP0082Date("2018-01-21T10:46:21.000+00:00");
|
||||
byte[] key = "BASE64_OPENPGP_PUBLIC_KEY".getBytes(Charset.forName("UTF-8"));
|
||||
PubkeyElement element = new PubkeyElement(new PubkeyElement.PubkeyDataElement(key), date);
|
||||
|
||||
assertXMLEqual(expected, element.toXML(null).toString());
|
||||
|
||||
XmlPullParser parser = TestUtils.getParser(expected);
|
||||
PubkeyElement parsed = PubkeyElementProvider.TEST_INSTANCE.parse(parser);
|
||||
|
||||
assertEquals(element.getDate(), parsed.getDate());
|
||||
assertTrue(Arrays.equals(element.getDataElement().getB64Data(), parsed.getDataElement().getB64Data()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.test.util.TestUtils;
|
||||
import org.jivesoftware.smackx.ox.element.PublicKeysListElement;
|
||||
import org.jivesoftware.smackx.ox.provider.PublicKeysListElementProvider;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.junit.Test;
|
||||
import org.jxmpp.util.XmppDateTime;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public class PublicKeysListElementTest extends SmackTestSuite {
|
||||
|
||||
@Test
|
||||
public void providerTest() throws Exception {
|
||||
String expected =
|
||||
"<public-keys-list xmlns='urn:xmpp:openpgp:0'>" +
|
||||
"<pubkey-metadata " +
|
||||
"v4-fingerprint='1357B01865B2503C18453D208CAC2A9678548E35' " +
|
||||
"date='2018-03-01T15:26:12.000+00:00'" +
|
||||
"/>" +
|
||||
"<pubkey-metadata " +
|
||||
"v4-fingerprint='67819B343B2AB70DED9320872C6464AF2A8E4C02' " +
|
||||
"date='1953-05-16T12:00:00.000+00:00'" +
|
||||
"/>" +
|
||||
"</public-keys-list>";
|
||||
|
||||
Date date1 = XmppDateTime.parseDate("2018-03-01T15:26:12.000+00:00");
|
||||
Date date2 = XmppDateTime.parseDate("1953-05-16T12:00:00.000+00:00");
|
||||
PublicKeysListElement.PubkeyMetadataElement child1 =
|
||||
new PublicKeysListElement.PubkeyMetadataElement(
|
||||
new OpenPgpV4Fingerprint("1357B01865B2503C18453D208CAC2A9678548E35"), date1);
|
||||
PublicKeysListElement.PubkeyMetadataElement child2 =
|
||||
new PublicKeysListElement.PubkeyMetadataElement(
|
||||
new OpenPgpV4Fingerprint("67819B343B2AB70DED9320872C6464AF2A8E4C02"), date2);
|
||||
|
||||
PublicKeysListElement element = PublicKeysListElement.builder()
|
||||
.addMetadata(child1)
|
||||
.addMetadata(child2)
|
||||
.build();
|
||||
|
||||
assertXMLEqual(expected, element.toXML(null).toString());
|
||||
|
||||
XmlPullParser parser = TestUtils.getParser(expected);
|
||||
PublicKeysListElement parsed = PublicKeysListElementProvider.TEST_INSTANCE.parse(parser);
|
||||
|
||||
assertEquals(element.getMetadata(), parsed.getMetadata());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listBuilderRefusesDuplicatesTest() throws PGPException {
|
||||
PublicKeysListElement.Builder builder = PublicKeysListElement.builder();
|
||||
String fp40 = "49545320414c4c2041424f555420444120484558";
|
||||
Date oneDate = new Date(12337883234L);
|
||||
Date otherDate = new Date(8888348384L);
|
||||
|
||||
// Check if size of metadata is one after insert.
|
||||
builder.addMetadata(new PublicKeysListElement.PubkeyMetadataElement(new OpenPgpV4Fingerprint(fp40), oneDate));
|
||||
assertEquals(builder.build().getMetadata().size(), 1);
|
||||
|
||||
// Check if size is still one after inserting element with same fp.
|
||||
builder.addMetadata(new PublicKeysListElement.PubkeyMetadataElement(new OpenPgpV4Fingerprint(fp40), otherDate));
|
||||
assertEquals(builder.build().getMetadata().size(), 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.jivesoftware.smack.DummyConnection;
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.util.FileUtils;
|
||||
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||
import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingOpenPgpKeyException;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||
import org.jivesoftware.smackx.ox.store.filebased.FileBasedOpenPgpStore;
|
||||
import org.jivesoftware.smackx.ox.util.SecretKeyBackupHelper;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.pgpainless.key.collection.PGPKeyRing;
|
||||
|
||||
public class SecretKeyBackupHelperTest extends SmackTestSuite {
|
||||
|
||||
private static final File basePath;
|
||||
|
||||
static {
|
||||
basePath = FileUtils.getTempDir("ox_secret_keys");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void backupPasswordGenerationTest() {
|
||||
final String alphabet = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ";
|
||||
|
||||
String backupCode = SecretKeyBackupHelper.generateBackupPassword();
|
||||
assertEquals(29, backupCode.length());
|
||||
for (int i = 0; i < backupCode.length(); i++) {
|
||||
if ((i + 1) % 5 == 0) {
|
||||
assertEquals('-', backupCode.charAt(i));
|
||||
} else {
|
||||
assertTrue(alphabet.indexOf(backupCode.charAt(i)) != -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAndDecryptSecretKeyElementTest()
|
||||
throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException,
|
||||
IOException, MissingUserIdOnKeyException, MissingOpenPgpKeyException, InvalidBackupCodeException {
|
||||
|
||||
// Prepare store and provider and so on...
|
||||
FileBasedOpenPgpStore store = new FileBasedOpenPgpStore(basePath);
|
||||
PainlessOpenPgpProvider provider = new PainlessOpenPgpProvider(new DummyConnection(), store);
|
||||
|
||||
// Generate and import key
|
||||
PGPKeyRing keyRing = PGPainless.generateKeyRing().simpleEcKeyRing("xmpp:alice@wonderland.lit");
|
||||
BareJid jid = JidCreate.bareFrom("alice@wonderland.lit");
|
||||
provider.getStore().importSecretKey(jid, keyRing.getSecretKeys());
|
||||
|
||||
// Create encrypted backup
|
||||
String backupCode = SecretKeyBackupHelper.generateBackupPassword();
|
||||
SecretkeyElement element = SecretKeyBackupHelper.createSecretkeyElement(provider, jid, Collections.singleton(new OpenPgpV4Fingerprint(keyRing.getSecretKeys())), backupCode);
|
||||
|
||||
// Decrypt backup and compare
|
||||
PGPSecretKeyRing secretKeyRing = SecretKeyBackupHelper.restoreSecretKeyBackup(element, backupCode);
|
||||
assertTrue(Arrays.equals(keyRing.getSecretKeys().getEncoded(), secretKeyRing.getEncoded()));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@BeforeClass
|
||||
public static void deleteDirs() {
|
||||
FileUtils.deleteDirectory(basePath);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.test.util.TestUtils;
|
||||
import org.jivesoftware.smackx.ox.element.SecretkeyElement;
|
||||
import org.jivesoftware.smackx.ox.provider.SecretkeyElementProvider;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public class SecretkeyElementTest extends SmackTestSuite {
|
||||
|
||||
@Test
|
||||
public void providerTest() throws Exception {
|
||||
String expected =
|
||||
"<secretkey xmlns='urn:xmpp:openpgp:0'>" +
|
||||
"BASE64_OPENPGP_ENCRYPTED_SECRET_KEY" +
|
||||
"</secretkey>";
|
||||
byte[] key = "BASE64_OPENPGP_ENCRYPTED_SECRET_KEY".getBytes(Charset.forName("UTF-8"));
|
||||
|
||||
SecretkeyElement element = new SecretkeyElement(key);
|
||||
|
||||
assertXMLEqual(expected, element.toXML(null).toString());
|
||||
|
||||
XmlPullParser parser = TestUtils.getParser(expected);
|
||||
SecretkeyElement parsed = SecretkeyElementProvider.TEST_INSTANCE.parse(parser);
|
||||
|
||||
assertTrue(Arrays.equals(element.getB64Data(), parsed.getB64Data()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.ox;
|
||||
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
|
||||
public class TestKeys {
|
||||
|
||||
public TestKeys() {
|
||||
|
||||
}
|
||||
|
||||
public static final BareJid JULIET_JID;
|
||||
public static final BareJid ROMEO_JID;
|
||||
|
||||
static {
|
||||
try {
|
||||
JULIET_JID = JidCreate.bareFrom("juliet@capulet.lit");
|
||||
ROMEO_JID = JidCreate.bareFrom("romeo@montague.lit");
|
||||
} catch (XmppStringprepException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final String JULIET_UID = "xmpp:juliet@capulet.lit";
|
||||
|
||||
/**
|
||||
* Public key of xmpp:juliet@capulet.lit.
|
||||
*/
|
||||
public static final String JULIET_PUB = "" +
|
||||
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||
"\n" +
|
||||
"mQENBFrxov4BCAChZwPrBxxIlwzpieR5T2pnaOZLWH0WqSON6rVjvfbJHWdDi3Th\n" +
|
||||
"remHW4gg4IBSTXkVFDIeQNVcOvGNgMg3Oe/x0I6FK12jrw9prycmjFxQ7A0ix7ZG\n" +
|
||||
"UkTF5jITgzJbkH100gYfXtZsfTyvgISSAT//6vvvQPZ3zCr09XvAG0CyQ1BhULsv\n" +
|
||||
"mVRe4Oh5b0VK4kLdv+GiA/T+49UKZj6lne9Vdti16ZIj7teVCbicfdhpTzsjur42\n" +
|
||||
"r8ptouKAuyFPw9KnGNwVlIiv5jt/Kit/LoOBenh74sitsCXq8IQ9kKp/eNt8TF4u\n" +
|
||||
"D4IGpxnJfB8XCiixYHoFEajmQBVJXNYtvoPvABEBAAG0F3htcHA6anVsaWV0QGNh\n" +
|
||||
"cHVsZXQubGl0iQFOBBMBCAA4FiEEHQGMdy34xe+GodzJtLUJy1k24D4FAlrxov4C\n" +
|
||||
"Gy8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQtLUJy1k24D6H7AgAoTjx4ezc\n" +
|
||||
"A83NeOY3tMHVQTM7hKuy0wMcSzQgVgJmhLYRZS8r+FocPZua/eke49GPhe2yozvl\n" +
|
||||
"ByWHtotklQeJiwOKxuPKMzneVA1ZK3/9LdGvtZlHMcAkEKDhit8HIaEcsFd4Z1re\n" +
|
||||
"EhF2lyvY/E+rrx9YxV0QjisSWV2dSptv6FeGSztr9e5E+Head6hEQhsugiTVRF+1\n" +
|
||||
"6mG90te0WGQ9YNiJ2FJovx5kBLTTuhwUz8Oacqihd2+RDDI5p3wJoogVL31aNb4n\n" +
|
||||
"c7dGo8ieJPHGlkBsOfmreSxijTodZz9MXsgcx7b//u0uQryViJoZHWbtnXOFjjNc\n" +
|
||||
"GWBtS084NKWl9w==\n" +
|
||||
"=ecwX\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
|
||||
/**
|
||||
* Private key of xmpp:juliet@capulet.lit.
|
||||
*/
|
||||
public static final String JULIET_PRIV = "" +
|
||||
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||
"\n" +
|
||||
"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\n" +
|
||||
"=yPPE\n" +
|
||||
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||
|
||||
public static final String ROMEO_UID = "xmpp:romeo@montague.lit";
|
||||
|
||||
/**
|
||||
* Public key of xmpp:romeo@montague.lit.
|
||||
*/
|
||||
public static final String ROMEO_PUB = "" +
|
||||
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||
"\n" +
|
||||
"mQENBFrxopkBCADiYg/+mEObXgxuMW6/LFKpEyaJK9pBMgutuxnYZ9PXWZmOhDIT\n" +
|
||||
"Ugm9X9YJ3Qh94KaHge9F4uCeFASmM1vvUTRFTEb1W5RR9ZE/sy/cdAttnZ5JloPi\n" +
|
||||
"CT3HDMIJAxIXhRJkeUR9GUb51ql27bMXl6lFh865VdNSXN/B8FzRQHENxv1Bq/6Z\n" +
|
||||
"iQOViIETeRRgO+u6u2iZkYlHgYMaoMK7+YiNlHXanU9Atcuaz0ZCJS/XFNH89iqB\n" +
|
||||
"Kvnv7KCQh4FhrNMLJRzNPXV8MY05nn0zF72qeEsniB16Xde18lMro8fQehg2mLwc\n" +
|
||||
"XGtCwCKI6QbZVxYQt77r3ZACiwl66soFWijVABEBAAG0F3htcHA6cm9tZW9AbW9u\n" +
|
||||
"dGFndWUubGl0iQFOBBMBCAA4FiEENdKZ0IovfYAjCwldBKMhguBeIfcFAlrxopkC\n" +
|
||||
"Gy8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQBKMhguBeIfcj8AgAu1wubUwr\n" +
|
||||
"2aQmDN3OqRM4M4yRL3oyYMkCKIjqD6KEeFsIXSSkXOuREJKEo8Mb1+ewV0SYmHCC\n" +
|
||||
"K3bKKq3m71AQ7evDhKGshacPYesiDvMdHWQdQnjfaoHhyn9qIKl7H0Xv1yf/wyuG\n" +
|
||||
"ANy1jYgtCEuYw7D+EsqNDdn8Xh+k/9s4aMI/6mfC0yGZgG8EyLTfbZkGPoS4aZfV\n" +
|
||||
"AGFbuqryg48dXtnuzAPKcdgMTTMSnmR729YlfkjCffcFaldyXoe1VMbudUO7nkO9\n" +
|
||||
"g65i5EXenkbc2h0TRDQ4lDFQyModqFTwYFYxAf/RA6tuhIQEoCnpCytFMvrRKMb3\n" +
|
||||
"Bx5vYRDVmE3jeg==\n" +
|
||||
"=2jSg\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
|
||||
/**
|
||||
* Private key of xmpp:romeo@montague.lit.
|
||||
*/
|
||||
public static final String ROMEO_PRIV = "" +
|
||||
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||
"\n" +
|
||||
"lQOYBFrxopkBCADiYg/+mEObXgxuMW6/LFKpEyaJK9pBMgutuxnYZ9PXWZmOhDIT\n" +
|
||||
"Ugm9X9YJ3Qh94KaHge9F4uCeFASmM1vvUTRFTEb1W5RR9ZE/sy/cdAttnZ5JloPi\n" +
|
||||
"CT3HDMIJAxIXhRJkeUR9GUb51ql27bMXl6lFh865VdNSXN/B8FzRQHENxv1Bq/6Z\n" +
|
||||
"iQOViIETeRRgO+u6u2iZkYlHgYMaoMK7+YiNlHXanU9Atcuaz0ZCJS/XFNH89iqB\n" +
|
||||
"Kvnv7KCQh4FhrNMLJRzNPXV8MY05nn0zF72qeEsniB16Xde18lMro8fQehg2mLwc\n" +
|
||||
"XGtCwCKI6QbZVxYQt77r3ZACiwl66soFWijVABEBAAEAB/4mu5p69/hRQ+UikWie\n" +
|
||||
"Yun9rZ4hSBR+pR5kaifA4/rV1Km2PZ4HujiaYyRO6beDOgWkF7IlpezCfzBQc2ce\n" +
|
||||
"ailkVemqHzIgV8CzQmhE8sHlzlr/wjXsXaJpRSCJxDG7PnRoJmt2b/W512WFSKQk\n" +
|
||||
"vDklAVh4U1vlsqhCGWr4DmuJbJkRyDhcX01tplRwim283F7bGqRcMBmKMZHiMgVc\n" +
|
||||
"0u84EYKKVizJ3YAaaVqZyHb4qdeKK2ak3fPNuGT/oGd2sxnkL+BZGjJpu3RGpTA1\n" +
|
||||
"tbOvOQnJGHQtABFxE8n6H9dHPJGtgyz2+udjUhL/P/E3PDoXazZkXRq2oHZKgg0f\n" +
|
||||
"AwOBBADsWncHgvz15rXPF7O6AivbGTJ5ctkgVy4U3Fu2sk9rf0fx0sryBSqtTBw1\n" +
|
||||
"Uvn/p9RwTsKw6fng6Nf78xpZFlUDB00YCcuWkGodxvjTAyB0dtBmkhopeKi0dmHh\n" +
|
||||
"ndnR6Pv0CsXu8nG7lUi+q6s3oc4h2OfDBhrqsyYY5M2gGit3dQQA9TNuinJD9XXv\n" +
|
||||
"QRyauMnSJ5xRcfOu8QCxZlllCvffZjSGCPoVjUpJEe9qsVbXVj2GYCxjLCSXV0V+\n" +
|
||||
"vlJfdPrl1BhZ3fmEpg0u7SyGDDOe8fe1ehk5sAeL8O0eFWlPSEaEccsjlpJ2FO0n\n" +
|
||||
"P04SZdOeM6wmhDTEDzpFnjbPndQTH+ED/R1zNzr55DvxQodmrW/BvTmhGQ22rHtk\n" +
|
||||
"IUfbeMaVfUvNLJA/JksrUIx3Gga9QCDZgfm1RsRhLUlHiqTQe23sPWgKOsbf5O1j\n" +
|
||||
"XJZaCNZ7LloVQbkG7xFcnb/n1+JjBr4FxXjAA6cY/iRGlznjIIaasyklKm1/4LuQ\n" +
|
||||
"hnH3QqTvCN3dOFS0F3htcHA6cm9tZW9AbW9udGFndWUubGl0iQFOBBMBCAA4FiEE\n" +
|
||||
"NdKZ0IovfYAjCwldBKMhguBeIfcFAlrxopkCGy8FCwkIBwIGFQoJCAsCBBYCAwEC\n" +
|
||||
"HgECF4AACgkQBKMhguBeIfcj8AgAu1wubUwr2aQmDN3OqRM4M4yRL3oyYMkCKIjq\n" +
|
||||
"D6KEeFsIXSSkXOuREJKEo8Mb1+ewV0SYmHCCK3bKKq3m71AQ7evDhKGshacPYesi\n" +
|
||||
"DvMdHWQdQnjfaoHhyn9qIKl7H0Xv1yf/wyuGANy1jYgtCEuYw7D+EsqNDdn8Xh+k\n" +
|
||||
"/9s4aMI/6mfC0yGZgG8EyLTfbZkGPoS4aZfVAGFbuqryg48dXtnuzAPKcdgMTTMS\n" +
|
||||
"nmR729YlfkjCffcFaldyXoe1VMbudUO7nkO9g65i5EXenkbc2h0TRDQ4lDFQyMod\n" +
|
||||
"qFTwYFYxAf/RA6tuhIQEoCnpCytFMvrRKMb3Bx5vYRDVmE3jeg==\n" +
|
||||
"=LZ1b\n" +
|
||||
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/**
|
||||
*
|
||||
* 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_im;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import org.jivesoftware.smack.DummyConnection;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smack.util.FileUtils;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.eme.element.ExplicitMessageEncryptionElement;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpContact;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpManager;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpMessage;
|
||||
import org.jivesoftware.smackx.ox.OpenPgpSelf;
|
||||
import org.jivesoftware.smackx.ox.crypto.PainlessOpenPgpProvider;
|
||||
import org.jivesoftware.smackx.ox.element.OpenPgpElement;
|
||||
import org.jivesoftware.smackx.ox.element.SigncryptElement;
|
||||
import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException;
|
||||
import org.jivesoftware.smackx.ox.store.filebased.FileBasedOpenPgpStore;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.JidTestUtil;
|
||||
import org.pgpainless.decryption_verification.OpenPgpMetadata;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
public class OXInstantMessagingManagerTest extends SmackTestSuite {
|
||||
|
||||
private static final File basePath;
|
||||
|
||||
static {
|
||||
basePath = FileUtils.getTempDir("ox_im_test_" + StringUtils.randomString(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws IOException, PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
|
||||
NoSuchProviderException, SmackException, MissingUserIdOnKeyException, InterruptedException, XMPPException,
|
||||
XmlPullParserException {
|
||||
DummyConnection aliceCon = new DummyConnection(
|
||||
DummyConnection.DummyConnectionConfiguration.builder()
|
||||
.setXmppDomain(JidTestUtil.EXAMPLE_ORG)
|
||||
.setUsernameAndPassword("alice", "dummypass").build());
|
||||
aliceCon.connect().login();
|
||||
|
||||
DummyConnection bobCon = new DummyConnection(
|
||||
DummyConnection.DummyConnectionConfiguration.builder()
|
||||
.setXmppDomain(JidTestUtil.EXAMPLE_ORG)
|
||||
.setUsernameAndPassword("bob", "dummypass").build());
|
||||
bobCon.connect().login();
|
||||
|
||||
FileBasedOpenPgpStore aliceStore = new FileBasedOpenPgpStore(new File(basePath, "alice"));
|
||||
FileBasedOpenPgpStore bobStore = new FileBasedOpenPgpStore(new File(basePath, "bob"));
|
||||
|
||||
PainlessOpenPgpProvider aliceProvider = new PainlessOpenPgpProvider(aliceCon, aliceStore);
|
||||
PainlessOpenPgpProvider bobProvider = new PainlessOpenPgpProvider(bobCon, bobStore);
|
||||
|
||||
OpenPgpManager aliceOpenPgp = OpenPgpManager.getInstanceFor(aliceCon);
|
||||
OpenPgpManager bobOpenPgp = OpenPgpManager.getInstanceFor(bobCon);
|
||||
|
||||
aliceOpenPgp.setOpenPgpProvider(aliceProvider);
|
||||
bobOpenPgp.setOpenPgpProvider(bobProvider);
|
||||
|
||||
OXInstantMessagingManager aliceOxim = OXInstantMessagingManager.getInstanceFor(aliceCon);
|
||||
OXInstantMessagingManager bobOxim = OXInstantMessagingManager.getInstanceFor(bobCon);
|
||||
|
||||
OpenPgpSelf aliceSelf = aliceOpenPgp.getOpenPgpSelf();
|
||||
OpenPgpSelf bobSelf = bobOpenPgp.getOpenPgpSelf();
|
||||
|
||||
assertFalse(aliceSelf.hasSecretKeyAvailable());
|
||||
assertFalse(bobSelf.hasSecretKeyAvailable());
|
||||
|
||||
// Generate keys
|
||||
aliceOpenPgp.generateAndImportKeyPair(aliceSelf.getJid());
|
||||
bobOpenPgp.generateAndImportKeyPair(bobSelf.getJid());
|
||||
|
||||
assertTrue(aliceSelf.hasSecretKeyAvailable());
|
||||
assertTrue(bobSelf.hasSecretKeyAvailable());
|
||||
|
||||
assertTrue(aliceSelf.isTrusted(aliceSelf.getSigningKeyFingerprint()));
|
||||
assertTrue(bobSelf.isTrusted(bobSelf.getSigningKeyFingerprint()));
|
||||
|
||||
assertTrue(aliceSelf.getTrustedFingerprints().contains(aliceSelf.getSigningKeyFingerprint()));
|
||||
|
||||
// Exchange keys
|
||||
aliceStore.importPublicKey(bobSelf.getJid(), bobSelf.getAnnouncedPublicKeys().iterator().next());
|
||||
bobStore.importPublicKey(aliceSelf.getJid(), aliceSelf.getAnnouncedPublicKeys().iterator().next());
|
||||
|
||||
// Simulate key announcement
|
||||
bobStore.setAnnouncedFingerprintsOf(bobSelf.getJid(), Collections.singletonMap(bobSelf.getSigningKeyFingerprint(), new Date()));
|
||||
bobStore.setAnnouncedFingerprintsOf(aliceSelf.getJid(), Collections.singletonMap(aliceSelf.getSigningKeyFingerprint(), new Date()));
|
||||
aliceStore.setAnnouncedFingerprintsOf(aliceSelf.getJid(), Collections.singletonMap(aliceSelf.getSigningKeyFingerprint(), new Date()));
|
||||
aliceStore.setAnnouncedFingerprintsOf(bobSelf.getJid(), Collections.singletonMap(bobSelf.getSigningKeyFingerprint(), new Date()));
|
||||
|
||||
OpenPgpContact aliceForBob = bobOpenPgp.getOpenPgpContact((EntityBareJid) aliceSelf.getJid());
|
||||
OpenPgpContact bobForAlice = aliceOpenPgp.getOpenPgpContact((EntityBareJid) bobSelf.getJid());
|
||||
|
||||
assertTrue(aliceForBob.hasUndecidedKeys());
|
||||
assertTrue(bobForAlice.hasUndecidedKeys());
|
||||
|
||||
assertTrue(aliceForBob.getUndecidedFingerprints().contains(aliceSelf.getSigningKeyFingerprint()));
|
||||
assertTrue(bobForAlice.getUndecidedFingerprints().contains(bobSelf.getSigningKeyFingerprint()));
|
||||
|
||||
bobForAlice.trust(bobSelf.getSigningKeyFingerprint());
|
||||
aliceForBob.trust(aliceSelf.getSigningKeyFingerprint());
|
||||
|
||||
assertFalse(aliceForBob.hasUndecidedKeys());
|
||||
assertFalse(bobForAlice.hasUndecidedKeys());
|
||||
|
||||
Message message = new Message();
|
||||
assertFalse(ExplicitMessageEncryptionElement.hasProtocol(message, ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0));
|
||||
|
||||
aliceOxim.addOxMessage(message, bobForAlice,
|
||||
Collections.<ExtensionElement>singletonList(new Message.Body(null, "Hello World!")));
|
||||
assertTrue(ExplicitMessageEncryptionElement.hasProtocol(message, ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0));
|
||||
assertNotNull(OpenPgpElement.fromStanza(message));
|
||||
|
||||
OpenPgpMessage decrypted = bobOpenPgp.decryptOpenPgpElement(OpenPgpElement.fromStanza(message), aliceForBob);
|
||||
assertEquals(OpenPgpMessage.State.signcrypt, decrypted.getState());
|
||||
|
||||
SigncryptElement signcryptElement = (SigncryptElement) decrypted.getOpenPgpContentElement();
|
||||
|
||||
Message.Body body = signcryptElement.getExtension(Message.Body.ELEMENT, Message.Body.NAMESPACE);
|
||||
assertNotNull(body);
|
||||
assertEquals("Hello World!", body.getMessage());
|
||||
|
||||
OpenPgpMetadata metadata = decrypted.getMetadata();
|
||||
assertTrue(metadata.isSigned() && metadata.isEncrypted());
|
||||
|
||||
// Check, if one of Bobs keys was used for decryption
|
||||
assertNotNull(bobSelf.getSigningKeyRing().getPublicKey(metadata.getDecryptionFingerprint().getKeyId()));
|
||||
|
||||
// Check if one of Alice' keys was used for signing
|
||||
assertTrue(metadata.containsVerifiedSignatureFrom(
|
||||
aliceForBob.getTrustedAnnouncedKeys().iterator().next()));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@BeforeClass
|
||||
public static void deleteDirs() {
|
||||
FileUtils.deleteDirectory(basePath);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue