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#[unsafe(no_mangle)]106pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateNkInitiatorForTest(107 mut env: JNIEnv,108 _object: JObject,109 remote_public_key: JByteArray,110 ephemeral_private_key: JByteArray,111) -> jlong {112 let result = bytes(&env, remote_public_key).and_then(|remote| {113 bytes(&env, ephemeral_private_key).and_then(|ephemeral| {114 CoreNoiseSession::nk_initiator_with_ephemeral_for_test(&remote, &ephemeral)115 .and_then(create)116 })117 });118 long_result(&mut env, result)119}120121#[unsafe(no_mangle)]122pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateNkResponderForTest(123 mut env: JNIEnv,124 _object: JObject,125 local_private_key: JByteArray,126 local_public_key: JByteArray,127 ephemeral_private_key: JByteArray,128) -> jlong {129 let result = bytes(&env, local_private_key).and_then(|private| {130 bytes(&env, local_public_key).and_then(|public| {131 bytes(&env, ephemeral_private_key).and_then(|ephemeral| {132 CoreNoiseSession::nk_responder_with_ephemeral_for_test(133 &private, &public, &ephemeral,134 )135 .and_then(create)136 })137 })138 });139 long_result(&mut env, result)140}141142#[unsafe(no_mangle)]143pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateKkInitiator(144 mut env: JNIEnv,145 _object: JObject,146 local_private_key: JByteArray,147 local_public_key: JByteArray,148 remote_public_key: JByteArray,149) -> jlong {150 let result = bytes(&env, local_private_key).and_then(|private| {151 bytes(&env, local_public_key).and_then(|public| {152 bytes(&env, remote_public_key).and_then(|remote| {153 CoreNoiseSession::kk_initiator(&private, &public, &remote).and_then(create)154 })155 })156 });157 long_result(&mut env, result)158}159160#[unsafe(no_mangle)]161pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateKkResponder(162 mut env: JNIEnv,163 _object: JObject,164 local_private_key: JByteArray,165 local_public_key: JByteArray,166 remote_public_key: JByteArray,167) -> jlong {168 let result = bytes(&env, local_private_key).and_then(|private| {169 bytes(&env, local_public_key).and_then(|public| {170 bytes(&env, remote_public_key).and_then(|remote| {171 CoreNoiseSession::kk_responder(&private, &public, &remote).and_then(create)172 })173 })174 });175 long_result(&mut env, result)176}177178#[unsafe(no_mangle)]179pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateKkInitiatorForTest(180 mut env: JNIEnv,181 _object: JObject,182 local_private_key: JByteArray,183 local_public_key: JByteArray,184 remote_public_key: JByteArray,185 ephemeral_private_key: JByteArray,186) -> jlong {187 let result = bytes(&env, local_private_key).and_then(|private| {188 bytes(&env, local_public_key).and_then(|public| {189 bytes(&env, remote_public_key).and_then(|remote| {190 bytes(&env, ephemeral_private_key).and_then(|ephemeral| {191 CoreNoiseSession::kk_initiator_with_ephemeral_for_test(192 &private, &public, &remote, &ephemeral,193 )194 .and_then(create)195 })196 })197 })198 });199 long_result(&mut env, result)200}201202#[unsafe(no_mangle)]203pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeCreateKkResponderForTest(204 mut env: JNIEnv,205 _object: JObject,206 local_private_key: JByteArray,207 local_public_key: JByteArray,208 remote_public_key: JByteArray,209 ephemeral_private_key: JByteArray,210) -> jlong {211 let result = bytes(&env, local_private_key).and_then(|private| {212 bytes(&env, local_public_key).and_then(|public| {213 bytes(&env, remote_public_key).and_then(|remote| {214 bytes(&env, ephemeral_private_key).and_then(|ephemeral| {215 CoreNoiseSession::kk_responder_with_ephemeral_for_test(216 &private, &public, &remote, &ephemeral,217 )218 .and_then(create)219 })220 })221 })222 });223 long_result(&mut env, result)224}225226#[unsafe(no_mangle)]227pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeWriteHandshake(228 mut env: JNIEnv,229 _object: JObject,230 handle: jlong,231 payload: JByteArray,232) -> jbyteArray {233 let result = bytes(&env, payload)234 .and_then(|value| with_session(handle, |session| session.write_handshake(&value)));235 array_result(&mut env, result)236}237238#[unsafe(no_mangle)]239pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeReadHandshake(240 mut env: JNIEnv,241 _object: JObject,242 handle: jlong,243 message: JByteArray,244) -> jbyteArray {245 let result = bytes(&env, message)246 .and_then(|value| with_session(handle, |session| session.read_handshake(&value)));247 array_result(&mut env, result)248}249250#[unsafe(no_mangle)]251pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeEncrypt(252 mut env: JNIEnv,253 _object: JObject,254 handle: jlong,255 plaintext: JByteArray,256) -> jbyteArray {257 let result = bytes(&env, plaintext)258 .and_then(|value| with_session(handle, |session| session.encrypt(&value)));259 array_result(&mut env, result)260}261262#[unsafe(no_mangle)]263pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeDecrypt(264 mut env: JNIEnv,265 _object: JObject,266 handle: jlong,267 ciphertext: JByteArray,268) -> jbyteArray {269 let result = bytes(&env, ciphertext)270 .and_then(|value| with_session(handle, |session| session.decrypt(&value)));271 array_result(&mut env, result)272}273274#[unsafe(no_mangle)]275pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeHandshakeHash(276 mut env: JNIEnv,277 _object: JObject,278 handle: jlong,279) -> jbyteArray {280 let result = with_session(handle, |session| session.handshake_hash());281 array_result(&mut env, result)282}283284#[unsafe(no_mangle)]285pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeRekeyOutgoing(286 mut env: JNIEnv,287 _object: JObject,288 handle: jlong,289) {290 if let Err(error) = with_session(handle, |session| session.rekey_outgoing()) {291 throw(&mut env, error);292 }293}294295#[unsafe(no_mangle)]296pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeRekeyIncoming(297 mut env: JNIEnv,298 _object: JObject,299 handle: jlong,300) {301 if let Err(error) = with_session(handle, |session| session.rekey_incoming()) {302 throw(&mut env, error);303 }304}305306#[unsafe(no_mangle)]307pub extern "system" fn Java_com_peachpasswords_sync_RustNoiseNative_nativeClose(308 mut env: JNIEnv,309 _object: JObject,310 handle: jlong,311) {312 match SESSIONS.lock() {313 Ok(mut sessions) => {314 sessions.remove(&handle);315 }316 Err(_) => throw(&mut env, "Noise session registry is unavailable".into()),317 }318}