Skip to content

Commit a36e49f

Browse files
Attachment encryption (#25)
1 parent 0a27299 commit a36e49f

File tree

14 files changed

+733
-4
lines changed

14 files changed

+733
-4
lines changed

library/build.gradle.kts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ android {
4040
"proguard-rules.pro"
4141
)
4242
}
43+
44+
debug {
45+
packaging {
46+
jniLibs {
47+
keepDebugSymbols += "**/*.so"
48+
}
49+
}
50+
}
4351
}
4452

4553
compileOptions {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package network.loki.messenger.libsession_util.image
2+
3+
import android.graphics.ImageDecoder
4+
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
import androidx.test.platform.app.InstrumentationRegistry
6+
import org.junit.Assert.assertEquals
7+
import org.junit.Assert.assertFalse
8+
import org.junit.Assert.assertTrue
9+
import org.junit.Test
10+
import org.junit.runner.RunWith
11+
import org.sessionfoundation.libsession_util.test.R
12+
13+
@RunWith(AndroidJUnit4::class)
14+
class GifUtilsTest {
15+
@Test
16+
fun testReencodeGif() {
17+
18+
for (outputSize in listOf(200, 400, 600)) {
19+
val output = InstrumentationRegistry.getInstrumentation()
20+
.targetContext
21+
.applicationContext
22+
.resources
23+
.openRawResource(R.raw.earth).use { input ->
24+
GifUtils.reencodeGif(
25+
input = input,
26+
timeoutMills = 100_000L,
27+
targetWidth = outputSize,
28+
targetHeight = outputSize
29+
)
30+
}
31+
32+
ImageDecoder.decodeDrawable(
33+
ImageDecoder.createSource(output)
34+
) { decoder, info, source ->
35+
assertEquals(outputSize, info.size.width)
36+
assertEquals(outputSize, info.size.height)
37+
assertTrue(info.isAnimated)
38+
}
39+
}
40+
}
41+
42+
@Test
43+
fun testCheckAnimatedGifWorks() {
44+
assertTrue(
45+
InstrumentationRegistry.getInstrumentation()
46+
.targetContext
47+
.applicationContext
48+
.resources
49+
.openRawResource(R.raw.earth)
50+
.use(GifUtils::isAnimatedGif)
51+
)
52+
53+
assertFalse(
54+
InstrumentationRegistry.getInstrumentation()
55+
.targetContext
56+
.applicationContext
57+
.resources
58+
.openRawResource(R.raw.sunflower_noanim)
59+
.use(GifUtils::isAnimatedGif)
60+
)
61+
}
62+
}
978 KB
Loading
26.7 KB
Loading

library/src/main/cpp/CMakeLists.txt

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
1515
set(CMAKE_CXX_EXTENSIONS OFF)
1616
set(CMAKE_CXX_FLAGS -Wno-deprecated-declarations)
1717

18-
set(CMAKE_BUILD_TYPE Release)
19-
2018
# Creates and names a library, sets it as either STATIC
2119
# or SHARED, and provides the relative paths to its source code.
2220
# You can define multiple libraries, and CMake builds them for you.
@@ -26,6 +24,55 @@ set(STATIC_BUNDLE ON)
2624
set(ENABLE_ONIONREQ OFF)
2725
add_subdirectory(../../../../libsession-util libsession)
2826

27+
include(FetchContent)
28+
29+
30+
## Catering for libwebp
31+
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
32+
set(WEBP_BUILD_ANIM_UTILS ON CACHE BOOL "" FORCE)
33+
set(WEBP_BUILD_LIBWEBPMUX ON CACHE BOOL "" FORCE)
34+
35+
FetchContent_Declare(
36+
webp
37+
GIT_REPOSITORY https://chromium.googlesource.com/webm/libwebp
38+
GIT_TAG v1.6.0
39+
)
40+
41+
FetchContent_MakeAvailable(webp)
42+
43+
## Catering for libyuv - to rescale images
44+
FetchContent_Declare(
45+
libyuv
46+
GIT_REPOSITORY https://chromium.googlesource.com/libyuv/libyuv
47+
GIT_TAG stable
48+
)
49+
FetchContent_MakeAvailable(libyuv)
50+
51+
## cgif
52+
FetchContent_Declare(
53+
cgif
54+
GIT_REPOSITORY https://github.com/dloebl/cgif.git
55+
GIT_TAG 4ddc417
56+
)
57+
FetchContent_MakeAvailable(cgif)
58+
59+
## giflib (only to encode)
60+
FetchContent_Declare(
61+
giflib
62+
GIT_REPOSITORY https://git.code.sf.net/p/giflib/code
63+
GIT_TAG 5.2.2
64+
)
65+
FetchContent_MakeAvailable(giflib)
66+
67+
## EasyGifReader (on top of giflib for easier reading)
68+
FetchContent_Declare(
69+
easy_gif_reader
70+
GIT_REPOSITORY https://github.com/Chlumsky/EasyGifReader
71+
GIT_TAG eaaa794
72+
)
73+
FetchContent_MakeAvailable(easy_gif_reader)
74+
75+
2976
set(SOURCES
3077
user_profile.cpp
3178
user_groups.cpp
@@ -44,6 +91,23 @@ set(SOURCES
4491
ed25519.cpp
4592
curve25519.cpp
4693
hash.cpp
94+
attachments.cpp
95+
webp_utils.cpp
96+
gif_utils.cpp
97+
98+
${cgif_SOURCE_DIR}/src/cgif.c
99+
${cgif_SOURCE_DIR}/src/cgif_rgb.c
100+
${cgif_SOURCE_DIR}/src/cgif_raw.c
101+
102+
${giflib_SOURCE_DIR}/gifalloc.c
103+
${giflib_SOURCE_DIR}/gif_err.c
104+
${giflib_SOURCE_DIR}/dgif_lib.c
105+
${giflib_SOURCE_DIR}/egif_lib.c
106+
${giflib_SOURCE_DIR}/gif_hash.c
107+
${giflib_SOURCE_DIR}/gif_font.c
108+
${giflib_SOURCE_DIR}/openbsd-reallocarray.c
109+
110+
${easy_gif_reader_SOURCE_DIR}/EasyGifReader.cpp
47111
)
48112

49113
add_library( # Sets the name of the library.
@@ -53,6 +117,15 @@ add_library( # Sets the name of the library.
53117
# Provides a relative path to your source file(s).
54118
${SOURCES})
55119

120+
target_include_directories(session_util
121+
PRIVATE
122+
${cgif_SOURCE_DIR}/inc
123+
${libyuv_SOURCE_DIR}/include
124+
${giflib_SOURCE_DIR}
125+
${easy_gif_reader_SOURCE_DIR}
126+
)
127+
128+
56129
# Searches for a specified prebuilt library and stores the path as a
57130
# variable. Because CMake includes system libraries in the search path by
58131
# default, you only need to specify the name of the public NDK library
@@ -78,4 +151,10 @@ target_link_libraries( # Specifies the target library.
78151
libsodium::sodium-internal
79152
# Links the target library to the log library
80153
# included in the NDK.
81-
${log-lib})
154+
${log-lib}
155+
webp
156+
libwebpmux
157+
webpdemux
158+
webpdecoder
159+
yuv
160+
)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include <jni.h>
2+
#include <session/attachments.hpp>
3+
#include "jni_utils.h"
4+
5+
using namespace session::attachment;
6+
using namespace jni_utils;
7+
8+
extern "C"
9+
JNIEXPORT jlong JNICALL
10+
Java_network_loki_messenger_libsession_1util_encrypt_Attachments_encryptedSize(JNIEnv *env,
11+
jobject thiz,
12+
jlong plaintext_size) {
13+
return encrypted_size(plaintext_size);
14+
}
15+
16+
extern "C"
17+
JNIEXPORT jlong JNICALL
18+
Java_network_loki_messenger_libsession_1util_encrypt_Attachments_decryptedMaxSize(JNIEnv *env,
19+
jobject thiz,
20+
jlong ciphertext_size) {
21+
auto s = decrypted_max_size(ciphertext_size);
22+
if (s.has_value()) {
23+
return *s;
24+
} else {
25+
env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
26+
"ciphertext_size too small to be a valid encrypted attachment");
27+
return 0;
28+
}
29+
}
30+
31+
extern "C"
32+
JNIEXPORT jbyteArray JNICALL
33+
Java_network_loki_messenger_libsession_1util_encrypt_Attachments_encryptBytes(JNIEnv *env,
34+
jobject thiz,
35+
jbyteArray seed,
36+
jbyteArray plaintext_in,
37+
jint plaintext_in_offset,
38+
jint plaintext_in_len,
39+
jbyteArray cipher_out,
40+
jint cipher_out_offset,
41+
jint cipher_out_len,
42+
jint domain) {
43+
return run_catching_cxx_exception_or_throws<jbyteArray>(env, [=] {
44+
auto key = encrypt(
45+
JavaByteArrayRef(env, seed).get_as_bytes(),
46+
JavaByteArrayRef(env, plaintext_in).get_as_bytes().subspan(plaintext_in_offset, plaintext_in_len),
47+
static_cast<Domain>(domain),
48+
JavaByteArrayRef(env, cipher_out).get_as_bytes().subspan(cipher_out_offset, cipher_out_len)
49+
);
50+
51+
52+
return util::bytes_from_span(env, std::span(reinterpret_cast<unsigned char *>(key.data()), key.size()));
53+
});
54+
}
55+
56+
extern "C"
57+
JNIEXPORT jlong JNICALL
58+
Java_network_loki_messenger_libsession_1util_encrypt_Attachments_decryptBytes(JNIEnv *env,
59+
jobject thiz,
60+
jbyteArray key,
61+
jbyteArray cipher_in,
62+
jint cipher_in_offset,
63+
jint cipher_in_len,
64+
jbyteArray plain_out,
65+
jint plain_out_offset,
66+
jint plain_out_len) {
67+
return run_catching_cxx_exception_or_throws<jlong>(env, [=] {
68+
JavaByteArrayRef key_ref(env, key);
69+
70+
return decrypt(
71+
JavaByteArrayRef(env, cipher_in).get_as_bytes().subspan(cipher_in_offset, cipher_in_len),
72+
std::span<std::byte, ENCRYPT_KEY_SIZE>(
73+
reinterpret_cast<std::byte *>(key_ref.get().data()),
74+
ENCRYPT_KEY_SIZE
75+
),
76+
JavaByteArrayRef(env, plain_out).get_as_bytes().subspan(plain_out_offset, plain_out_len)
77+
);
78+
});
79+
}

0 commit comments

Comments
 (0)