jni_bridge.rs

10.0 KB · raw

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}