diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/httpfileupload/HttpFileUploadManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/httpfileupload/HttpFileUploadManager.java
index 1da12a5759..87cb00b576 100644
--- a/smack-experimental/src/main/java/org/jivesoftware/smackx/httpfileupload/HttpFileUploadManager.java
+++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/httpfileupload/HttpFileUploadManager.java
@@ -55,6 +55,7 @@
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
@@ -69,11 +70,13 @@
/**
* A manager for XEP-0363: HTTP File Upload.
+ * This manager is also capable of XEP-XXXX: OMEMO Media Sharing.
*
* @author Grigory Fedorov
* @author Florian Schmaus
* @author Paul Schaub
* @see XEP-0363: HTTP File Upload
+ * @see XEP-XXXX: OMEMO Media Sharing
*/
public final class HttpFileUploadManager extends Manager {
@@ -92,6 +95,7 @@ public final class HttpFileUploadManager extends Manager {
public static final String NAMESPACE_0_2 = "urn:xmpp:http:upload";
private static final Logger LOGGER = Logger.getLogger(HttpFileUploadManager.class.getName());
+ private static final SecureRandom SECURE_RANDOM = new SecureRandom();
static {
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
@@ -282,21 +286,21 @@ public URL uploadFile(File file, UploadProgressListener listener) throws Interru
* Upload a file encrypted using the scheme described in OMEMO Media Sharing.
* The file is being encrypted using a random 256 bit AES key in Galois Counter Mode using a random 16 byte IV and
* then uploaded to the server.
- * The URL that is returned has a modified scheme (aesgcm:// instead of http(s)://) and has the IV and key attached
+ * The URL that is returned has a modified scheme (aesgcm:// instead of https://) and has the IV and key attached
* as ref part.
*
* Note: The URL contains the used key and IV in plain text. Keep in mind to only share this URL though a secured
* channel (i.e. end-to-end encrypted message), as anybody who can read the URL can also decrypt the file.
*
* Note: This method uses a IV of length 16 instead of 12. Although not specified in the ProtoXEP, 16 byte IVs are
- * currently used by most implementations. {@link #decryptionCipherForEncryptedFile(String)} also supports 12 byte IVs.
+ * currently used by most implementations. This implementation also supports 12 byte IVs when decrypting.
*
* @param file file
* @return AESGCM URL which contains the key and IV of the encrypted file.
*
* @see XEP-XXXX: OMEMO Media Sharing
*/
- public String uploadFileEncrypted(File file) throws InterruptedException, IOException,
+ public AesgcmUrl uploadFileEncrypted(File file) throws InterruptedException, IOException,
XMPPException.XMPPErrorException, SmackException, InvalidAlgorithmParameterException,
NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException {
return uploadFileEncrypted(file, null);
@@ -305,14 +309,14 @@ public String uploadFileEncrypted(File file) throws InterruptedException, IOExce
* Upload a file encrypted using the scheme described in OMEMO Media Sharing.
* The file is being encrypted using a random 256 bit AES key in Galois Counter Mode using a random 16 byte IV and
* then uploaded to the server.
- * The URL that is returned has a modified scheme (aesgcm:// instead of http(s)://) and has the IV and key attached
+ * The URL that is returned has a modified scheme (aesgcm:// instead of https://) and has the IV and key attached
* as ref part.
*
* Note: The URL contains the used key and IV in plain text. Keep in mind to only share this URL though a secured
* channel (i.e. end-to-end encrypted message), as anybody who can read the URL can also decrypt the file.
*
* Note: This method uses a IV of length 16 instead of 12. Although not specified in the ProtoXEP, 16 byte IVs are
- * currently used by most implementations. {@link #decryptionCipherForEncryptedFile(String)} also supports 12 byte IVs.
+ * currently used by most implementations. This implementation also supports 12 byte IVs when decrypting.
*
* @param file file
* @param listener progress listener or null
@@ -320,102 +324,31 @@ public String uploadFileEncrypted(File file) throws InterruptedException, IOExce
*
* @see XEP-XXXX: OMEMO Media Sharing
*/
- public String uploadFileEncrypted(File file, UploadProgressListener listener) throws IOException,
+ public AesgcmUrl uploadFileEncrypted(File file, UploadProgressListener listener) throws IOException,
InterruptedException, XMPPException.XMPPErrorException, SmackException, NoSuchPaddingException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
if (!file.isFile()) {
throw new FileNotFoundException("The path " + file.getAbsolutePath() + " is not a file");
}
+ // The encrypted file will contain an extra block with the AEAD MAC.
long cipherFileLength = file.length() + 16;
final Slot slot = requestSlot(file.getName(), cipherFileLength, "application/octet-stream");
URL slotUrl = slot.getGetUrl();
- // fresh AES key
- OmemoMediaSharing.Key key = OmemoMediaSharing.generateKey();
+ // fresh AES key + iv
+ byte[] key = OmemoMediaSharingUtils.generateRandomKey();
+ byte[] iv = OmemoMediaSharingUtils.generateRandomIV();
+ Cipher cipher = OmemoMediaSharingUtils.encryptionCipherFrom(key, iv);
FileInputStream fis = new FileInputStream(file);
- // encrypt the file on the fly
- CipherInputStream cis = new CipherInputStream(fis, key.cipher);
+ // encrypt the file on the fly - encryption actually happens below in uploadFile()
+ CipherInputStream cis = new CipherInputStream(fis, cipher);
uploadFile(cis, cipherFileLength, slot, listener);
- // set URL scheme to aesgcm:// and append IV + KEY
- return slotUrl.toString().replaceFirst(slotUrl.getProtocol(), "aesgcm")
- + "#" + key.getHexIv() + key.getHexKey();
- }
-
- /**
- * Parse encryption key parameters from an aesgcm-URL and return a {@link Cipher} which can be used to decrypt the
- * file to which the URL points to.
- *
- * @param aesgcmUrl url string that has a protocol of "aesgcm".
- * @return {@link Cipher} that can be used to decrypt the file.
- *
- * @throws InvalidAlgorithmParameterException
- * @throws NoSuchAlgorithmException
- * @throws InvalidKeyException
- * @throws NoSuchPaddingException
- */
- public static Cipher decryptionCipherForEncryptedFile(String aesgcmUrl) throws InvalidAlgorithmParameterException,
- NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException {
-
- if (!aesgcmUrl.startsWith("aesgcm://")) {
- throw new IllegalArgumentException("The provided URL does not appear to belong to a file which was " +
- "uploaded using OMEMO Media Sharing.");
- }
-
- String ref;
- try {
- ref = aesgcmUrl.substring(aesgcmUrl.lastIndexOf("#") + 1);
- } catch (StringIndexOutOfBoundsException e) {
- ref = null;
- }
-
- if (ref == null || ref.length() == 0) {
- throw new IllegalArgumentException("The provided URL does not have a ref part, which normally includes " +
- "the key and initialization vector for file encryption.");
- }
-
- byte[] refBytes = OmemoMediaSharing.hexStringToByteArray(ref);
-
- byte[] key = new byte[32];
- byte[] iv;
- int ivLen;
- // determine the length of the initialization vector part
- switch (refBytes.length) {
- // 32 bytes key + 16 bytes IV
- case 48:
- ivLen = 16;
- break;
-
- // 32 bytes key + 12 bytes IV
- case 44:
- ivLen = 12;
- break;
- default:
- throw new IllegalArgumentException("Provided URL has an invalid ref tag.");
- }
- iv = new byte[ivLen];
- System.arraycopy(refBytes, 0, iv, 0, ivLen);
- System.arraycopy(refBytes, ivLen, key, 0, 32);
-
- return new OmemoMediaSharing.Key(key, iv, OmemoMediaSharing.KEYTYPE, OmemoMediaSharing.CIPHERMODE, false).cipher;
- }
-
- public static URL httpUrlFromAesgcmUrl(String aesgcmUrl) {
- final String aesgcmProto = "aesgcm";
- if (!aesgcmUrl.startsWith(aesgcmProto)) {
- throw new IllegalArgumentException("Provided URL is not a aesgcm URL.");
- }
-
- String httpUrl = aesgcmUrl.replaceFirst(aesgcmProto, "https");
- try {
- return new URL(httpUrl);
- } catch (MalformedURLException e) {
- throw new AssertionError("Failed to convert aesgcm URL to http URL.");
- }
+ return new AesgcmUrl(slotUrl, key, iv);
}
/**
@@ -647,12 +580,24 @@ private static boolean containsHttpFileUploadNamespace(DiscoverInfo discoverInfo
return discoverInfo.containsFeature(NAMESPACE) || discoverInfo.containsFeature(NAMESPACE_0_2);
}
+ /**
+ * Generate a securely random byte array.
+ *
+ * @param len length of the byte array
+ * @return byte array
+ */
+ private static byte[] secureRandomBytes(int len) {
+ byte[] bytes = new byte[len];
+ SECURE_RANDOM.nextBytes(bytes);
+ return bytes;
+ }
+
/**
* Utility code for XEP-XXXX: OMEMO Media Sharing.
*
* @see XEP-XXXX: OMEMO Media Sharing
*/
- private static class OmemoMediaSharing {
+ static class OmemoMediaSharingUtils {
private static final String KEYTYPE = "AES";
private static final String CIPHERMODE = "AES/GCM/NoPadding";
@@ -666,91 +611,202 @@ private static class OmemoMediaSharing {
// At some point we should switch to 12 bytes though.
private static final int LEN_IV = LEN_IV_16;
- private static final SecureRandom RANDOM = new SecureRandom();
+ static byte[] generateRandomIV() {
+ return generateRandomIV(LEN_IV);
+ }
+
+ static byte[] generateRandomIV(int len) {
+ return secureRandomBytes(len);
+ }
+
+ /**
+ * Generate a random 256 bit AES key.
+ *
+ * @return encoded AES key
+ * @throws NoSuchAlgorithmException if the JVM doesn't provide the given key type.
+ */
+ static byte[] generateRandomKey() throws NoSuchAlgorithmException {
+ KeyGenerator generator = KeyGenerator.getInstance(KEYTYPE);
+ generator.init(LEN_KEY_BITS);
+ return generator.generateKey().getEncoded();
+ }
+
+ /**
+ * Create a {@link Cipher} from a given key and iv which is in encryption mode.
+ *
+ * @param key aes encryption key
+ * @param iv initialization vector
+ *
+ * @return cipher in encryption mode
+ *
+ * @throws NoSuchPaddingException if the JVM doesn't provide the padding specified in the ciphermode.
+ * @throws NoSuchAlgorithmException if the JVM doesn't provide the encryption method specified in the ciphermode.
+ * @throws InvalidAlgorithmParameterException if the cipher cannot be initiated.
+ * @throws InvalidKeyException if the key is invalid.
+ */
+ private static Cipher encryptionCipherFrom(byte[] key, byte[] iv)
+ throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
+ InvalidKeyException {
+ SecretKey secretKey = new SecretKeySpec(key, KEYTYPE);
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ Cipher cipher = Cipher.getInstance(CIPHERMODE);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
+ return cipher;
+ }
+
+ /**
+ * Create a {@link Cipher} from a given key and iv which is in decryption mode.
+ *
+ * @param key aes encryption key
+ * @param iv initialization vector
+ *
+ * @return cipher in decryption mode
+ *
+ * @throws NoSuchPaddingException if the JVM doesn't provide the padding specified in the ciphermode.
+ * @throws NoSuchAlgorithmException if the JVM doesn't provide the encryption method specified in the ciphermode.
+ * @throws InvalidAlgorithmParameterException if the cipher cannot be initiated.
+ * @throws InvalidKeyException if the key is invalid.
+ */
+ private static Cipher decryptionCipherFrom(byte[] key, byte[] iv)
+ throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
+ InvalidKeyException {
+ SecretKey secretKey = new SecretKeySpec(key, KEYTYPE);
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ Cipher cipher = Cipher.getInstance(CIPHERMODE);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
+ return cipher;
+ }
+ }
+
+ /**
+ * This class represents a aesgcm URL as described in XEP-XXXX: OMEMO Media Sharing.
+ * As the builtin {@link URL} class cannot handle the aesgcm protocol identifier, this class
+ * is used as a utility class that bundles together a {@link URL}, key and IV.
+ *
+ * @see XEP-XXXX: OMEMO Media Sharing
+ */
+ public static class AesgcmUrl {
+
+ public static final String PROTOCOL = "aesgcm";
+
+ private final URL httpsUrl;
+ private final byte[] keyBytes;
+ private final byte[] ivBytes;
/**
- * Generate a securely random byte array.
+ * Private constructor that constructs the {@link AesgcmUrl} from a normal https {@link URL}, a key and iv.
*
- * @param len length of the byte array
- * @return byte array
+ * @param httpsUrl normal https url as given by the {@link Slot}.
+ * @param key byte array of an encoded 256 bit aes key
+ * @param iv 16 or 12 byte initialization vector
*/
- private static byte[] secureRandomBytes(int len) {
- byte[] bytes = new byte[len];
- OmemoMediaSharing.RANDOM.nextBytes(bytes);
- return bytes;
+ AesgcmUrl(URL httpsUrl, byte[] key, byte[] iv) {
+ this.httpsUrl = Objects.requireNonNull(httpsUrl);
+ this.keyBytes = Objects.requireNonNull(key);
+ this.ivBytes = Objects.requireNonNull(iv);
}
/**
- * Convert a hexadecimal String to bytes.
- * Stolen from https://stackoverflow.com/a/140861/11150851
+ * Parse a {@link AesgcmUrl} from a {@link String}.
+ * The parsed object will provide a normal {@link URL} under which the offered file can be downloaded,
+ * as well as a {@link Cipher} that can be used to decrypt it.
*
- * @param s hex string
- * @return byte array
+ * @param aesgcmUrlString aesgcm URL as a {@link String}
*/
- private static byte[] hexStringToByteArray(String s) {
- int len = s.length();
- byte[] data = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
- + Character.digit(s.charAt(i + 1), 16));
+ public AesgcmUrl(String aesgcmUrlString) {
+ if (!aesgcmUrlString.startsWith(PROTOCOL)) {
+ throw new IllegalArgumentException("Provided String does not resemble a aesgcm URL.");
}
- return data;
+
+ // Convert aesgcm Url to https URL
+ this.httpsUrl = extractHttpsUrl(aesgcmUrlString);
+
+ // Extract IV and Key
+ byte[][] ivAndKey = extractIVAndKey(aesgcmUrlString);
+ this.ivBytes = ivAndKey[0];
+ this.keyBytes = ivAndKey[1];
}
/**
- * Generate a {@link Key} which consists of the encryption key encoded as bytes, the initialization vector
- * as bytes, as well as a {@link Cipher} which was created using the key and IV with {@link #KEYTYPE}
- * and {@link #CIPHERMODE}.
+ * Return a https {@link URL} under which the file can be downloaded.
*
- * @return key
- * @throws InvalidAlgorithmParameterException in case the encryption parameters are invalid
- * @throws NoSuchAlgorithmException if the JVM lacks support for the used cipher
- * @throws InvalidKeyException if the key is invalid
- * @throws NoSuchPaddingException if there is no such specified padding
+ * @return https URL
*/
- static Key generateKey()
- throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, InvalidKeyException,
- NoSuchPaddingException {
- KeyGenerator generator = KeyGenerator.getInstance(KEYTYPE);
- generator.init(LEN_KEY_BITS);
- byte[] keyBytes = generator.generateKey().getEncoded();
- return new Key(keyBytes, secureRandomBytes(LEN_IV), KEYTYPE, CIPHERMODE, true);
+ public URL getDownloadUrl() {
+ return httpsUrl;
+ }
+
+ /**
+ * Returns the {@link String} representation of this aesgcm URL.
+ *
+ * @return aesgcm URL with key and IV.
+ */
+ public String getAesgcmUrl() {
+ String aesgcmUrl = httpsUrl.toString().replaceFirst(httpsUrl.getProtocol(), PROTOCOL);
+ return aesgcmUrl + "#" + StringUtils.encodeHex(ivBytes) + StringUtils.encodeHex(keyBytes);
}
- private static class Key {
-
- private final byte[] key;
- private final byte[] iv;
- private final Cipher cipher;
-
- Key(byte[] key, byte[] iv, String keyType, String cipherMode, boolean encryptMode)
- throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException,
- InvalidKeyException {
- this.key = key;
- this.iv = iv;
- SecretKey secretKey = new SecretKeySpec(key, keyType);
- IvParameterSpec ivSpec = new IvParameterSpec(iv);
- this.cipher = Cipher.getInstance(cipherMode);
- cipher.init(encryptMode ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, secretKey, ivSpec);
+ /**
+ * Returns a {@link Cipher} in decryption mode, which can be used to decrypt the offered file.
+ *
+ * @return cipher
+ *
+ * @throws NoSuchPaddingException if the JVM cannot provide the specified cipher mode
+ * @throws NoSuchAlgorithmException if the JVM cannot provide the specified cipher mode
+ * @throws InvalidAlgorithmParameterException if the JVM cannot provide the specified cipher
+ * (eg. if no BC provider is added)
+ * @throws InvalidKeyException if the provided key is invalid
+ */
+ public Cipher getDecryptionCipher() throws NoSuchPaddingException, NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException, InvalidKeyException {
+ return OmemoMediaSharingUtils.decryptionCipherFrom(keyBytes, ivBytes);
+ }
+
+ private static URL extractHttpsUrl(String aesgcmUrlString) {
+ // aesgcm -> https
+ String httpsUrlString = aesgcmUrlString.replaceFirst(PROTOCOL, "https");
+ // remove #ref
+ httpsUrlString = httpsUrlString.substring(0, httpsUrlString.indexOf("#"));
+
+ try {
+ return new URL(httpsUrlString);
+ } catch (MalformedURLException e) {
+ throw new AssertionError("Failed to convert aesgcm URL to https URL: '" + aesgcmUrlString + "'", e);
}
+ }
- /**
- * Return the key encoded as hexadecimal digits.
- *
- * @return key in hex
- */
- String getHexKey() {
- return StringUtils.encodeHex(key);
+ private static byte[][] extractIVAndKey(String aesgcmUrlString) {
+ int startOfRef = aesgcmUrlString.lastIndexOf("#");
+ if (startOfRef == -1) {
+ throw new IllegalArgumentException("The provided aesgcm Url does not have a ref part which is " +
+ "supposed to contain the encryption key for file encryption.");
}
- /**
- * Return the IV encoded as hexadecimal digits.
- *
- * @return IV in hex
- */
- String getHexIv() {
- return StringUtils.encodeHex(iv);
+ String ref = aesgcmUrlString.substring(startOfRef + 1);
+ byte[] refBytes = StringUtils.hexStringToByteArray(ref);
+
+ byte[] key = new byte[32];
+ byte[] iv;
+ int ivLen;
+ // determine the length of the initialization vector part
+ switch (refBytes.length) {
+ // 32 bytes key + 16 bytes IV
+ case 48:
+ ivLen = 16;
+ break;
+
+ // 32 bytes key + 12 bytes IV
+ case 44:
+ ivLen = 12;
+ break;
+ default:
+ throw new IllegalArgumentException("Provided URL has an invalid ref tag (" + ref.length() + "): '" + ref + "'");
}
+ iv = new byte[ivLen];
+ System.arraycopy(refBytes, 0, iv, 0, ivLen);
+ System.arraycopy(refBytes, ivLen, key, 0, 32);
+
+ return new byte[][] {iv,key};
}
}
}
diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/httpfileupload/OmemoMediaSharingUtilsTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/httpfileupload/OmemoMediaSharingUtilsTest.java
new file mode 100644
index 0000000000..335704f3c4
--- /dev/null
+++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/httpfileupload/OmemoMediaSharingUtilsTest.java
@@ -0,0 +1,70 @@
+/**
+ *
+ * Copyright © 2019 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.httpfileupload;
+
+import static junit.framework.TestCase.assertEquals;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.jivesoftware.smack.util.StringUtils;
+
+import org.junit.Test;
+
+public class OmemoMediaSharingUtilsTest {
+
+ private static final String iv_12 = "8c3d050e9386ec173861778f";
+ private static final String iv_16 = "1ad857dcbb119e2642e4f8f7c137819e";
+ private static final String key = "4f15af8f1a28100d0101fb1c2e119b0c18c34396c68ad379f5912ee21dca6b0b";
+ private static final String key_iv_12 = iv_12 + key;
+ private static final String key_iv_16 = iv_16 + key;
+
+ private static final String file = "download.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/tr%C3%A8s%20cool.jpg";
+ private static final String file_https = "https://" + file;
+ private static final String file_aesgcm_12 = "aesgcm://" + file + "#" + key_iv_12;
+ private static final String file_aesgcm_16 = "aesgcm://" + file + "#" + key_iv_16;
+
+ @Test
+ public void test12byteIvVariant() throws MalformedURLException {
+ HttpFileUploadManager.AesgcmUrl aesgcm = new HttpFileUploadManager.AesgcmUrl(file_aesgcm_12);
+
+ // Make sure, that parsed aesgcm url still equals input string
+ assertEquals(file_aesgcm_12, aesgcm.getAesgcmUrl());
+ assertEquals(file_https, aesgcm.getDownloadUrl().toString());
+
+ URL url = new URL(file_https);
+ aesgcm = new HttpFileUploadManager.AesgcmUrl(url, StringUtils.hexStringToByteArray(key),
+ StringUtils.hexStringToByteArray(iv_12));
+ assertEquals(file_aesgcm_12, aesgcm.getAesgcmUrl());
+ assertEquals(file_https, aesgcm.getDownloadUrl().toString());
+ }
+
+ @Test
+ public void test16byteIvVariant() throws MalformedURLException {
+ HttpFileUploadManager.AesgcmUrl aesgcm = new HttpFileUploadManager.AesgcmUrl(file_aesgcm_16);
+
+ // Make sure, that parsed aesgcm url still equals input string
+ assertEquals(file_aesgcm_16, aesgcm.getAesgcmUrl());
+ assertEquals(file_https, aesgcm.getDownloadUrl().toString());
+
+ URL url = new URL(file_https);
+ aesgcm = new HttpFileUploadManager.AesgcmUrl(url, StringUtils.hexStringToByteArray(key),
+ StringUtils.hexStringToByteArray(iv_16));
+ assertEquals(file_aesgcm_16, aesgcm.getAesgcmUrl());
+ assertEquals(file_https, aesgcm.getDownloadUrl().toString());
+ }
+}
diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/httpfileupload/HttpFileUploadIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/httpfileupload/HttpFileUploadIntegrationTest.java
index 7ec883df63..96673d0c13 100644
--- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/httpfileupload/HttpFileUploadIntegrationTest.java
+++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/httpfileupload/HttpFileUploadIntegrationTest.java
@@ -131,7 +131,7 @@ public void omemoMediaSharingTest() throws IOException, NoSuchPaddingException,
fos.close();
}
- String aesgcmUrl = hfumOne.uploadFileEncrypted(file, new UploadProgressListener() {
+ HttpFileUploadManager.AesgcmUrl aesgcmUrl = hfumOne.uploadFileEncrypted(file, new UploadProgressListener() {
@Override
public void onUploadProgress(long uploadedBytes, long totalBytes) {
double progress = uploadedBytes / totalBytes;
@@ -139,10 +139,10 @@ public void onUploadProgress(long uploadedBytes, long totalBytes) {
}
});
- URL httpUrl = HttpFileUploadManager.httpUrlFromAesgcmUrl(aesgcmUrl);
- Cipher decryptionCipher = HttpFileUploadManager.decryptionCipherForEncryptedFile(aesgcmUrl);
+ URL httpsUrl = aesgcmUrl.getDownloadUrl();
+ Cipher decryptionCipher = aesgcmUrl.getDecryptionCipher();
- HttpURLConnection urlConnection = getHttpUrlConnectionFor(httpUrl);
+ HttpURLConnection urlConnection = getHttpUrlConnectionFor(httpsUrl);
ByteArrayOutputStream baos = new ByteArrayOutputStream(fileSize);
byte[] buffer = new byte[4096];