1use super::CoreNoiseSession;2use jni::{3 JNIEnv,4 objects::{JByteArray, JObject},5 sys::{jbyteArray, jlong},6};7use once_cell::sync::Lazy;8use std::{9 collections::HashMap,10 ptr,11 sync::{12 Mutex,13 atomic::{AtomicI64, Ordering},14 },15};1617static NEXT_HANDLE: AtomicI64 = AtomicI64::new(1);18static SESSIONS: Lazy<Mutex<HashMap<i64, CoreNoiseSession>>> =19 Lazy::new(|| Mutex::new(HashMap::new()));2021type NativeResult<T> = Result<T, String>;2223fn bytes(env: &JNIEnv<'_>, value: JByteArray<'_>) -> NativeResult<Vec<u8>> {24 env.convert_byte_array(value)25 .map_err(|error| error.to_string())26}2728fn create(session: CoreNoiseSession) -> NativeResult<jlong> {29 let handle = NEXT_HANDLE.fetch_add(1, Ordering::Relaxed);30 SESSIONS31 .lock()32 .map_err(|_| "Noise session registry is unavailable".to_string())?33 .insert(handle, session);34 Ok(handle)35}3637fn with_session<T>(38 handle: jlong,39 operation: impl FnOnce(&mut CoreNoiseSession) -> NativeResult<T>,40) -> NativeResult<T> {41 let mut sessions = SESSIONS42 .lock()43 .map_err(|_| "Noise session registry is unavailable".to_string())?;44 let session = sessions45 .get_mut(&handle)46 .ok_or_else(|| "Noise session handle is invalid or closed".to_string())?;47 operation(session)48}4950fn throw(env: &mut JNIEnv<'_>, message: String) {51 let _ = env.throw_new("java/lang/IllegalStateException", message);52}5354fn long_result(env: &mut JNIEnv<'_>, result: NativeResult<jlong>) -> jlong {55 match result {56 Ok(value) => value,57 Err(error) => {58 throw(env, error);59 060 }61 }62}6364fn array_result(env: &mut JNIEnv<'_>, result: NativeResult<Vec<u8>>) -> jbyteArray {65 match result {66 Ok(value) => match env.byte_array_from_slice(&value) {67 Ok(array) => array.into_raw(),68 Err(error) => {69 throw(env, error.to_string());70 ptr::null_mut()71 }72 },73 Err(error) => {74 throw(env, error);75 ptr::null_mut()76 }77 }78}7980#[unsafe(no_mangle)]81pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateNkInitiator(82 mut env: JNIEnv,83 _object: JObject,84 remote_public_key: JByteArray,85) -> jlong {86 let result = bytes(&env, remote_public_key)87 .and_then(|key| CoreNoiseSession::nk_initiator(&key).and_then(create));88 long_result(&mut env, result)89}9091#[unsafe(no_mangle)]92pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateNkResponder(93 mut env: JNIEnv,94 _object: JObject,95 local_private_key: JByteArray,96 local_public_key: JByteArray,97) -> jlong {98 let result = bytes(&env, local_private_key).and_then(|private| {99 bytes(&env, local_public_key)100 .and_then(|public| CoreNoiseSession::nk_responder(&private, &public).and_then(create))101 });102 long_result(&mut env, result)103}104105#[cfg(feature = "test-constructors")]106#[unsafe(no_mangle)]107pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateNkInitiatorForTest(108 mut env: JNIEnv,109 _object: JObject,110 remote_public_key: JByteArray,111 ephemeral_private_key: JByteArray,112) -> jlong {113 let result = bytes(&env, remote_public_key).and_then(|remote| {114 bytes(&env, ephemeral_private_key).and_then(|ephemeral| {115 CoreNoiseSession::nk_initiator_with_ephemeral_for_test(&remote, &ephemeral)116 .and_then(create)117 })118 });119 long_result(&mut env, result)120}121122#[cfg(feature = "test-constructors")]123#[unsafe(no_mangle)]124pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateNkResponderForTest(125 mut env: JNIEnv,126 _object: JObject,127 local_private_key: JByteArray,128 local_public_key: JByteArray,129 ephemeral_private_key: JByteArray,130) -> jlong {131 let result = bytes(&env, local_private_key).and_then(|private| {132 bytes(&env, local_public_key).and_then(|public| {133 bytes(&env, ephemeral_private_key).and_then(|ephemeral| {134 CoreNoiseSession::nk_responder_with_ephemeral_for_test(135 &private, &public, &ephemeral,136 )137 .and_then(create)138 })139 })140 });141 long_result(&mut env, result)142}143144#[unsafe(no_mangle)]145pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateKkInitiator(146 mut env: JNIEnv,147 _object: JObject,148 local_private_key: JByteArray,149 local_public_key: JByteArray,150 remote_public_key: JByteArray,151) -> jlong {152 let result = bytes(&env, local_private_key).and_then(|private| {153 bytes(&env, local_public_key).and_then(|public| {154 bytes(&env, remote_public_key).and_then(|remote| {155 CoreNoiseSession::kk_initiator(&private, &public, &remote).and_then(create)156 })157 })158 });159 long_result(&mut env, result)160}161162#[unsafe(no_mangle)]163pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateKkResponder(164 mut env: JNIEnv,165 _object: JObject,166 local_private_key: JByteArray,167 local_public_key: JByteArray,168 remote_public_key: JByteArray,169) -> jlong {170 let result = bytes(&env, local_private_key).and_then(|private| {171 bytes(&env, local_public_key).and_then(|public| {172 bytes(&env, remote_public_key).and_then(|remote| {173 CoreNoiseSession::kk_responder(&private, &public, &remote).and_then(create)174 })175 })176 });177 long_result(&mut env, result)178}179180#[cfg(feature = "test-constructors")]181#[unsafe(no_mangle)]182pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateKkInitiatorForTest(183 mut env: JNIEnv,184 _object: JObject,185 local_private_key: JByteArray,186 local_public_key: JByteArray,187 remote_public_key: JByteArray,188 ephemeral_private_key: JByteArray,189) -> jlong {190 let result = bytes(&env, local_private_key).and_then(|private| {191 bytes(&env, local_public_key).and_then(|public| {192 bytes(&env, remote_public_key).and_then(|remote| {193 bytes(&env, ephemeral_private_key).and_then(|ephemeral| {194 CoreNoiseSession::kk_initiator_with_ephemeral_for_test(195 &private, &public, &remote, &ephemeral,196 )197 .and_then(create)198 })199 })200 })201 });202 long_result(&mut env, result)203}204205#[cfg(feature = "test-constructors")]206#[unsafe(no_mangle)]207pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateKkResponderForTest(208 mut env: JNIEnv,209 _object: JObject,210 local_private_key: JByteArray,211 local_public_key: JByteArray,212 remote_public_key: JByteArray,213 ephemeral_private_key: JByteArray,214) -> jlong {215 let result = bytes(&env, local_private_key).and_then(|private| {216 bytes(&env, local_public_key).and_then(|public| {217 bytes(&env, remote_public_key).and_then(|remote| {218 bytes(&env, ephemeral_private_key).and_then(|ephemeral| {219 CoreNoiseSession::kk_responder_with_ephemeral_for_test(220 &private, &public, &remote, &ephemeral,221 )222 .and_then(create)223 })224 })225 })226 });227 long_result(&mut env, result)228}229230#[unsafe(no_mangle)]231pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeWriteHandshake(232 mut env: JNIEnv,233 _object: JObject,234 handle: jlong,235 payload: JByteArray,236) -> jbyteArray {237 let result = bytes(&env, payload)238 .and_then(|value| with_session(handle, |session| session.write_handshake(&value)));239 array_result(&mut env, result)240}241242#[unsafe(no_mangle)]243pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeReadHandshake(244 mut env: JNIEnv,245 _object: JObject,246 handle: jlong,247 message: JByteArray,248) -> jbyteArray {249 let result = bytes(&env, message)250 .and_then(|value| with_session(handle, |session| session.read_handshake(&value)));251 array_result(&mut env, result)252}253254#[unsafe(no_mangle)]255pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeEncrypt(256 mut env: JNIEnv,257 _object: JObject,258 handle: jlong,259 plaintext: JByteArray,260) -> jbyteArray {261 let result = bytes(&env, plaintext)262 .and_then(|value| with_session(handle, |session| session.encrypt(&value)));263 array_result(&mut env, result)264}265266#[unsafe(no_mangle)]267pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeDecrypt(268 mut env: JNIEnv,269 _object: JObject,270 handle: jlong,271 ciphertext: JByteArray,272) -> jbyteArray {273 let result = bytes(&env, ciphertext)274 .and_then(|value| with_session(handle, |session| session.decrypt(&value)));275 array_result(&mut env, result)276}277278#[unsafe(no_mangle)]279pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeHandshakeHash(280 mut env: JNIEnv,281 _object: JObject,282 handle: jlong,283) -> jbyteArray {284 let result = with_session(handle, |session| session.handshake_hash());285 array_result(&mut env, result)286}287288#[unsafe(no_mangle)]289pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeRekeyOutgoing(290 mut env: JNIEnv,291 _object: JObject,292 handle: jlong,293) {294 if let Err(error) = with_session(handle, |session| session.rekey_outgoing()) {295 throw(&mut env, error);296 }297}298299#[unsafe(no_mangle)]300pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeRekeyIncoming(301 mut env: JNIEnv,302 _object: JObject,303 handle: jlong,304) {305 if let Err(error) = with_session(handle, |session| session.rekey_incoming()) {306 throw(&mut env, error);307 }308}309310#[unsafe(no_mangle)]311pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeClose(312 mut env: JNIEnv,313 _object: JObject,314 handle: jlong,315) {316 match SESSIONS.lock() {317 Ok(mut sessions) => {318 sessions.remove(&handle);319 }320 Err(_) => throw(&mut env, "Noise session registry is unavailable".into()),321 }322}