diff --git a/domain/build.gradle b/domain/build.gradle index f6e291f..31be99d 100644 --- a/domain/build.gradle +++ b/domain/build.gradle @@ -21,9 +21,6 @@ dependencies { api "org.jxmpp:jxmpp-core:1.0.1" api "org.jxmpp:jxmpp-jid:1.0.1" - api "org.apache.santuario:xmlsec:2.2.0" - - testImplementation "org.igniterealtime.smack:smack-java7:$smackJava7Version" // RxJava2 diff --git a/domain/src/main/java/org/jivesoftware/smackx/ikey/IkeyManager.java b/domain/src/main/java/org/jivesoftware/smackx/ikey/IkeyManager.java index a1f3eef..7cd59d4 100644 --- a/domain/src/main/java/org/jivesoftware/smackx/ikey/IkeyManager.java +++ b/domain/src/main/java/org/jivesoftware/smackx/ikey/IkeyManager.java @@ -1,8 +1,6 @@ package org.jivesoftware.smackx.ikey; import org.apache.xml.security.c14n.CanonicalizationException; -import org.apache.xml.security.c14n.Canonicalizer; -import org.apache.xml.security.c14n.InvalidCanonicalizerException; import org.apache.xml.security.parser.XMLParserException; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.jivesoftware.smack.Manager; @@ -10,13 +8,10 @@ import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; -import org.jivesoftware.smack.util.Async; import org.jivesoftware.smackx.ikey.element.IkeyElement; import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureVerificationMechanism; import org.jivesoftware.smackx.ikey.util.IkeyConstants; import org.jivesoftware.smackx.ikey.util.UnsupportedSignatureAlgorithmException; -import org.jivesoftware.smackx.ikey.util.canonicalization.ElementCanonicalizer; -import org.jivesoftware.smackx.ikey.util.canonicalization.XmlSecElementCanonicalizer; import org.jivesoftware.smackx.ikey_ox.OxIkeySignatureVerificationMechanism; import org.jivesoftware.smackx.pep.PepEventListener; import org.jivesoftware.smackx.pep.PepManager; @@ -41,15 +36,9 @@ public final class IkeyManager extends Manager { private static final Map INSTANCES = new WeakHashMap<>(); private IkeyStore store; - private final ElementCanonicalizer canonicalizer; private IkeyManager(XMPPConnection connection) { super(connection); - try { - this.canonicalizer = new XmlSecElementCanonicalizer(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS)); - } catch (InvalidCanonicalizerException e) { - throw new AssertionError(e); - } } public static synchronized IkeyManager getInstanceFor(XMPPConnection connection) { @@ -106,7 +95,7 @@ public final class IkeyManager extends Manager { } private void processIkeyElement(EntityBareJid from, IkeyElement element) - throws XMLParserException, IOException, CanonicalizationException, UnsupportedSignatureAlgorithmException { + throws IOException, UnsupportedSignatureAlgorithmException { if (isFromTheFuture(element)) { LOGGER.log(Level.WARNING, "Received ikey element appears to be from the future: " + element.getSubordinates().getTimestamp()); return; @@ -126,9 +115,9 @@ public final class IkeyManager extends Manager { } private boolean verifyIkeyElement(EntityBareJid from, IkeyElement element) - throws XMLParserException, IOException, CanonicalizationException, UnsupportedSignatureAlgorithmException { + throws IOException, UnsupportedSignatureAlgorithmException { IkeySignatureVerificationMechanism verificationMechanism = getSignatureVerificationMechanismFor(element); - IkeySignatureVerifier verifier = new IkeySignatureVerifier(verificationMechanism, canonicalizer); + IkeySignatureVerifier verifier = new IkeySignatureVerifier(verificationMechanism); return verifier.verify(element, from); } @@ -168,7 +157,7 @@ public final class IkeyManager extends Manager { public void onPepEvent(EntityBareJid from, IkeyElement event, String id, Message carrierMessage) { try { processIkeyElement(from, event); - } catch (XMLParserException | CanonicalizationException | IOException | UnsupportedSignatureAlgorithmException e) { + } catch (IOException | UnsupportedSignatureAlgorithmException e) { LOGGER.log(Level.WARNING, "Error:", e); } } diff --git a/domain/src/main/java/org/jivesoftware/smackx/ikey/IkeySignatureVerifier.java b/domain/src/main/java/org/jivesoftware/smackx/ikey/IkeySignatureVerifier.java index 6e65cde..9273107 100644 --- a/domain/src/main/java/org/jivesoftware/smackx/ikey/IkeySignatureVerifier.java +++ b/domain/src/main/java/org/jivesoftware/smackx/ikey/IkeySignatureVerifier.java @@ -1,7 +1,5 @@ package org.jivesoftware.smackx.ikey; -import org.apache.xml.security.c14n.CanonicalizationException; -import org.apache.xml.security.parser.XMLParserException; import org.bouncycastle.util.encoders.Base64; import org.jivesoftware.smackx.ikey.element.IkeyElement; import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureVerificationMechanism; @@ -21,7 +19,7 @@ public class IkeySignatureVerifier { } public boolean verify(IkeyElement element, EntityBareJid owner) - throws XMLParserException, IOException, CanonicalizationException { + throws IOException { throwIfMismatchingMechanism(element); throwIfMismatchingOwnerJid(element, owner); diff --git a/domain/src/main/java/org/jivesoftware/smackx/ikey/element/IkeyElement.java b/domain/src/main/java/org/jivesoftware/smackx/ikey/element/IkeyElement.java index 78f5395..0dea6f8 100644 --- a/domain/src/main/java/org/jivesoftware/smackx/ikey/element/IkeyElement.java +++ b/domain/src/main/java/org/jivesoftware/smackx/ikey/element/IkeyElement.java @@ -22,13 +22,11 @@ public class IkeyElement implements ExtensionElement { private final IkeyType type; private final SuperordinateElement superordinate; private final SubordinateListElement subordinates; - private final ProofElement proof; - public IkeyElement(IkeyType type, SuperordinateElement superordinate, SubordinateListElement subordinates, ProofElement proof) { + public IkeyElement(IkeyType type, SuperordinateElement superordinate, SubordinateListElement subordinates) { this.type = type; this.superordinate = superordinate; this.subordinates = subordinates; - this.proof = proof; } public IkeyType getType() { @@ -43,10 +41,6 @@ public class IkeyElement implements ExtensionElement { return subordinates; } - public ProofElement getProof() { - return proof; - } - @Override public String getNamespace() { return NAMESPACE; @@ -64,7 +58,6 @@ public class IkeyElement implements ExtensionElement { .rightAngleBracket() .append(getSuperordinate()) .append(getSubordinates()) - .append(getProof()) .closeElement(this); } @@ -75,7 +68,6 @@ public class IkeyElement implements ExtensionElement { .append(getType()) .append(getSuperordinate()) .append(getSubordinates()) - .append(getProof()) .build(); } @@ -85,7 +77,6 @@ public class IkeyElement implements ExtensionElement { .append(getElementName(), o.getElementName()) .append(getType(), o.getType()) .append(getSuperordinate(), o.getSuperordinate()) - .append(getSubordinates(), o.getSubordinates()) - .append(getProof(), o.getProof())); + .append(getSubordinates(), o.getSubordinates())); } } diff --git a/domain/src/main/java/org/jivesoftware/smackx/ikey/element/SubordinateListElement.java b/domain/src/main/java/org/jivesoftware/smackx/ikey/element/SubordinateListElement.java index 0a64438..029d22d 100644 --- a/domain/src/main/java/org/jivesoftware/smackx/ikey/element/SubordinateListElement.java +++ b/domain/src/main/java/org/jivesoftware/smackx/ikey/element/SubordinateListElement.java @@ -16,16 +16,13 @@ public class SubordinateListElement implements NamedElement { public static final String NAMESPACE = IkeyConstants.NAMESPACE; public static final String ELEMENT = "subordinates"; - public static final String ATTR_STAMP = "stamp"; public static final String ATTR_JID = "jid"; private final List subordinates; private final EntityBareJid jid; - private final Date timestamp; - public SubordinateListElement(EntityBareJid jid, Date timestamp, List subordinates) { + public SubordinateListElement(EntityBareJid jid, List subordinates) { this.jid = jid; - this.timestamp = timestamp; this.subordinates = Objects.requireNonNullNorEmpty(subordinates, "List of subordinates MUST NOT be null nor empty."); } @@ -33,10 +30,6 @@ public class SubordinateListElement implements NamedElement { return jid; } - public Date getTimestamp() { - return timestamp; - } - public List getSubordinates() { return subordinates; } @@ -50,7 +43,6 @@ public class SubordinateListElement implements NamedElement { public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { return new XmlStringBuilder(this) .attribute(ATTR_JID, getJid()) - .attribute(ATTR_STAMP, getTimestamp()) .rightAngleBracket() .append(getSubordinates()) .closeElement(this); @@ -61,7 +53,6 @@ public class SubordinateListElement implements NamedElement { return HashCode.builder() .append(getElementName()) .append(getJid()) - .append(getTimestamp()) .append(getSubordinates()) .build(); } @@ -71,7 +62,6 @@ public class SubordinateListElement implements NamedElement { return EqualsUtil.equals(this, other, (e, o) -> e .append(getElementName(), o.getElementName()) .append(getJid(), o.getJid()) - .append(getTimestamp(), o.getTimestamp()) .append(getSubordinates(), o.getSubordinates())); } } diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/EncapsulatingSignatureManager.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/EncapsulatingSignatureManager.java new file mode 100644 index 0000000..4ba2dd8 --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/EncapsulatingSignatureManager.java @@ -0,0 +1,20 @@ +package org.jivesoftware.smackx.signed.xep0285; + +import org.bouncycastle.openpgp.PGPSignature; +import org.jivesoftware.smackx.signed.xep0285.element.DataElement; +import org.jivesoftware.smackx.signed.xep0285.element.PlainElement; +import org.jivesoftware.smackx.signed.xep0285.element.SignatureElement; +import org.jivesoftware.smackx.signed.xep0285.element.SignedElement; +import org.jivesoftware.smackx.signed.xep0285.signing.Signer; + +import java.io.IOException; + +public class EncapsulatingSignatureManager { + + public static SignedElement createSignedElement(PlainElement plainElement, Signer signer) throws IOException { + DataElement dataElement = DataElement.fromPlainElement(plainElement); + PGPSignature signature = signer.createSignature(dataElement.getUtf8Bytes()); + SignatureElement signatureElement = SignatureElement.fromBytes(signer.getAlgorithmName(signature), signature.getEncoded()); + return new SignedElement(signatureElement, dataElement); + } +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/DataElement.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/DataElement.java new file mode 100644 index 0000000..024d213 --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/DataElement.java @@ -0,0 +1,58 @@ +package org.jivesoftware.smackx.signed.xep0285.element; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smack.util.stringencoder.Base64; + +import java.nio.charset.StandardCharsets; + +public final class DataElement implements NamedElement { + + public static final String ELEMENT = "data"; + + private final String base64Content; + private final String utf8Content; + + private DataElement(String utf8Content, String base64Content) { + this.utf8Content = utf8Content; + this.base64Content = base64Content; + } + + public static DataElement fromUtf8Content(String utf8Content) { + return new DataElement(utf8Content, Base64.encodeToString(utf8Content.getBytes(StandardCharsets.UTF_8))); + } + + public static DataElement fromBase64Content(String base64Content) { + return new DataElement(Base64.decodeToString(base64Content), base64Content); + } + + public static DataElement fromPlainElement(PlainElement element) { + return fromUtf8Content(element.toXML().toString()); + } + + public String getUtf8Content() { + return utf8Content; + } + + public byte[] getUtf8Bytes() { + return getUtf8Content().getBytes(StandardCharsets.UTF_8); + } + + public String getBase64Content() { + return base64Content; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .rightAngleBracket() + .append(getBase64Content()) + .closeElement(this); + } +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/PlainElement.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/PlainElement.java new file mode 100644 index 0000000..67e5181 --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/PlainElement.java @@ -0,0 +1,92 @@ +package org.jivesoftware.smackx.signed.xep0285.element; + +import org.jivesoftware.smack.packet.ExtensionElement; +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; + +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public final class PlainElement implements ExtensionElement { + + public static final String ELEMENT = "plain"; + public static final String NAMESPACE = "urn:xmpp:signed:0"; + public static final String ATTR_TIMESTAMP = "timestamp"; + + private final String utf8Content; + private final String base64Content; + private final Date timestamp; + + private PlainElement(String utf8Content, String base64Content, Date timestamp) { + this.utf8Content = utf8Content; + this.base64Content = base64Content; + this.timestamp = timestamp; + } + + public static PlainElement fromExtensionElement(ExtensionElement element) { + return fromUtf8String(element.toXML().toString(), new Date()); + } + + public static PlainElement fromUtf8String(String utf8, Date timestamp) { + return new PlainElement(utf8, Base64.encodeToString(utf8.getBytes(StandardCharsets.UTF_8)), timestamp); + } + + public static PlainElement fromBase64String(String base64, Date timestamp) { + return new PlainElement(Base64.decodeToString(base64), base64, timestamp); + } + + public String getBase64Content() { + return base64Content; + } + + public String getUtf8Content() { + return utf8Content; + } + + public byte[] asUtf8Bytes() { + return toXML().toString().getBytes(StandardCharsets.UTF_8); + } + + public Date getTimestamp() { + return timestamp; + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .attribute(ATTR_TIMESTAMP, getTimestamp()) + .rightAngleBracket() + .append(getBase64Content()) + .closeElement(this); + } + + @Override + public boolean equals(Object other) { + return EqualsUtil.equals(this, other, (e, o) -> e + .append(getElementName(), o.getElementName()) + .append(getBase64Content(), o.getBase64Content()) + .append(getTimestamp(), o.getTimestamp())); + } + + @Override + public int hashCode() { + return HashCode.builder() + .append(getElementName()) + .append(getBase64Content()) + .append(getTimestamp()) + .build(); + } +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/SignatureElement.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/SignatureElement.java new file mode 100644 index 0000000..0cea166 --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/SignatureElement.java @@ -0,0 +1,56 @@ +package org.jivesoftware.smackx.signed.xep0285.element; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smack.util.stringencoder.Base64; + +public final class SignatureElement implements NamedElement { + + public static final String ELEMENT = "signature"; + public static final String ATTR_ALGORITHM = "algorithm"; + + private final String algorithm; + private final byte[] bytes; + private final String base64Content; + + private SignatureElement(String algorithm, byte[] bytes, String base64Content) { + this.algorithm = algorithm; + this.bytes = bytes; + this.base64Content = base64Content; + } + + public static SignatureElement fromBytes(String algorithm, byte[] bytes) { + return new SignatureElement(algorithm, bytes, Base64.encodeToString(bytes)); + } + + public static SignatureElement fromBase64Content(String algorithm, String base64Content) { + return new SignatureElement(algorithm, Base64.decode(base64Content), base64Content); + } + + public String getAlgorithm() { + return algorithm; + } + + public String getBase64Content() { + return base64Content; + } + + public byte[] getBytes() { + return bytes.clone(); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .attribute(ATTR_ALGORITHM, getAlgorithm()) + .rightAngleBracket() + .append(getBase64Content()) + .closeElement(this); + } +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/SignedElement.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/SignedElement.java new file mode 100644 index 0000000..6647035 --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/element/SignedElement.java @@ -0,0 +1,45 @@ +package org.jivesoftware.smackx.signed.xep0285.element; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class SignedElement implements ExtensionElement { + + public static final String ELEMENT = "signed"; + + private final SignatureElement signature; + private final DataElement data; + + public SignedElement(SignatureElement signature, DataElement data) { + this.signature = signature; + this.data = data; + } + + public SignatureElement getSignature() { + return signature; + } + + public DataElement getData() { + return data; + } + + @Override + public String getNamespace() { + return PlainElement.NAMESPACE; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + return new XmlStringBuilder(this) + .rightAngleBracket() + .append(getSignature()) + .append(getData()) + .closeElement(this); + } +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/provider/PlainElementProvider.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/provider/PlainElementProvider.java new file mode 100644 index 0000000..3f8040d --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/provider/PlainElementProvider.java @@ -0,0 +1,20 @@ +package org.jivesoftware.smackx.signed.xep0285.provider; + +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.parsing.SmackParsingException; +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smack.util.ParserUtils; +import org.jivesoftware.smack.xml.XmlPullParser; +import org.jivesoftware.smack.xml.XmlPullParserException; +import org.jivesoftware.smackx.signed.xep0285.element.PlainElement; + +import java.io.IOException; + +public class PlainElementProvider extends ExtensionElementProvider { + @Override + public PlainElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) + throws XmlPullParserException, IOException, SmackParsingException { + String timestamp = ParserUtils.getRequiredAttribute(parser, PlainElement.ATTR_TIMESTAMP); + return PlainElement.fromBase64String(parser.nextText(), ParserUtils.getDateFromXep82String(timestamp)); + } +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/provider/SignedElementProvider.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/provider/SignedElementProvider.java new file mode 100644 index 0000000..3330e23 --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/provider/SignedElementProvider.java @@ -0,0 +1,45 @@ +package org.jivesoftware.smackx.signed.xep0285.provider; + +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smack.util.Objects; +import org.jivesoftware.smack.util.ParserUtils; +import org.jivesoftware.smack.xml.XmlPullParser; +import org.jivesoftware.smack.xml.XmlPullParserException; +import org.jivesoftware.smackx.signed.xep0285.element.DataElement; +import org.jivesoftware.smackx.signed.xep0285.element.SignatureElement; +import org.jivesoftware.smackx.signed.xep0285.element.SignedElement; + +import java.io.IOException; + +public class SignedElementProvider extends ExtensionElementProvider { + + @Override + public SignedElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) + throws XmlPullParserException, IOException { + + SignatureElement signature = null; + DataElement data = null; + + XmlPullParser.TagEvent tag; + String name; + do { + tag = parser.nextTag(); + name = parser.getName(); + if (tag == XmlPullParser.TagEvent.START_ELEMENT) { + switch (name) { + case SignatureElement.ELEMENT: + String algorithm = ParserUtils.getRequiredAttribute(parser, SignatureElement.ATTR_ALGORITHM); + signature = SignatureElement.fromBase64Content(algorithm, parser.nextText()); + break; + + case DataElement.ELEMENT: + data = DataElement.fromBase64Content(parser.nextText()); + break; + } + } + } while (parser.getDepth() != initialDepth); + + return new SignedElement(Objects.requireNonNull(signature), Objects.requireNonNull(data)); + } +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/signing/OpenPGPSigner.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/signing/OpenPGPSigner.java new file mode 100644 index 0000000..4f5ecbc --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/signing/OpenPGPSigner.java @@ -0,0 +1,74 @@ +package org.jivesoftware.smackx.signed.xep0285.signing; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.util.io.Streams; +import org.pgpainless.PGPainless; +import org.pgpainless.algorithm.HashAlgorithm; +import org.pgpainless.algorithm.PublicKeyAlgorithm; +import org.pgpainless.decryption_verification.OpenPgpMetadata; +import org.pgpainless.encryption_signing.EncryptionStream; +import org.pgpainless.key.protection.SecretKeyRingProtector; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class OpenPGPSigner implements Signer { + + private final SecretKeyRingProtector protector; + private final PGPSecretKeyRing secretKey; + + public OpenPGPSigner(PGPSecretKeyRing secretKey, SecretKeyRingProtector protector) { + this.protector = protector; + this.secretKey = secretKey; + } + + @Override + public PGPSignature createSignature(byte[] data) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(data); + try { + EncryptionStream signer = PGPainless.createEncryptor().onOutputStream(outputStream) + .doNotEncrypt() + .createDetachedSignature() + .signWith(protector, secretKey) + .noArmor(); + Streams.pipeAll(inputStream, signer); + signer.close(); + inputStream.close(); + outputStream.close(); + OpenPgpMetadata metadata = signer.getResult(); + return metadata.getSignatures().iterator().next(); + + } catch (PGPException e) { + throw new IOException(e); + } + } + + @Override + public String getAlgorithmName(PGPSignature signature) { + PublicKeyAlgorithm signAlgo = PublicKeyAlgorithm.fromId(signature.getKeyAlgorithm()); + + String signAlgoName; + switch (signAlgo) { + case RSA_GENERAL: + case RSA_ENCRYPT: + case RSA_SIGN: + signAlgoName = "RSA"; + break; + case DSA: + signAlgoName = "DSA"; + break; + case ECDSA: + signAlgoName = "ECDSA"; + break; + default: + throw new IllegalArgumentException("Signature was signed with unknown signature algorithm: " + signature.getKeyAlgorithm()); + } + + signAlgoName += HashAlgorithm.fromId(signature.getHashAlgorithm()); + return signAlgoName; + } +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/signing/Signer.java b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/signing/Signer.java new file mode 100644 index 0000000..36bdacc --- /dev/null +++ b/domain/src/main/java/org/jivesoftware/smackx/signed/xep0285/signing/Signer.java @@ -0,0 +1,12 @@ +package org.jivesoftware.smackx.signed.xep0285.signing; + +import org.bouncycastle.openpgp.PGPSignature; + +import java.io.IOException; + +public interface Signer { + + PGPSignature createSignature(byte[] data) throws IOException; + + String getAlgorithmName(PGPSignature signature); +} diff --git a/domain/src/main/java/org/jivesoftware/smackx/util/MercurySmackTestSuite.java b/domain/src/main/java/org/jivesoftware/smackx/util/MercurySmackTestSuite.java index 68f034d..72a75b9 100644 --- a/domain/src/main/java/org/jivesoftware/smackx/util/MercurySmackTestSuite.java +++ b/domain/src/main/java/org/jivesoftware/smackx/util/MercurySmackTestSuite.java @@ -3,7 +3,13 @@ package org.jivesoftware.smackx.util; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.util.stringencoder.Base64; +import org.jivesoftware.smack.xml.SmackXmlParser; +import org.jivesoftware.smack.xml.XmlPullParser; +import org.jivesoftware.smack.xml.XmlPullParserException; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; import java.security.Security; public class MercurySmackTestSuite { @@ -35,4 +41,39 @@ public class MercurySmackTestSuite { Security.addProvider(new BouncyCastleProvider()); } + + public static XmlPullParser getParser(String string) { + return getParser(string, null); + } + + public static XmlPullParser getParser(String string, String startTag) { + return getParser(new StringReader(string), startTag); + } + + private static XmlPullParser getParser(Reader reader, String startTag) { + XmlPullParser parser; + try { + parser = SmackXmlParser.newXmlParser(reader); + if (startTag == null) { + while (parser.getEventType() != XmlPullParser.Event.START_ELEMENT) { + parser.next(); + } + return parser; + } + boolean found = false; + + while (!found) { + if ((parser.next() == XmlPullParser.Event.START_ELEMENT) && parser.getName().equals(startTag)) + found = true; + } + + if (!found) + throw new IllegalArgumentException("Can not find start tag '" + startTag + "'"); + } catch (XmlPullParserException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + return parser; + } } diff --git a/domain/src/test/java/org/jivesoftware/smackx/ikey/element/IkeyElementTest.java b/domain/src/test/java/org/jivesoftware/smackx/ikey/element/IkeyElementTest.java index 99961ea..af08f2a 100644 --- a/domain/src/test/java/org/jivesoftware/smackx/ikey/element/IkeyElementTest.java +++ b/domain/src/test/java/org/jivesoftware/smackx/ikey/element/IkeyElementTest.java @@ -59,38 +59,4 @@ public class IkeyElementTest extends MercurySmackTestSuite { return new SubordinateListElement(jid, date, Arrays.asList(subordinateElements)); } - public static XmlPullParser getParser(String string) { - return getParser(string, null); - } - - public static XmlPullParser getParser(String string, String startTag) { - return getParser(new StringReader(string), startTag); - } - - private static XmlPullParser getParser(Reader reader, String startTag) { - XmlPullParser parser; - try { - parser = SmackXmlParser.newXmlParser(reader); - if (startTag == null) { - while (parser.getEventType() != XmlPullParser.Event.START_ELEMENT) { - parser.next(); - } - return parser; - } - boolean found = false; - - while (!found) { - if ((parser.next() == XmlPullParser.Event.START_ELEMENT) && parser.getName().equals(startTag)) - found = true; - } - - if (!found) - throw new IllegalArgumentException("Can not find start tag '" + startTag + "'"); - } catch (XmlPullParserException e) { - throw new RuntimeException(e); - } catch (IOException e) { - throw new RuntimeException(e); - } - return parser; - } } diff --git a/domain/src/test/java/org/jivesoftware/smackx/signed/xep0285/PlainElementTest.java b/domain/src/test/java/org/jivesoftware/smackx/signed/xep0285/PlainElementTest.java new file mode 100644 index 0000000..29cc44b --- /dev/null +++ b/domain/src/test/java/org/jivesoftware/smackx/signed/xep0285/PlainElementTest.java @@ -0,0 +1,42 @@ +package org.jivesoftware.smackx.signed.xep0285; + +import org.jivesoftware.smack.parsing.SmackParsingException; +import org.jivesoftware.smack.util.ParserUtils; +import org.jivesoftware.smack.xml.XmlPullParserException; +import org.jivesoftware.smackx.signed.xep0285.element.PlainElement; +import org.jivesoftware.smackx.signed.xep0285.provider.PlainElementProvider; +import org.jivesoftware.smackx.util.MercurySmackTestSuite; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PlainElementTest extends MercurySmackTestSuite { + + @Test + public void test() throws XmlPullParserException, IOException, SmackParsingException { + String plain = "" + + "c6373824-a307-40dd-8fe0-bad6e7299ad0" + + "Wherefore art thou, Romeo?" + + ""; + String example2 = "" + + "PG1lc3NhZ2UgeG1sbnM9ImphYmJlcjpjbGllbnQiIGZyb209Imp1bGlldEBjYXB" + + "1bGV0Lm5ldC9iYWxjb255IiB0bz0icm9tZW9AbW9udGVndWUubmV0IiB0eXBlPS" + + "JjaGF0Ij48dGhyZWFkPmM2MzczODI0LWEzMDctNDBkZC04ZmUwLWJhZDZlNzI5O" + + "WFkMDwvdGhyZWFkPjxib2R5PldoZXJlZm9yZSBhcnQgdGhvdSwgUm9tZW8/PC9i" + + "b2R5PjwvbWVzc2FnZT4=" + + ""; + + PlainElement parsed = new PlainElementProvider() + .parse(getParser(example2)); + PlainElement fromPlain = PlainElement.fromUtf8String(plain, ParserUtils.getDateFromXep82String("2010-06-29T02:15:21.012+00:00")); + + assertEquals(parsed, fromPlain); + assertEquals(plain, parsed.getUtf8Content()); + } +} diff --git a/domain/src/test/java/org/jivesoftware/smackx/signed/xep0285/SignedElementTest.java b/domain/src/test/java/org/jivesoftware/smackx/signed/xep0285/SignedElementTest.java new file mode 100644 index 0000000..8c75645 --- /dev/null +++ b/domain/src/test/java/org/jivesoftware/smackx/signed/xep0285/SignedElementTest.java @@ -0,0 +1,40 @@ +package org.jivesoftware.smackx.signed.xep0285; + +import org.jivesoftware.smack.parsing.SmackParsingException; +import org.jivesoftware.smack.xml.XmlPullParserException; +import org.jivesoftware.smackx.signed.xep0285.element.SignedElement; +import org.jivesoftware.smackx.signed.xep0285.provider.SignedElementProvider; +import org.jivesoftware.smackx.util.MercurySmackTestSuite; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +public class SignedElementTest extends MercurySmackTestSuite { + + @Test + public void test() throws XmlPullParserException, IOException, SmackParsingException { + String example3 = + "" + + "" + + "DxbxIziY1C1Ytcxkj0IFLsfmDLMv96JMlMAQZ7jh49IbsOIPsxI2LyLmqhKH/994UXDJKQLHvLJz" + + "gAmw8V2b+zmyZeItJzSmB+HHiLFVXkD2Dd4JfetsafsfIcB7uNWg0gAeiKrTHfFgiyEC/2WxwOj3" + + "JUMRyQ9ykEPIzS0GZ/k=" + + "" + + "" + + "PHBsYWluIHhtbG5zPSJ1cm46eG1wcDpzaWduZWQ6MCIgdGltZXN0YW1wPSIyMDEwLTA2LTI5VDAy" + + "OjE1OjIxLjAxMloiPgogIFBHMWxjM05oWjJVZ2VHMXNibk05SW1waFltSmxjanBqYkdsbGJuUWlJ" + + "R1p5YjIwOUltcDFiR2xsZEVCallYQgogIDFiR1YwTG01bGRDOWlZV3hqYjI1NUlpQjBiejBpY205" + + "dFpXOUFiVzl1ZEdWbmRXVXVibVYwSWlCMGVYQmxQUwogIEpqYUdGMElqNDhkR2h5WldGa1BtTTJN" + + "emN6T0RJMExXRXpNRGN0TkRCa1pDMDRabVV3TFdKaFpEWmxOekk1TwogIFdGa01Ed3ZkR2h5WldG" + + "a1BqeGliMlI1UGxkb1pYSmxabTl5WlNCaGNuUWdkR2h2ZFN3Z1VtOXRaVzgvUEM5aQogIGIyUjVQ" + + "and2YldWemMyRm5aVDQ9CjwvcGxhaW4+Cg==" + + "" + + ""; + + SignedElement signedElement = new SignedElementProvider() + .parse(getParser(example3)); + + System.out.println(example3); + System.out.println(signedElement.toXML()); + } +} diff --git a/libs/Smack b/libs/Smack index 38bfe24..1c822dc 160000 --- a/libs/Smack +++ b/libs/Smack @@ -1 +1 @@ -Subproject commit 38bfe2492149cb095a1376080320e37c71832504 +Subproject commit 1c822dcaa4d4cb92d8b2d048f49bb69885143d56