Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

base64/hex utils #39

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 108 additions & 1 deletion android/src/main/cpp/sodium-jni.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#include <jni.h>
#include "sodium.h"

Expand All @@ -7,6 +6,22 @@
extern "C" {
#endif

/* *****************************************************************************
* Helpers
* *****************************************************************************
*/

// use only for copying values, returning values here from crypto won't work
unsigned char* as_unsigned_char_array(JNIEnv *jenv, jbyteArray array) {
if (array == NULL) {
return NULL;
}
int len = (*jenv)->GetArrayLength (jenv, array);
unsigned char* buf = malloc(len);
(*jenv)->GetByteArrayRegion (jenv, array, 0, len, (jbyte*)(buf));
return buf;
}

/* *****************************************************************************
* Sodium-specific functions
* *****************************************************************************
Expand Down Expand Up @@ -455,6 +470,98 @@ JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1sign_1ed25519_1s
return (jint)result;
}

JNIEXPORT jint JNICALL
Java_org_libsodium_jni_SodiumJNI_base64_1variant_1ORIGINAL(JNIEnv *env, jclass clazz) {
return (jint)sodium_base64_VARIANT_ORIGINAL;
}

JNIEXPORT jint JNICALL
Java_org_libsodium_jni_SodiumJNI_base64_1variant_1VARIANT_1ORIGINAL_1NO_1PADDING(JNIEnv *env,
jclass clazz) {
return (jint)sodium_base64_VARIANT_ORIGINAL_NO_PADDING;
}

JNIEXPORT jint JNICALL
Java_org_libsodium_jni_SodiumJNI_base64_1variant_1VARIANT_1URLSAFE(JNIEnv *env, jclass clazz) {
return (jint)sodium_base64_VARIANT_URLSAFE;
}

JNIEXPORT jint JNICALL
Java_org_libsodium_jni_SodiumJNI_base64_1variant_1VARIANT_1URLSAFE_1NO_1PADDING(JNIEnv *env,
jclass clazz) {
return (jint)sodium_base64_VARIANT_URLSAFE_NO_PADDING;
}

JNIEXPORT jint JNICALL
Java_org_libsodium_jni_SodiumJNI_sodium_1base642bin(JNIEnv *jenv, jclass clazz, jbyteArray j_bin,
jint j_bin_maxlen, jbyteArray j_b64, jint j_b64_len,
jbyteArray j_ignore, jintArray j_bin_len,
jbyteArray j_b64_end, jint j_variant) {
unsigned char *bin = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_bin, 0);
jint *len = (*jenv)->GetIntArrayElements(jenv, j_bin_len, 0);
unsigned char *b64 = as_unsigned_char_array(jenv, j_b64);
unsigned char *ignore = as_unsigned_char_array(jenv, j_ignore);
void *memory = malloc(sizeof(int));
int *ptr = (int *)memory;

int result = sodium_base642bin(bin, j_bin_maxlen, b64, j_b64_len, ignore,
ptr, j_b64_end, j_variant);
(*jenv)->ReleaseByteArrayElements(jenv, j_bin, (jbyte *) bin, 0);
len[0] = *ptr;
(*jenv)->ReleaseIntArrayElements(jenv, j_bin_len, len, 0);
free(memory);
return (jint)result;
}

JNIEXPORT jchar JNICALL
Java_org_libsodium_jni_SodiumJNI_sodium_1bin2hex(JNIEnv *jenv, jclass clazz, jbyteArray j_hex,
jint j_hex_maxlen, jbyteArray j_bin, jint j_bin_len) {
unsigned char *hex = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_hex, 0);
unsigned char *bin = as_unsigned_char_array(jenv, j_bin);

int result = sodium_bin2hex(hex, j_hex_maxlen, bin, j_bin_len);
(*jenv)->ReleaseByteArrayElements(jenv, j_hex, (jbyte *) hex, 0);
return (jint)result;
}

JNIEXPORT jint JNICALL
Java_org_libsodium_jni_SodiumJNI_sodium_1hex2bin(JNIEnv *jenv, jclass clazz, jbyteArray j_bin,
jint j_bin_maxlen, jbyteArray j_hex, jint j_hex_len,
jbyteArray j_ignore, jintArray j_bin_len,
jbyteArray j_hex_end) {
unsigned char *bin = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_bin, 0);
jint *len = (*jenv)->GetIntArrayElements(jenv, j_bin_len, 0);
unsigned char *hex = as_unsigned_char_array(jenv, j_hex);
unsigned char *ignore = as_unsigned_char_array(jenv, j_ignore);
void *memory = malloc(sizeof(int));
int *ptr = (int *)memory;

int result = sodium_hex2bin(bin, j_bin_maxlen, hex, j_hex_len, ignore, ptr, j_hex_end);
(*jenv)->ReleaseByteArrayElements(jenv, j_bin, (jbyte *) bin, 0);
len[0] = *ptr;
(*jenv)->ReleaseIntArrayElements(jenv, j_bin_len, len, 0);
free(memory);
return (jint)result;
}

JNIEXPORT jchar JNICALL
Java_org_libsodium_jni_SodiumJNI_sodium_1bin2base64(JNIEnv *jenv, jclass clazz, jbyteArray j_b64,
jint j_b64_maxlen, jbyteArray j_bin, jint j_bin_len,
jint j_variant) {
unsigned char *b64 = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_b64, 0);
unsigned char *bin = as_unsigned_char_array(jenv, j_bin);

int result = sodium_bin2base64(b64, j_b64_maxlen, bin, j_bin_len, j_variant);
(*jenv)->ReleaseByteArrayElements(jenv, j_b64, (jbyte *) b64, 0);
return (jint)result;
}

JNIEXPORT jint JNICALL
Java_org_libsodium_jni_SodiumJNI_sodium_1base64_1encoded_1len(JNIEnv *jenv, jclass clazz,
jint j_bin_len, jint j_variant) {
return (jint) sodium_base64_encoded_len(j_bin_len, j_variant);
}

#ifdef __cplusplus
}
#endif
11 changes: 11 additions & 0 deletions android/src/main/java/org/libsodium/jni/SodiumJNI.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,15 @@ public class SodiumJNI {
public final static native int crypto_sign_ed25519_pk_to_curve25519(byte[] curve25519_pk, final byte[] ed25519_pk);
public final static native int crypto_sign_ed25519_sk_to_curve25519(byte[] curve25519_sk, final byte[] ed25519_sk);
public final static native int crypto_sign_ed25519_sk_to_pk(byte[] sk, byte[] pk);

public final static native int base64_variant_ORIGINAL();
public final static native int base64_variant_VARIANT_ORIGINAL_NO_PADDING();
public final static native int base64_variant_VARIANT_URLSAFE();
public final static native int base64_variant_VARIANT_URLSAFE_NO_PADDING();

public final static native char sodium_bin2base64(byte[] b64, final int b64_maxlen, final byte[] bin, final int bin_len, final int variant);
public final static native int sodium_base642bin(final byte[] bin, int bin_maxlen, final byte[] b64, final int b64_len, final byte[] ignore, int[] bin_len, final byte[] b64_end, final int variant);
public final static native char sodium_bin2hex(byte[] hex, int hex_maxlen, byte[] bin, final int bin_len);
public final static native int sodium_hex2bin(byte[] bin, final int bin_maxlen, final byte[] hex, final int hex_len, final byte[] ignore, int[] bin_len, final byte[] hex_end);
public final static native int sodium_base64_encoded_len(final int bin_len, final int variant);
}
123 changes: 123 additions & 0 deletions android/src/main/java/org/libsodium/rn/RCTSodiumModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -665,4 +665,127 @@ public void crypto_sign_ed25519_sk_to_pk(final String sk, final Promise p) {
p.reject(ESODIUM, ERR_FAILURE, t);
}
}

// ***************************************************************************
// * Utils
// ***************************************************************************

@ReactMethod
public void to_base64(final String message, final int variant, final Promise p) {
byte[] m = message.getBytes(StandardCharsets.UTF_8);
String result = this.binToBase64(m, variant);
if (result == null) {
p.reject(ESODIUM,ERR_FAILURE);
} else {
p.resolve(result);
}
}

@ReactMethod
public void from_base64(final String cipher, final int variant, final Promise p) {
byte[] result = this.base64ToBin(cipher, variant);
if (result == null) {
p.reject(ESODIUM,ERR_FAILURE);
} else {
p.resolve(new String(result, StandardCharsets.UTF_8));
}
}

@ReactMethod
public void to_hex(final String message, final Promise p) {
byte[] m = message.getBytes(StandardCharsets.UTF_8);
String result = this.binToHex(m);
if (result == null) {
p.reject(ESODIUM,ERR_FAILURE);
} else {
p.resolve(result);
}
}

@ReactMethod
public void from_hex(final String cipher, final Promise p) {
byte[] result = this.hexToBin(cipher);
if (result == null) {
p.reject(ESODIUM,ERR_FAILURE);
} else {
p.resolve(new String(result, StandardCharsets.UTF_8));
}
}

private String binToBase64(final byte[] data, final int variant) {
try {
if (data.length <= 0 || variant == 0)
return null;
else {
int encoded_len = Sodium.sodium_base64_encoded_len(data.length, variant);
byte[] encoded = new byte[encoded_len];
Sodium.sodium_bin2base64(encoded, encoded_len, data, data.length, variant);
return new String(encoded, StandardCharsets.UTF_8);
}
}
catch (Throwable t) {
return null;
}
}

private byte[] base64ToBin(String cipher, final int variant) {
try {
byte[] c = cipher.getBytes(StandardCharsets.UTF_8);

if (c.length <= 0 || variant == 0)
return null;

else {
int blen = c.length;
byte[] decoded = new byte[blen];
int[] decoded_len = new int[1];
int result = Sodium.sodium_base642bin(decoded, blen, c, c.length, null, decoded_len, null, variant);
if (result != 0)
return null;
else
return Arrays.copyOfRange(decoded, 0, decoded_len[0]);
}
}
catch (Throwable t) {
return null;
}
}

private String binToHex(final byte[] data) {
try {
if (data.length <= 0)
return null;

else {
int encoded_len = data.length * 2 + 1;
byte[] encoded = new byte[encoded_len];
Sodium.sodium_bin2hex(encoded, encoded_len, data, data.length);
return new String(encoded, StandardCharsets.UTF_8);
}
} catch (Throwable t) {
return null;
}
}

private byte[] hexToBin(String cipher) {
try {
byte[] c = cipher.getBytes(StandardCharsets.UTF_8);

if (c.length <= 0)
return null;

else {
int blen = c.length / 2;
byte[] decoded = new byte[blen];
int[] decoded_len = new int[1];
int result = Sodium.sodium_hex2bin(decoded, blen, c, c.length, null, decoded_len, null);
if (result != 0)
return null;
else
return Arrays.copyOfRange(decoded, 0, decoded_len[0]);
}
} catch (Throwable t) {
return null;
}
}
}
20 changes: 20 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,18 @@ declare module "react-native-sodium" {
algo: number
): Promise<string>;


//
// Utils
//
export function to_base64(message: string, variant: number): Promise<string>;

export function from_base64(cipher: string, variant: number): Promise<string>;

export function to_hex(message: string): Promise<string>;

export function from_hex(cipher: string): Promise<string>;

/**
* Bytes of salt on password hashing, the pwhash* API.
*/
Expand Down Expand Up @@ -370,4 +382,12 @@ declare module "react-native-sodium" {
* Version 1.3 of the Argon2id algorithm, available since libsodium 1.0.13.
*/
export const crypto_pwhash_ALG_ARGON2ID13: number;

export const base64_variant_ORIGINAL: number;

export const base64_variant_VARIANT_ORIGINAL_NO_PADDING: number;

export const base64_variant_VARIANT_URLSAFE: number;

export const base64_variant_VARIANT_URLSAFE_NO_PADDING: number;
}
6 changes: 6 additions & 0 deletions ios/RCTSodium/RCTSodium.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@
- (void) crypto_box_seal:(NSString*)m pk:(NSString*)pk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
- (void) crypto_box_seal_open:(NSString*)c pk:(NSString*)pk sk:(NSString*)sk resolve: (RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;

- (void) to_base64:(NSString*)message variant:(NSNumber*)variant resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
- (void) from_base64:(NSString*)cipher variant:(NSNumber*)variant resolve: (RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;

- (void) to_hex:(NSString*)message resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
- (void) from_hex:(NSString*)cipher resolve: (RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;

@end
Loading