jni_bridge.rs

9.8 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#[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}