@@ -156,4 +156,134 @@ Java_network_loki_messenger_libsession_1util_SessionEncrypt_calculateECHDAgreeme
156156 return util::bytes_from_span (env, shared_secret);
157157 });
158158
159+ }
160+
161+ extern " C"
162+ JNIEXPORT jlong JNICALL
163+ Java_network_loki_messenger_libsession_1util_encrypt_EncryptionStream_00024Companion_createEncryptionStreamState (
164+ JNIEnv *env, jobject thiz, jbyteArray javaKey, jbyteArray javaHeaderOut) {
165+ JavaByteArrayRef key (env, javaKey);
166+ JavaByteArrayRef headerOut (env, javaHeaderOut);
167+
168+ if (headerOut.get ().size () < crypto_secretstream_xchacha20poly1305_HEADERBYTES) {
169+ env->ThrowNew (env->FindClass (" java/lang/IllegalArgumentException" ),
170+ " Invalid headerOut: not enough space" );
171+ return 0 ;
172+ }
173+
174+ if (key.get ().size () != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
175+ env->ThrowNew (env->FindClass (" java/lang/IllegalArgumentException" ),
176+ " Invalid key: unexpected size" );
177+ return 0 ;
178+ }
179+
180+ auto state = std::make_unique<crypto_secretstream_xchacha20poly1305_state>();
181+ crypto_secretstream_xchacha20poly1305_init_push (state.get (),
182+ headerOut.get ().data (),
183+ key.get ().data ());
184+
185+ return reinterpret_cast <jlong>(state.release ());
186+ }
187+
188+ extern " C"
189+ JNIEXPORT jint JNICALL
190+ Java_network_loki_messenger_libsession_1util_encrypt_EncryptionStream_00024Companion_encryptionStreamHeaderSize (
191+ JNIEnv *env, jobject thiz) {
192+ return static_cast <jint>(crypto_secretstream_xchacha20poly1305_HEADERBYTES);
193+ }
194+
195+ extern " C"
196+ JNIEXPORT jint JNICALL
197+ Java_network_loki_messenger_libsession_1util_encrypt_EncryptionStream_00024Companion_encryptionStreamChunkOverhead (
198+ JNIEnv *env, jobject thiz) {
199+ return static_cast <jint>(crypto_secretstream_xchacha20poly1305_ABYTES);
200+ }
201+
202+ extern " C"
203+ JNIEXPORT jint JNICALL
204+ Java_network_loki_messenger_libsession_1util_encrypt_EncryptionStream_00024Companion_encryptStreamPush (
205+ JNIEnv *env, jobject thiz, jlong state_ptr, jbyteArray java_in_buf, jint in_buf_size, jbyteArray java_out_buf) {
206+ auto state = reinterpret_cast <crypto_secretstream_xchacha20poly1305_state*>(state_ptr);
207+
208+ JavaByteArrayRef in_buf (env, java_in_buf);
209+ JavaByteArrayRef out_buf (env, java_out_buf);
210+
211+ unsigned long long cipher_len = out_buf.get ().size ();
212+
213+ if (crypto_secretstream_xchacha20poly1305_push (
214+ state,
215+ out_buf.get ().data (), &cipher_len, // Cipher data out
216+ in_buf.get ().data (), in_buf_size, // Plaintext data in
217+ nullptr , 0 , // Additional data (not used here)
218+ 0 // Tag (not used here, can be 0 for message)
219+ )) {
220+ env->ThrowNew (env->FindClass (" java/lang/IllegalStateException" ),
221+ " Failed to push data into encryption stream" );
222+ return 0 ;
223+ }
224+
225+ // Return the size of the ciphertext written to the output buffer
226+ return cipher_len;
227+ }
228+
229+ extern " C"
230+ JNIEXPORT void JNICALL
231+ Java_network_loki_messenger_libsession_1util_encrypt_EncryptionStream_00024Companion_destroyEncryptionStreamState (
232+ JNIEnv *env, jobject thiz, jlong state_ptr) {
233+ delete reinterpret_cast <crypto_secretstream_xchacha20poly1305_state*>(state_ptr);
234+ }
235+
236+
237+ extern " C"
238+ JNIEXPORT jlong JNICALL
239+ Java_network_loki_messenger_libsession_1util_encrypt_DecryptionStream_00024Companion_createDecryptionStreamState (
240+ JNIEnv *env, jobject thiz, jbyteArray javaKey, jbyteArray javaHeader) {
241+ JavaByteArrayRef key (env, javaKey);
242+ JavaByteArrayRef header (env, javaHeader);
243+
244+ if (header.get ().size () < crypto_secretstream_xchacha20poly1305_HEADERBYTES) {
245+ env->ThrowNew (env->FindClass (" java/lang/IllegalArgumentException" ),
246+ " Invalid header: unexpected size" );
247+ return 0 ;
248+ }
249+
250+ if (key.get ().size () != crypto_secretstream_xchacha20poly1305_KEYBYTES) {
251+ env->ThrowNew (env->FindClass (" java/lang/IllegalArgumentException" ),
252+ " Invalid key: unexpected size" );
253+ return 0 ;
254+ }
255+
256+ auto state = std::make_unique<crypto_secretstream_xchacha20poly1305_state>();
257+
258+ if (crypto_secretstream_xchacha20poly1305_init_pull (state.get (), header.get ().data (), key.get ().data ()) != 0 ) {
259+ env->ThrowNew (env->FindClass (" java/lang/IllegalArgumentException" ),
260+ " Failed to initialize decryption stream state" );
261+ return 0 ;
262+ }
263+
264+ return reinterpret_cast <jlong>(state.release ());
265+ }
266+
267+ extern " C"
268+ JNIEXPORT jint JNICALL
269+ Java_network_loki_messenger_libsession_1util_encrypt_DecryptionStream_00024Companion_decryptionStreamPull (
270+ JNIEnv *env, jobject thiz, jlong native_state_ptr, jbyteArray java_in_buf, jint in_buf_len, jbyteArray java_out_buf) {
271+ JavaByteArrayRef out_buf (env, java_out_buf);
272+ JavaByteArrayRef in_buf (env, java_in_buf);
273+
274+ unsigned long long mlen = out_buf.get ().size ();
275+
276+ if (crypto_secretstream_xchacha20poly1305_pull (
277+ reinterpret_cast <crypto_secretstream_xchacha20poly1305_state*>(native_state_ptr),
278+ out_buf.get ().data (), &mlen, // Plaintext data out
279+ nullptr , // Tag (not used here)
280+ in_buf.get ().data (), in_buf_len, // Ciphertext data in
281+ nullptr , 0 // Additional data (not used here)
282+ )) {
283+ env->ThrowNew (env->FindClass (" java/lang/IllegalStateException" ),
284+ " Failed to pull data from decryption stream" );
285+ return 0 ;
286+ }
287+
288+ return mlen;
159289}
0 commit comments