diff --git a/bin/main/icu/jnet/whatsjava/Main$1.class b/bin/main/icu/jnet/whatsjava/Main$1.class index 0385d80..787a21e 100644 Binary files a/bin/main/icu/jnet/whatsjava/Main$1.class and b/bin/main/icu/jnet/whatsjava/Main$1.class differ diff --git a/bin/main/icu/jnet/whatsjava/Main.class b/bin/main/icu/jnet/whatsjava/Main.class index e2c0652..629165d 100644 Binary files a/bin/main/icu/jnet/whatsjava/Main.class and b/bin/main/icu/jnet/whatsjava/Main.class differ diff --git a/bin/main/icu/jnet/whatsjava/encryption/AES.class b/bin/main/icu/jnet/whatsjava/encryption/AES.class index 1d037d8..9eca3ee 100644 Binary files a/bin/main/icu/jnet/whatsjava/encryption/AES.class and b/bin/main/icu/jnet/whatsjava/encryption/AES.class differ diff --git a/bin/main/icu/jnet/whatsjava/encryption/BinaryDecoder.class b/bin/main/icu/jnet/whatsjava/encryption/BinaryDecoder.class index 82e4640..4efc824 100644 Binary files a/bin/main/icu/jnet/whatsjava/encryption/BinaryDecoder.class and b/bin/main/icu/jnet/whatsjava/encryption/BinaryDecoder.class differ diff --git a/bin/main/icu/jnet/whatsjava/encryption/BinaryEncryption.class b/bin/main/icu/jnet/whatsjava/encryption/BinaryEncryption.class index c19512d..6285769 100644 Binary files a/bin/main/icu/jnet/whatsjava/encryption/BinaryEncryption.class and b/bin/main/icu/jnet/whatsjava/encryption/BinaryEncryption.class differ diff --git a/bin/main/icu/jnet/whatsjava/encryption/EncryptionKeys.class b/bin/main/icu/jnet/whatsjava/encryption/EncryptionKeys.class index 7b411ff..ebcbb8f 100644 Binary files a/bin/main/icu/jnet/whatsjava/encryption/EncryptionKeys.class and b/bin/main/icu/jnet/whatsjava/encryption/EncryptionKeys.class differ diff --git a/bin/main/icu/jnet/whatsjava/encryption/MediaEncryption.class b/bin/main/icu/jnet/whatsjava/encryption/MediaEncryption.class new file mode 100644 index 0000000..42696ea Binary files /dev/null and b/bin/main/icu/jnet/whatsjava/encryption/MediaEncryption.class differ diff --git a/bin/main/icu/jnet/whatsjava/helper/Utils.class b/bin/main/icu/jnet/whatsjava/helper/Utils.class index bc1883b..4b8ae1b 100644 Binary files a/bin/main/icu/jnet/whatsjava/helper/Utils.class and b/bin/main/icu/jnet/whatsjava/helper/Utils.class differ diff --git a/bin/main/icu/jnet/whatsjava/web/WebConversationMessage.class b/bin/main/icu/jnet/whatsjava/web/WebConversationMessage.class index dfa7253..8a46a0c 100644 Binary files a/bin/main/icu/jnet/whatsjava/web/WebConversationMessage.class and b/bin/main/icu/jnet/whatsjava/web/WebConversationMessage.class differ diff --git a/bin/main/icu/jnet/whatsjava/web/WebImageMessage.class b/bin/main/icu/jnet/whatsjava/web/WebImageMessage.class index 14b1a7a..ddf4301 100644 Binary files a/bin/main/icu/jnet/whatsjava/web/WebImageMessage.class and b/bin/main/icu/jnet/whatsjava/web/WebImageMessage.class differ diff --git a/bin/main/icu/jnet/whatsjava/web/WebVideoMessage.class b/bin/main/icu/jnet/whatsjava/web/WebVideoMessage.class index b310f63..15dc596 100644 Binary files a/bin/main/icu/jnet/whatsjava/web/WebVideoMessage.class and b/bin/main/icu/jnet/whatsjava/web/WebVideoMessage.class differ diff --git a/build.gradle b/build.gradle index 753b087..d414b99 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,9 @@ dependencies { // https://mvnrepository.com/artifact/commons-codec/commons-codec compile group: 'commons-codec', name: 'commons-codec', version: '1.14' + // https://mvnrepository.com/artifact/commons-io/commons-io + compile group: 'commons-io', name: 'commons-io', version: '2.7' + // https://mvnrepository.com/artifact/org.whispersystems/curve25519-java compile group: 'org.whispersystems', name: 'curve25519-java', version: '0.5.0' diff --git a/build/classes/java/main/icu/jnet/whatsjava/Main$1.class b/build/classes/java/main/icu/jnet/whatsjava/Main$1.class index ed462eb..39f209a 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/Main$1.class and b/build/classes/java/main/icu/jnet/whatsjava/Main$1.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/Main.class b/build/classes/java/main/icu/jnet/whatsjava/Main.class index 31e805c..9763378 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/Main.class and b/build/classes/java/main/icu/jnet/whatsjava/Main.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/encryption/AES.class b/build/classes/java/main/icu/jnet/whatsjava/encryption/AES.class index 119454f..cec770a 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/encryption/AES.class and b/build/classes/java/main/icu/jnet/whatsjava/encryption/AES.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/encryption/BinaryDecoder.class b/build/classes/java/main/icu/jnet/whatsjava/encryption/BinaryDecoder.class index 6dee5b8..f2db4b4 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/encryption/BinaryDecoder.class and b/build/classes/java/main/icu/jnet/whatsjava/encryption/BinaryDecoder.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/encryption/BinaryEncryption.class b/build/classes/java/main/icu/jnet/whatsjava/encryption/BinaryEncryption.class index e037be7..dc7eeb1 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/encryption/BinaryEncryption.class and b/build/classes/java/main/icu/jnet/whatsjava/encryption/BinaryEncryption.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/encryption/EncryptionKeys.class b/build/classes/java/main/icu/jnet/whatsjava/encryption/EncryptionKeys.class index 494bfea..bcc23c3 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/encryption/EncryptionKeys.class and b/build/classes/java/main/icu/jnet/whatsjava/encryption/EncryptionKeys.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/encryption/MediaEncryption.class b/build/classes/java/main/icu/jnet/whatsjava/encryption/MediaEncryption.class new file mode 100644 index 0000000..383f77c Binary files /dev/null and b/build/classes/java/main/icu/jnet/whatsjava/encryption/MediaEncryption.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/helper/Utils.class b/build/classes/java/main/icu/jnet/whatsjava/helper/Utils.class index 2c78fa4..2261271 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/helper/Utils.class and b/build/classes/java/main/icu/jnet/whatsjava/helper/Utils.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/web/WebImageMessage.class b/build/classes/java/main/icu/jnet/whatsjava/web/WebImageMessage.class index 64c932b..3c1e48a 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/web/WebImageMessage.class and b/build/classes/java/main/icu/jnet/whatsjava/web/WebImageMessage.class differ diff --git a/build/classes/java/main/icu/jnet/whatsjava/web/WebVideoMessage.class b/build/classes/java/main/icu/jnet/whatsjava/web/WebVideoMessage.class index a156118..288da43 100644 Binary files a/build/classes/java/main/icu/jnet/whatsjava/web/WebVideoMessage.class and b/build/classes/java/main/icu/jnet/whatsjava/web/WebVideoMessage.class differ diff --git a/build/libs/WhatsJava-all.jar b/build/libs/WhatsJava-all.jar index 2e6ad53..49b22bc 100644 Binary files a/build/libs/WhatsJava-all.jar and b/build/libs/WhatsJava-all.jar differ diff --git a/src/main/java/icu/jnet/whatsjava/Main.java b/src/main/java/icu/jnet/whatsjava/Main.java index 1f275ba..318a10a 100644 --- a/src/main/java/icu/jnet/whatsjava/Main.java +++ b/src/main/java/icu/jnet/whatsjava/Main.java @@ -3,15 +3,10 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.util.Base64; import javax.imageio.ImageIO; -import icu.jnet.whatsjava.helper.Utils; import icu.jnet.whatsjava.web.WebChat; -import icu.jnet.whatsjava.web.WebConversationMessage; -import icu.jnet.whatsjava.web.WebImageMessage; -import icu.jnet.whatsjava.web.WebVideoMessage; public class Main { diff --git a/src/main/java/icu/jnet/whatsjava/constants/ExpectedResponse.java b/src/main/java/icu/jnet/whatsjava/constants/ExpectedResponse.java index 34647bc..320f015 100644 --- a/src/main/java/icu/jnet/whatsjava/constants/ExpectedResponse.java +++ b/src/main/java/icu/jnet/whatsjava/constants/ExpectedResponse.java @@ -4,17 +4,11 @@ public class ExpectedResponse { // Excepted message type for the next message of the backend - public static final byte LOGIN = 0; - - public static final byte NEW_SERVER_ID = 1; - - public static final byte SCAN_QR_CODE = 2; - - public static final byte RESTORE_SESSION = 3; - - public static final byte RESOLVE_CHALLENGE = 4; - - public static final byte LOGGING_OUT = 5; - - public static final byte MESSAGE_GENERIC = 6; + public static final byte LOGIN = 0, + NEW_SERVER_ID = 1, + SCAN_QR_CODE = 2, + RESTORE_SESSION = 3, + RESOLVE_CHALLENGE = 4, + LOGGING_OUT = 5, + MESSAGE_GENERIC = 6; } diff --git a/src/main/java/icu/jnet/whatsjava/encryption/AES.java b/src/main/java/icu/jnet/whatsjava/encryption/AES.java index e4f69f4..4b2ecdd 100644 --- a/src/main/java/icu/jnet/whatsjava/encryption/AES.java +++ b/src/main/java/icu/jnet/whatsjava/encryption/AES.java @@ -31,7 +31,22 @@ static byte[] decrypt(byte[] encrypted, byte[] secretKey) { return null; } - // Encrypt it using AES and encKey + // Used for E2E media decryption in the MediaEncryption class + static byte[] decrypt(byte[] encrypted, byte[] secretKey, byte[] iv) { + try + { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); // PKCS5PADDING required + SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey, "AES"); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(iv)); + + return cipher.doFinal(encrypted); + } catch (Exception e) { + System.out.println("Error while decrypting: " + e.toString()); + } + return null; + } + + // Encrypt using AES and encKey static byte[] encrypt(byte[] decrypted, byte[] encKey) { try { diff --git a/src/main/java/icu/jnet/whatsjava/encryption/BinaryDecoder.java b/src/main/java/icu/jnet/whatsjava/encryption/BinaryDecoder.java index c9c6ef7..c2c3049 100644 --- a/src/main/java/icu/jnet/whatsjava/encryption/BinaryDecoder.java +++ b/src/main/java/icu/jnet/whatsjava/encryption/BinaryDecoder.java @@ -279,26 +279,26 @@ private String readNode() { try { switch(tag) { - // "message" message + // Conversation messages case BinaryConstants.Tags.BINARY_8: byte[] bin8 = readBytes(readByte() & 0xff); base64Decoded = Base64.getEncoder().encodeToString( WebMessageInfo.parseFrom(bin8).toByteArray()); + break; - // video & image message + // Image, video, extended and rarely conversation messages case BinaryConstants.Tags.BINARY_20: byte[] bin20 = readBytes(readInt20()); - base64Decoded = Base64.getEncoder().encodeToString( WebMessageInfo.parseFrom(bin20).toByteArray()); + break; // ? case BinaryConstants.Tags.BINARY_32: byte[] bin32 = readBytes(readInt(4, false)); - base64Decoded = Base64.getEncoder().encodeToString( WebMessageInfo.parseFrom(bin32).toByteArray()); - + break; default: base64Decoded = readString(tag); diff --git a/src/main/java/icu/jnet/whatsjava/encryption/BinaryEncryption.java b/src/main/java/icu/jnet/whatsjava/encryption/BinaryEncryption.java index 0c4cde3..34a3ffc 100644 --- a/src/main/java/icu/jnet/whatsjava/encryption/BinaryEncryption.java +++ b/src/main/java/icu/jnet/whatsjava/encryption/BinaryEncryption.java @@ -9,6 +9,11 @@ public class BinaryEncryption { + /* + * Encrypt and decrypt binary messages, but no E2E media + * + */ + public static byte[] decrypt(byte[] message, EncryptionKeyPair keyPair) throws DecoderException { // Encode byte array to hex char String hexMessage = Hex.encodeHexString(message, true); diff --git a/src/main/java/icu/jnet/whatsjava/encryption/EncryptionKeys.java b/src/main/java/icu/jnet/whatsjava/encryption/EncryptionKeys.java index d7e2bbc..3be4aab 100644 --- a/src/main/java/icu/jnet/whatsjava/encryption/EncryptionKeys.java +++ b/src/main/java/icu/jnet/whatsjava/encryption/EncryptionKeys.java @@ -6,7 +6,6 @@ import org.whispersystems.curve25519.Curve25519; -import at.favre.lib.crypto.HKDF; import icu.jnet.whatsjava.helper.Utils; public class EncryptionKeys { @@ -25,7 +24,7 @@ public static EncryptionKeyPair generate(String base64Secret, byte[] privateKey) byte[] sharedSecret = Curve25519.getInstance(Curve25519.BEST) .calculateAgreement(publicKey, privateKey); // Expand the shared key to 80 bytes using HKDF - byte[] sharedSecretExpanded = expandUsingHKDF(sharedSecret, 80); + byte[] sharedSecretExpanded = Utils.expandUsingHKDF(sharedSecret, 80, null); // Validate data by HMAC boolean valid = hmacValidate(sharedSecretExpanded, secret); @@ -61,11 +60,6 @@ public static EncryptionKeyPair generate(String base64Secret, byte[] privateKey) return null; } - private static byte[] expandUsingHKDF(byte[] key, int length) { - byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(null, key); - return HKDF.fromHmacSha256().expand(pseudoRandomKey, null, length); - } - private static boolean hmacValidate(byte[] sharedSecretExpanded, byte[] secret) { byte[] hmacValidationKey = Arrays.copyOfRange(sharedSecretExpanded, 32, 64); byte[] hmacSecretA = Arrays.copyOfRange(secret, 0, 32); diff --git a/src/main/java/icu/jnet/whatsjava/encryption/MediaEncryption.java b/src/main/java/icu/jnet/whatsjava/encryption/MediaEncryption.java new file mode 100644 index 0000000..2489fa6 --- /dev/null +++ b/src/main/java/icu/jnet/whatsjava/encryption/MediaEncryption.java @@ -0,0 +1,52 @@ +package icu.jnet.whatsjava.encryption; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import icu.jnet.whatsjava.helper.Utils; + +public class MediaEncryption { + + /* + * Decrypt E2E media + * + */ + + // Depending on the media type a different info parameter is used for the HKDF function + public static String MEDIA_TYPE_IMAGE = "WhatsApp Image Keys", + MEDIA_TYPE_VIDEO = "WhatsApp Video Keys", + MEDIA_TYPE_AUDIO = "WhatsApp Audio Keys", + MEDIA_TYPE_DOCUMENT = "WhatsApp Document Keys"; + + + public static byte[] decrypt(byte[] mediaKey, String url, String mediaType) { + // Expand mediaKey to 112 bytes and add mediaInfo + byte[] mediaKeyExpanded = Utils.expandUsingHKDF(mediaKey, 112, mediaType.getBytes()); + + byte[] iv = Arrays.copyOfRange(mediaKeyExpanded, 0, 16); + byte[] cipherKey = Arrays.copyOfRange(mediaKeyExpanded, 16, 48); + byte[] macKey = Arrays.copyOfRange(mediaKeyExpanded, 48, 80); + // refKey mediaKeyExpanded[80:112] not used + + // Download encrypted media + byte[] encryptedMedia = Utils.urlToEncMedia(url); + + if(encryptedMedia != null) { + byte[] file = Arrays.copyOfRange(encryptedMedia, 0, encryptedMedia.length - 10); + byte[] mac = Arrays.copyOfRange(encryptedMedia, encryptedMedia.length - 10, encryptedMedia.length); + + // Hmac sign message + byte[] message = ByteBuffer.allocate(iv.length + file.length).put(iv).put(file).array(); + + // Validate macKey of mediaKeyExpanded with mac key of the encrypted media + byte[] hmacSign = Utils.signHMAC(macKey, message); + + // Media validated + if(Arrays.equals(mac, Arrays.copyOfRange(hmacSign, 0, 10))) { + return AES.decrypt(file, cipherKey, iv); + } + } + + return null; + } +} diff --git a/src/main/java/icu/jnet/whatsjava/helper/Utils.java b/src/main/java/icu/jnet/whatsjava/helper/Utils.java index a57dd19..d333598 100644 --- a/src/main/java/icu/jnet/whatsjava/helper/Utils.java +++ b/src/main/java/icu/jnet/whatsjava/helper/Utils.java @@ -1,6 +1,12 @@ package icu.jnet.whatsjava.helper; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Instant; @@ -9,9 +15,12 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.io.FileUtils; + import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import at.favre.lib.crypto.HKDF; import icu.jnet.whatsjava.constants.RequestType; import icu.jnet.whatsjava.encryption.BinaryEncoder; import icu.jnet.whatsjava.encryption.BinaryEncryption; @@ -34,7 +43,7 @@ public static void waitMillis(long millis) { } } - /* Generate random byte array of specified length */ + // Generate random byte array of specified length public static byte[] randomBytes(int length) { Random rand = new Random(); byte[] clientId = new byte[length]; @@ -43,26 +52,26 @@ public static byte[] randomBytes(int length) { return clientId; } - /* WhatsApp adds a tag to most of the json messages. That's why we need to remove it */ + // WhatsApp adds a tag to most of the json messages. That's why we need to remove it public static JsonObject encodeValidJson(String message, String splitStart) { String rawSplittedMessage = message.replaceFirst(splitStart, "##").split("##")[1]; String rawMessage = rawSplittedMessage.substring(0, rawSplittedMessage.length() - 1); return JsonParser.parseString(rawMessage).getAsJsonObject(); } - /* Default split char [,] */ + // Default split char [,] public static JsonObject encodeValidJson(String message) { String raw = message.replaceFirst("[,]", "##").split("##")[1]; return JsonParser.parseString(raw).getAsJsonObject(); } - /* WhatsApp needs a message tag at the start of every Websocket request */ + // WhatsApp needs a message tag at the start of every Websocket request private static String getMessageTag() { String messageTag = Instant.now().getEpochSecond() + ".--" + wsRequestCount++; return messageTag; } - /* WhatsApp binary message tags look different */ + // WhatsApp binary message tags look different private static String getBinaryMessageTag() { if(binaryMessageTag.equals("")) { binaryMessageTag = (new Random().nextInt(900) + 100) + ""; @@ -76,7 +85,7 @@ public static int getMessageCount() { return wsRequestCount; } - /* Create a new websocket json request string */ + // Create a new websocket json request string public static String buildWebsocketJsonRequest(int requestType, String... content) { String messageTag = getMessageTag(); @@ -108,7 +117,7 @@ public static String buildWebsocketJsonRequest(int requestType, String... conten return request; } - /* Create a new websocket binary request array */ + // Create a new websocket binary request array public static byte[] buildWebsocketBinaryRequest(EncryptionKeyPair keyPair, String json, byte... waTags) { String tag = null; @@ -130,7 +139,13 @@ public static byte[] buildWebsocketBinaryRequest(EncryptionKeyPair keyPair, Stri .put(messageTag).put(waTags).put(hmacSign).put(encrypted).array(); } - /* Implementation: https://github.com/danharper/hmac-examples */ + // HLDF key expansion + public static byte[] expandUsingHKDF(byte[] key, int expandedLength, byte[] info) { + byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(null, key); + return HKDF.fromHmacSha256().expand(pseudoRandomKey, info, expandedLength); + } + + // Implementation: https://github.com/danharper/hmac-examples public static byte[] signHMAC(byte[] hmacValidationKey, byte[] hmacValidationMessage) { try { Mac hasher = Mac.getInstance("HmacSHA256"); @@ -143,4 +158,28 @@ public static byte[] signHMAC(byte[] hmacValidationKey, byte[] hmacValidationMes } return null; } + + // Download encrypted media files + public static byte[] urlToEncMedia(String url) { + try { + // Create random temporary file + Path path = Files.createTempFile(null, ".enc"); + File tmpFile = path.toFile(); + + byte[] encryptedMedia = null; + // Download encrypted file + try { + FileUtils.copyURLToFile(new URL(url), tmpFile); + + // Convert file to byte array + encryptedMedia = Files.readAllBytes(path); + } catch(FileNotFoundException ex) {} + + tmpFile.delete(); + return encryptedMedia; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } } diff --git a/src/main/java/icu/jnet/whatsjava/web/WebImageMessage.java b/src/main/java/icu/jnet/whatsjava/web/WebImageMessage.java index df931ae..8742ba6 100644 --- a/src/main/java/icu/jnet/whatsjava/web/WebImageMessage.java +++ b/src/main/java/icu/jnet/whatsjava/web/WebImageMessage.java @@ -1,10 +1,17 @@ package icu.jnet.whatsjava.web; +import icu.jnet.whatsjava.encryption.MediaEncryption; import icu.jnet.whatsjava.encryption.proto.ProtoBuf.ImageMessage; import icu.jnet.whatsjava.encryption.proto.ProtoBuf.WebMessageInfo; public class WebImageMessage extends WebMessage { + /* + * E2E media image message + * + */ + + private String mimetype, url, caption; private byte[] fileSha256, mediaKey, jpegThumbnail; private long fileLength; @@ -51,6 +58,10 @@ public byte[] getJpegThumbnail() { return jpegThumbnail; } + public byte[] getJpegFullResolution() { + return MediaEncryption.decrypt(mediaKey, url, MediaEncryption.MEDIA_TYPE_IMAGE); + } + public long getFileLength() { return fileLength; } diff --git a/src/main/java/icu/jnet/whatsjava/web/WebVideoMessage.java b/src/main/java/icu/jnet/whatsjava/web/WebVideoMessage.java index 761149c..a877a05 100644 --- a/src/main/java/icu/jnet/whatsjava/web/WebVideoMessage.java +++ b/src/main/java/icu/jnet/whatsjava/web/WebVideoMessage.java @@ -1,11 +1,17 @@ package icu.jnet.whatsjava.web; +import icu.jnet.whatsjava.encryption.MediaEncryption; import icu.jnet.whatsjava.encryption.proto.ProtoBuf.VideoMessage; import icu.jnet.whatsjava.encryption.proto.ProtoBuf.WebMessageInfo; import icu.jnet.whatsjava.encryption.proto.ProtoBuf.VideoMessage.VIDEO_MESSAGE_ATTRIBUTION; public class WebVideoMessage extends WebMessage { + /* + * E2E media video message + * + */ + private String mimetype, url; private byte[] fileSha256, mediaKey, jpegThumbnail; private long fileLength; @@ -46,10 +52,14 @@ public byte[] getMediaKey() { return mediaKey; } - public byte[] getJpegThumbnail() { + public byte[] getMp4Thumbnail() { return jpegThumbnail; } + public byte[] getMp4FullResolution() { + return MediaEncryption.decrypt(mediaKey, url, MediaEncryption.MEDIA_TYPE_VIDEO); + } + public long getFileLength() { return fileLength; }