Add OxIkeyManager

This commit is contained in:
Paul Schaub 2020-09-25 22:18:42 +02:00
parent 474e327f42
commit 49eb137acb
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
8 changed files with 236 additions and 0 deletions

View File

@ -17,6 +17,8 @@ dependencies {
api "org.igniterealtime.smack:smack-im:$smackImVersion"
api "org.igniterealtime.smack:smack-tcp:$smackTcpVersion"
api "org.igniterealtime.smack:smack-openpgp:$smackOpenpgpVersion"
api "org.igniterealtime.smack:smack-omemo:$smackOmemoVersion"
api "org.igniterealtime.smack:smack-omemo-signal:$smackOmemoSignalVersion"
api "org.jxmpp:jxmpp-core:1.0.1"
api "org.jxmpp:jxmpp-jid:1.0.1"

View File

@ -8,7 +8,11 @@ import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.ikey.element.IkeyElement;
import org.jivesoftware.smackx.ikey.element.ProofElement;
import org.jivesoftware.smackx.ikey.element.SignedElement;
import org.jivesoftware.smackx.ikey.element.SubordinateListElement;
import org.jivesoftware.smackx.ikey.element.SuperordinateElement;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.ikey.provider.IkeyElementProvider;
import org.jivesoftware.smackx.ikey.provider.SubordinateListElementProvider;
@ -69,6 +73,15 @@ public final class IkeyManager extends Manager {
.removePepEventListener(pepEventListener);
}
public IkeyElement createIkeyElement(IkeySignatureCreationMechanism mechanism,
SuperordinateElement superordinateElement,
SubordinateListElement subordinateListElement)
throws IOException {
SignedElement signedElement = new SignedElement(subordinateListElement);
ProofElement proofElement = new ProofElement(mechanism.createSignature(signedElement.getUtf8Bytes()));
return new IkeyElement(mechanism.getType(), superordinateElement, signedElement, proofElement);
}
public void publishIkeyElement(IkeyElement ikeyElement)
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
SmackException.NotConnectedException, SmackException.NoResponseException {

View File

@ -5,6 +5,7 @@ import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.EqualsUtil;
import org.jivesoftware.smack.util.HashCode;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
public class ProofElement implements NamedElement {
@ -16,6 +17,10 @@ public class ProofElement implements NamedElement {
this.base64Sig = base64Sig;
}
public ProofElement(byte[] plainBytes) {
this(Base64.encodeToString(plainBytes));
}
public String getBase64Signature() {
return base64Sig;
}

View File

@ -0,0 +1,49 @@
package org.jivesoftware.smackx.ikey_ox;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smackx.ikey.IkeyManager;
import org.jivesoftware.smackx.ikey.element.IkeyElement;
import org.jivesoftware.smackx.ikey.element.SubordinateElement;
import org.jivesoftware.smackx.ikey.element.SubordinateListElement;
import org.jivesoftware.smackx.ikey.element.SuperordinateElement;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureCreationMechanism;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.WeakHashMap;
public final class OxIkeyManager extends Manager {
private static final Map<XMPPConnection, OxIkeyManager> INSTANCES = new WeakHashMap<>();
private final IkeyManager ikeyManager;
private OxIkeyManager(XMPPConnection connection) {
super(connection);
this.ikeyManager = IkeyManager.getInstanceFor(connection);
}
public static OxIkeyManager getInstanceFor(XMPPConnection connection) {
OxIkeyManager manager = INSTANCES.get(connection);
if (manager == null) {
manager = new OxIkeyManager(connection);
INSTANCES.put(connection, manager);
}
return manager;
}
public IkeyElement createOxIkeyElement(PGPSecretKeyRing secretKeys,
SecretKeyRingProtector keyRingProtector,
SubordinateElement... subordinateElements) throws IOException {
IkeySignatureCreationMechanism mechanism = new OxIkeySignatureCreationMechanism(secretKeys, keyRingProtector);
SuperordinateElement superordinateElement = new SuperordinateElement(secretKeys.getPublicKey().getEncoded());
SubordinateListElement subordinateListElement = new SubordinateListElement(connection().getUser().asEntityBareJid(),
new Date(), Arrays.asList(subordinateElements));
return ikeyManager.createIkeyElement(mechanism, superordinateElement, subordinateListElement);
}
}

View File

@ -0,0 +1,37 @@
package org.jivesoftware.smackx.ikey_utils;
import org.jivesoftware.smackx.ikey.element.SubordinateElement;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint;
import org.jivesoftware.smackx.ox.util.OpenPgpPubSubUtil;
import org.jivesoftware.smackx.pubsub.PubSubUri;
import org.jxmpp.jid.BareJid;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.net.URI;
import java.net.URISyntaxException;
public class IkeySubordinateElementCreator {
public static SubordinateElement createOxSubordinateElement(BareJid pubSubService, OpenPgpV4Fingerprint fingerprint, String itemId)
throws URISyntaxException {
String node = OpenPgpPubSubUtil.PEP_NODE_PUBLIC_KEY(fingerprint);
PubSubUri pubSubUri = new PubSubUri(pubSubService, node, itemId, null);
URI uri = new URI(pubSubUri.toString());
return new SubordinateElement(uri, fingerprint.toString());
}
public static SubordinateElement createOmemoSubordinateElement(BareJid pubSubService, OmemoDevice device, OmemoFingerprint fingerprint)
throws URISyntaxException {
PubSubUri pubSubUri = new PubSubUri(pubSubService, "urn:xmpp:omemo:1:bundles", Integer.toString(device.getDeviceId()), null);
URI uri = new URI(pubSubUri.toString());
return new SubordinateElement(uri, fingerprint.toString());
}
public static SubordinateElement createSiacsOmemoSubordinateElement(BareJid pubSubService, OmemoDevice device, OmemoFingerprint fingerprint)
throws URISyntaxException {
PubSubUri pubSubUri = new PubSubUri(pubSubService, device.getBundleNodeName(), null, null);
URI uri = new URI(pubSubUri.toString());
return new SubordinateElement(uri, fingerprint.toString());
}
}

View File

@ -44,6 +44,7 @@ public class IkeyElementTest extends MercurySmackTestSuite {
IkeyElement ikeyElement = new IkeyElement(type, superordinate, new SignedElement(subordinates), proof);
String xml = ikeyElement.toXML().toString();
System.out.println(xml);
System.out.println(subordinates.toXML().toString());
IkeyElement parsed = IkeyElementProvider.INSTANCE.parse(PacketParserUtils.getParserFor(xml));

View File

@ -0,0 +1,73 @@
package org.jivesoftware.smackx.ikey.element;
import org.bouncycastle.openpgp.PGPException;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.ikey.IkeySignatureCreator;
import org.jivesoftware.smackx.ikey.IkeySignatureVerifier;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
import org.jivesoftware.smackx.ikey_ox.OxIkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ikey_ox.OxIkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.util.MercurySmackTestSuite;
import org.junit.jupiter.api.Test;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.key.collection.PGPKeyRing;
import org.pgpainless.key.generation.KeySpec;
import org.pgpainless.key.generation.type.ECDSA;
import org.pgpainless.key.generation.type.curve.EllipticCurve;
import org.pgpainless.key.protection.UnprotectedKeysProtector;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class XepTest extends MercurySmackTestSuite {
@Test
public void test() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException, URISyntaxException {
EntityBareJid jid = JidCreate.entityBareFromOrThrowUnchecked("juliet@capulet.lit");
PGPKeyRing keyRing = PGPainless.generateKeyRing()
.withMasterKey(KeySpec.getBuilder(ECDSA.fromCurve(EllipticCurve._P256))
.withKeyFlags(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)
.withDefaultAlgorithms())
.withPrimaryUserId("xmpp:" + jid)
.withoutPassphrase()
.build();
IkeySignatureCreationMechanism signingMechanism = new OxIkeySignatureCreationMechanism(
keyRing.getSecretKeys(), new UnprotectedKeysProtector());
IkeySignatureCreator creator = new IkeySignatureCreator(signingMechanism);
IkeySignatureVerificationMechanism verificationMechanism = new OxIkeySignatureVerificationMechanism(keyRing.getPublicKeys());
IkeySignatureVerifier verifier = new IkeySignatureVerifier(verificationMechanism);
SuperordinateElement superordinate = new SuperordinateElement(Base64.encodeToString(keyRing.getMasterKey().getEncoded()));
List<SubordinateElement> subList = new ArrayList<>();
subList.add(new SubordinateElement(
new URI("xmpp:" + jid + "?;node=urn:xmpp:openpgp:0:public-keys:1357B01865B2503C18453D208CAC2A9678548E35;item=2020-01-21T10:46:21Z"),
"1357B01865B2503C18453D208CAC2A9678548E35"));
subList.add(new SubordinateElement(new URI("xmpp:" + jid + "?;node=urn:xmpp:omemo:1:bundles;item=31415"), "e64dc9166dd34db64c9247bd502c5969e365a98f3aa41c87247d120487fdd32f"));
subList.add(new SubordinateElement(new URI("xmpp:" + jid + "?;node=eu.siacs.conversations.axolotl.bundles:31415"), "e64dc9166dd34db64c9247bd502c5969e365a98f3aa41c87247d120487fdd32f"));
SubordinateListElement subs = new SubordinateListElement(jid, new Date(), subList);
ProofElement proofElement = creator.createProofFor(subs);
IkeyElement ikeyElement = new IkeyElement(IkeyType.OX, superordinate, new SignedElement(subs), proofElement);
System.out.println(subs.toXML().toString());
System.out.println(ikeyElement.toXML().toString());
assertTrue(verifier.verify(ikeyElement, jid));
}
}

View File

@ -0,0 +1,56 @@
package org.jivesoftware.smackx.ikey_utils;
import org.jivesoftware.smackx.ikey.element.SubordinateElement;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint;
import org.junit.jupiter.api.Test;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import java.net.URISyntaxException;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class IkeySubordinateElementCreatorTest {
@Test
public void testOxSubordinateElementCreation() throws URISyntaxException {
String xml = "<sub uri='xmpp:hamlet@denmark.lit?;node=urn:xmpp:openpgp:0:public-keys:1357B01865B2503C18453D208CAC2A9678548E35;item=2020-01-21T10:46:21Z' " +
"fpr='1357B01865B2503C18453D208CAC2A9678548E35'/>";
BareJid pubSubService = JidCreate.bareFromOrThrowUnchecked("hamlet@denmark.lit");
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint("1357B01865B2503C18453D208CAC2A9678548E35");
String itemId = "2020-01-21T10:46:21Z";
SubordinateElement element = IkeySubordinateElementCreator.createOxSubordinateElement(pubSubService, fingerprint, itemId);
assertEquals(xml, element.toXML().toString());
}
@Test
public void testOmemoSubordinateElementCreation() throws URISyntaxException {
String xml = "<sub uri='xmpp:hamlet@denmark.lit?;node=urn:xmpp:omemo:1:bundles;item=31415' " +
"fpr='e64dc9166dd34db64c9247bd502c5969e365a98f3aa41c87247d120487fdd32f'/>";
BareJid pubSubService = JidCreate.bareFromOrThrowUnchecked("hamlet@denmark.lit");
OmemoFingerprint fingerprint = new OmemoFingerprint("e64dc9166dd34db64c9247bd502c5969e365a98f3aa41c87247d120487fdd32f");
SubordinateElement element = IkeySubordinateElementCreator.createOmemoSubordinateElement(pubSubService, new OmemoDevice(pubSubService, 31415), fingerprint);
assertEquals(xml, element.toXML().toString());
}
@Test
public void testSiacsOmemoSubordinateElementCreation() throws URISyntaxException {
String xml = "<sub uri='xmpp:hamlet@denmark.lit?;node=eu.siacs.conversations.axolotl.bundles:31415' " +
"fpr='e64dc9166dd34db64c9247bd502c5969e365a98f3aa41c87247d120487fdd32f'/>";
BareJid pubSubService = JidCreate.bareFromOrThrowUnchecked("hamlet@denmark.lit");
OmemoFingerprint fingerprint = new OmemoFingerprint("e64dc9166dd34db64c9247bd502c5969e365a98f3aa41c87247d120487fdd32f");
SubordinateElement element = IkeySubordinateElementCreator.createSiacsOmemoSubordinateElement(pubSubService, new OmemoDevice(pubSubService, 31415), fingerprint);
assertEquals(xml, element.toXML().toString());
}
}