Comment JET code

This commit is contained in:
vanitasvitae 2017-08-25 16:34:20 +02:00
parent efe0adebe3
commit 5bef2f44ce
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
9 changed files with 142 additions and 26 deletions

View File

@ -17,6 +17,9 @@
package org.jivesoftware.smackx.jet; package org.jivesoftware.smackx.jet;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
@ -53,6 +56,7 @@ import org.jxmpp.jid.FullJid;
/** /**
* Manager for Jingle Encrypted Transfers (XEP-XXXX). * Manager for Jingle Encrypted Transfers (XEP-XXXX).
* @see <a href="https://geekplace.eu/xeps/xep-jet/xep-jet.html">Proto-XEP</a>
*/ */
public final class JetManager extends Manager implements JingleDescriptionManager { public final class JetManager extends Manager implements JingleDescriptionManager {
@ -76,6 +80,11 @@ public final class JetManager extends Manager implements JingleDescriptionManage
jingleManager.addJingleDescriptionManager(this); jingleManager.addJingleDescriptionManager(this);
} }
/**
* Return an instance of the JetManager for the given connection.
* @param connection connection.
* @return instance.
*/
public static JetManager getInstanceFor(XMPPConnection connection) { public static JetManager getInstanceFor(XMPPConnection connection) {
JetManager manager = INSTANCES.get(connection); JetManager manager = INSTANCES.get(connection);
@ -87,35 +96,60 @@ public final class JetManager extends Manager implements JingleDescriptionManage
return manager; return manager;
} }
public OutgoingFileOfferController sendEncryptedFile(File file, FullJid recipient, JingleEnvelopeManager envelopeManager) throws Exception { /**
* Send a file to recipient, JET encrypted using the method described by envelopeManager.
* @param file file
* @param recipient recipient
* @param envelopeManager {@link JingleEnvelopeManager} (eg. OmemoManager).
* @return controller for the outgoing file transfer.
*/
public OutgoingFileOfferController sendEncryptedFile(File file, FullJid recipient, JingleEnvelopeManager envelopeManager)
throws IOException, NoSuchAlgorithmException, SmackException.FeatureNotSupportedException,
InvalidKeyException, InterruptedException, XMPPException.XMPPErrorException, NoSuchPaddingException,
JingleEnvelopeManager.JingleEncryptionException, SmackException.NotConnectedException,
SmackException.NoResponseException, NoSuchProviderException, InvalidAlgorithmParameterException {
return sendEncryptedFile(file, JingleFile.fromFile(file, null, null, null), recipient, envelopeManager); return sendEncryptedFile(file, JingleFile.fromFile(file, null, null, null), recipient, envelopeManager);
} }
public OutgoingFileOfferController sendEncryptedFile(File file, JingleFile metadata, FullJid recipient, JingleEnvelopeManager envelopeManager) throws Exception { /**
* Send a file to recipient, JET encrypted using the method described by envelopeManager.
* @param file file containing data.
* @param metadata custom metadata about the file (like alternative filename...)
* @param recipient recipient
* @param envelopeManager {@link JingleEnvelopeManager} (eg. OmemoManager).
* @return controller for the outgoing file transfer.
*/
public OutgoingFileOfferController sendEncryptedFile(File file, JingleFile metadata, FullJid recipient, JingleEnvelopeManager envelopeManager)
throws FileNotFoundException, SmackException.FeatureNotSupportedException, NoSuchAlgorithmException,
InvalidKeyException, InterruptedException, XMPPException.XMPPErrorException, NoSuchPaddingException,
JingleEnvelopeManager.JingleEncryptionException, SmackException.NotConnectedException,
SmackException.NoResponseException, NoSuchProviderException, InvalidAlgorithmParameterException {
if (file == null || !file.exists()) { if (file == null || !file.exists()) {
throw new IllegalArgumentException("File MUST NOT be null and MUST exist."); throw new IllegalArgumentException("File MUST NOT be null and MUST exist.");
} }
throwIfRecipientLacksSupport(recipient); return sendEncryptedStream(new FileInputStream(file), metadata, recipient, envelopeManager);
JingleSession session = jingleManager.createSession(Role.initiator, recipient);
JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator);
session.addContent(content);
JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(file, metadata);
content.setDescription(offer);
JingleTransportManager transportManager = jingleManager.getBestAvailableTransportManager(recipient);
content.setTransport(transportManager.createTransportForInitiator(content));
JetSecurity security = new JetSecurity(envelopeManager, recipient, content.getName(), Aes256GcmNoPadding.NAMESPACE);
content.setSecurity(security);
session.sendInitiate(connection());
return offer;
} }
/**
* Send the content of an InputStream to recipient, JET encrypted via the method described by envelopeManager.
* @param inputStream InputStream with data.
* @param metadata metadata about the inputstream (filename etc).
* @param recipient recipient
* @param envelopeManager {@link JingleEnvelopeManager} (eg. OmemoManager).
* @return controller for the outgoing file transfer.
* @throws XMPPException.XMPPErrorException
* @throws SmackException.FeatureNotSupportedException Recipient does not support JET or needed Jingle features.
* @throws SmackException.NotConnectedException
* @throws InterruptedException
* @throws SmackException.NoResponseException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws JingleEnvelopeManager.JingleEncryptionException JET encryption failed.
* @throws NoSuchProviderException
* @throws InvalidAlgorithmParameterException
*/
public OutgoingFileOfferController sendEncryptedStream(InputStream inputStream, JingleFile metadata, FullJid recipient, JingleEnvelopeManager envelopeManager) public OutgoingFileOfferController sendEncryptedStream(InputStream inputStream, JingleFile metadata, FullJid recipient, JingleEnvelopeManager envelopeManager)
throws XMPPException.XMPPErrorException, SmackException.FeatureNotSupportedException, SmackException.NotConnectedException, throws XMPPException.XMPPErrorException, SmackException.FeatureNotSupportedException, SmackException.NotConnectedException,
InterruptedException, SmackException.NoResponseException, NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, InterruptedException, SmackException.NoResponseException, NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException,
@ -140,26 +174,53 @@ public final class JetManager extends Manager implements JingleDescriptionManage
return offer; return offer;
} }
/**
* Register an {@link JingleEnvelopeManager}
* @param method manager.
*/
public void registerEnvelopeManager(JingleEnvelopeManager method) { public void registerEnvelopeManager(JingleEnvelopeManager method) {
envelopeManagers.put(method.getJingleEnvelopeNamespace(), method); envelopeManagers.put(method.getJingleEnvelopeNamespace(), method);
} }
/**
* Unregister an {@link JingleEnvelopeManager}
* @param namespace namespace of the manager.
*/
public void unregisterEnvelopeManager(String namespace) { public void unregisterEnvelopeManager(String namespace) {
envelopeManagers.remove(namespace); envelopeManagers.remove(namespace);
} }
/**
* Return an {@link JingleEnvelopeManager} for the given namespace.
* @param namespace namespace.
* @return manager or null.
*/
public JingleEnvelopeManager getEnvelopeManager(String namespace) { public JingleEnvelopeManager getEnvelopeManager(String namespace) {
return envelopeManagers.get(namespace); return envelopeManagers.get(namespace);
} }
/**
* Register an {@link ExtensionElementProvider} for an envelope element.
* @param namespace namespace.
* @param provider provider.
*/
public static void registerEnvelopeProvider(String namespace, ExtensionElementProvider<?> provider) { public static void registerEnvelopeProvider(String namespace, ExtensionElementProvider<?> provider) {
envelopeProviders.put(namespace, provider); envelopeProviders.put(namespace, provider);
} }
/**
* Unregister an {@link ExtensionElementProvider} for an envelope element.
* @param namespace namespace.
*/
public static void unregisterEnvelopeProvider(String namespace) { public static void unregisterEnvelopeProvider(String namespace) {
envelopeProviders.remove(namespace); envelopeProviders.remove(namespace);
} }
/**
* Return an {@link ExtensionElementProvider} for an envelope element with the given namespace.
* @param namespace namespace.
* @return provider.
*/
public static ExtensionElementProvider<?> getEnvelopeProvider(String namespace) { public static ExtensionElementProvider<?> getEnvelopeProvider(String namespace) {
return envelopeProviders.get(namespace); return envelopeProviders.get(namespace);
} }
@ -179,6 +240,15 @@ public final class JetManager extends Manager implements JingleDescriptionManage
JingleFileTransferManager.getInstanceFor(connection()).notifyContentAdd(session, content); JingleFileTransferManager.getInstanceFor(connection()).notifyContentAdd(session, content);
} }
/**
* Throw a {@link org.jivesoftware.smack.SmackException.FeatureNotSupportedException} when recipient doesn't support JET.
* @param recipient recipient.
* @throws XMPPException.XMPPErrorException
* @throws SmackException.NotConnectedException
* @throws InterruptedException
* @throws SmackException.NoResponseException
* @throws SmackException.FeatureNotSupportedException
*/
private void throwIfRecipientLacksSupport(FullJid recipient) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, SmackException.FeatureNotSupportedException { private void throwIfRecipientLacksSupport(FullJid recipient) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, SmackException.FeatureNotSupportedException {
if (!ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(recipient, getNamespace())) { if (!ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(recipient, getNamespace())) {
throw new SmackException.FeatureNotSupportedException(getNamespace(), recipient); throw new SmackException.FeatureNotSupportedException(getNamespace(), recipient);

View File

@ -21,6 +21,9 @@ import org.jivesoftware.smackx.jet.element.JetSecurityElement;
import org.jivesoftware.smackx.jingle.adapter.JingleSecurityAdapter; import org.jivesoftware.smackx.jingle.adapter.JingleSecurityAdapter;
import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement;
/**
* Adapter to parse JetSecurityElements into JetSecurity components.
*/
public class JetSecurityAdapter implements JingleSecurityAdapter<JetSecurity> { public class JetSecurityAdapter implements JingleSecurityAdapter<JetSecurity> {
@Override @Override

View File

@ -26,18 +26,44 @@ import org.jivesoftware.smack.packet.ExtensionElement;
import org.jxmpp.jid.FullJid; import org.jxmpp.jid.FullJid;
/** /**
* Classes that implement this interface can be used to encrypt Jingle File Transfers. * Interface that provides methods that need to be implemented by potential JingleEnvelopeManagers.
* An JingleEnvelopeManager can be used to secure a JET encrypted Transport.
*/ */
public interface JingleEnvelopeManager { public interface JingleEnvelopeManager {
/**
* Encrypt a serialized encryption key (Transport Secret) and return the resulting {@link ExtensionElement} (Envelope).
* @param recipient recipient of the transfer.
* @param keyData Serialized key. This is referred to in the XEP as Transport Secret.
* @return encrypted Transport Secret as Envelope element.
* @throws JingleEncryptionException JET encryption fails.
* @throws InterruptedException
* @throws NoSuchAlgorithmException
* @throws SmackException.NotConnectedException
* @throws SmackException.NoResponseException
*/
ExtensionElement encryptJingleTransfer(FullJid recipient, byte[] keyData) ExtensionElement encryptJingleTransfer(FullJid recipient, byte[] keyData)
throws JingleEncryptionException, InterruptedException, NoSuchAlgorithmException, throws JingleEncryptionException, InterruptedException, NoSuchAlgorithmException,
SmackException.NotConnectedException, SmackException.NoResponseException; SmackException.NotConnectedException, SmackException.NoResponseException;
/**
* Decrypt a serialized encryption key (Transport Secret) from an {@link ExtensionElement} (Envelope).
* @param sender sender of the Envelope.
* @param envelope encrypted key as Envelope element.
* @return decrypted Transport Secret.
* @throws JingleEncryptionException JET encryption fails.
* @throws InterruptedException
* @throws XMPPException.XMPPErrorException
* @throws SmackException.NotConnectedException
* @throws SmackException.NoResponseException
*/
byte[] decryptJingleTransfer(FullJid sender, ExtensionElement envelope) byte[] decryptJingleTransfer(FullJid sender, ExtensionElement envelope)
throws JingleEncryptionException, InterruptedException, XMPPException.XMPPErrorException, throws JingleEncryptionException, InterruptedException, XMPPException.XMPPErrorException,
SmackException.NotConnectedException, SmackException.NoResponseException; SmackException.NotConnectedException, SmackException.NoResponseException;
/**
* Exception that wraps possible exceptions that might occur during encryption/decryption.
*/
class JingleEncryptionException extends Exception { class JingleEncryptionException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -46,7 +72,15 @@ public interface JingleEnvelopeManager {
} }
} }
/**
* Return the connection of the manager.
* @return connection.
*/
XMPPConnection getConnection(); XMPPConnection getConnection();
/**
* Return the namespace of the Envelope method.
* @return namespace.
*/
String getJingleEnvelopeNamespace(); String getJingleEnvelopeNamespace();
} }

View File

@ -41,7 +41,8 @@ import org.jivesoftware.smackx.jingle.element.JingleElement;
import org.jxmpp.jid.FullJid; import org.jxmpp.jid.FullJid;
/** /**
* Created by vanitas on 22.07.17. * JetSecurity security component for Jingle Encrypted Transports.
* @see <a href="https://geekplace.eu/xeps/xep-jet/xep-jet.html">Proto-XEP</a>
*/ */
public class JetSecurity extends JingleSecurity<JetSecurityElement> { public class JetSecurity extends JingleSecurity<JetSecurityElement> {
private static final Logger LOGGER = Logger.getLogger(JetSecurity.class.getName()); private static final Logger LOGGER = Logger.getLogger(JetSecurity.class.getName());

View File

@ -26,6 +26,10 @@ import javax.crypto.CipherOutputStream;
import org.jivesoftware.smackx.bytestreams.BytestreamSession; import org.jivesoftware.smackx.bytestreams.BytestreamSession;
import org.jivesoftware.smackx.jingle.component.JingleSecurityBytestreamSession; import org.jivesoftware.smackx.jingle.component.JingleSecurityBytestreamSession;
/**
* Wrapper that wraps a the {@link InputStream} and {@link OutputStream} of a {@link BytestreamSession} into a
* {@link CipherInputStream} and {@link CipherOutputStream}.
*/
public class JetSecurityBytestreamSession extends JingleSecurityBytestreamSession { public class JetSecurityBytestreamSession extends JingleSecurityBytestreamSession {
private final Cipher cipher; private final Cipher cipher;

View File

@ -16,7 +16,8 @@
*/ */
/** /**
* Smack's API for XEP-XXXX: Jingle Encrypted Transfers</a>. * Smack's API for XEP-XXXX: Jingle Encrypted Transports
* @see <a href="https://geekplace.eu/xeps/xep-jet/xep-jet.html">Proto-XEP</a>
* Internal classes. * Internal classes.
*/ */
package org.jivesoftware.smackx.jet.component; package org.jivesoftware.smackx.jet.component;

View File

@ -22,7 +22,7 @@ import org.jivesoftware.smackx.jet.component.JetSecurity;
import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement;
/** /**
* Implementation of the Jingle security element as specified in XEP-XXXX (Jingle Encrypted Transfers). * Implementation of the Jingle security element as specified in XEP-XXXX (Jingle Encrypted Transports).
* <jingle> * <jingle>
* <content> * <content>
* <description/> * <description/>
@ -30,6 +30,7 @@ import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement;
* <security/> <- You are here. * <security/> <- You are here.
* </content> * </content>
* </jingle> * </jingle>
* @see <a href="https://geekplace.eu/xeps/xep-jet/xep-jet.html">Proto-XEP</a>
*/ */
public class JetSecurityElement extends JingleContentSecurityElement { public class JetSecurityElement extends JingleContentSecurityElement {
public static final String ATTR_CONTENT_NAME = "name"; public static final String ATTR_CONTENT_NAME = "name";

View File

@ -16,7 +16,8 @@
*/ */
/** /**
* Smack's API for XEP-XXXX: Jingle Encrypted Transfers</a>. * Smack's API for XEP-XXXX: Jingle Encrypted Transports
* @see <a href="https://geekplace.eu/xeps/xep-jet/xep-jet.html">Proto-XEP</a>
* Elements. * Elements.
*/ */
package org.jivesoftware.smackx.jet.element; package org.jivesoftware.smackx.jet.element;

View File

@ -16,6 +16,7 @@
*/ */
/** /**
* Smack's API for XEP-XXXX: Jingle Encrypted Transfers</a>. * Smack's API for XEP-XXXX: Jingle Encrypted Transports.
* @see <a href="https://geekplace.eu/xeps/xep-jet/xep-jet.html">Proto-XEP</a>
*/ */
package org.jivesoftware.smackx.jet; package org.jivesoftware.smackx.jet;