From 1f454ed66764f709ecf704e664745af8a59a16be Mon Sep 17 00:00:00 2001 From: Diogo de Azevedo Silva Date: Fri, 26 Nov 2021 19:11:46 -0300 Subject: [PATCH] feat: crypto_box_seed_keypair to derive key pair --- android/src/main/cpp/sodium-jni.c | 26 ++++++++++++ .../java/org/libsodium/jni/SodiumJNI.java | 5 +++ .../org/libsodium/rn/RCTSodiumModule.java | 26 ++++++++++++ index.d.ts | 41 +++++++++++++++++-- ios/RCTSodium/RCTSodium.h | 1 + ios/RCTSodium/RCTSodium.m | 19 +++++++++ 6 files changed, 115 insertions(+), 3 deletions(-) diff --git a/android/src/main/cpp/sodium-jni.c b/android/src/main/cpp/sodium-jni.c index e29767b..227f6cc 100644 --- a/android/src/main/cpp/sodium-jni.c +++ b/android/src/main/cpp/sodium-jni.c @@ -199,6 +199,16 @@ JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1box_1keypair(JNI return (jint)result; } +JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1box_1seed_1keypair(JNIEnv *jenv, jclass jcls, jbyteArray j_pk, jbyteArray j_sk, jbyteArray j_seed) { + unsigned char *pk = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_pk, 0); + unsigned char *sk = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_sk, 0); + unsigned char *seed = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_seed, 0); + int result = (int)crypto_box_seed_keypair(pk, sk, seed); + (*jenv)->ReleaseByteArrayElements(jenv, j_pk, (jbyte *) pk, 0); + (*jenv)->ReleaseByteArrayElements(jenv, j_sk, (jbyte *) sk, 0); + return (jint)result; +} + JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1box_1easy(JNIEnv *jenv, jclass jcls, jbyteArray j_c, jbyteArray j_m, jlong j_mlen, jbyteArray j_n, jbyteArray j_pk, jbyteArray j_sk) { unsigned char *c = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_c, 0); unsigned char *m = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, j_m, 0); @@ -347,6 +357,22 @@ JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1pwhash_1algo_1ar return (jint) crypto_pwhash_ALG_ARGON2ID13; } +JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1pwhash_1bytes_1max(JNIEnv *jenv, jclass jcls) { + return (jint) crypto_pwhash_BYTES_MAX; +} + +JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1pwhash_1bytes_1min(JNIEnv *jenv, jclass jcls) { + return (jint) crypto_pwhash_BYTES_MIN; +} + +JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1pwhash_1passwd_1max(JNIEnv *jenv, jclass jcls) { + return (jint) crypto_pwhash_PASSWD_MAX; +} + +JNIEXPORT jint JNICALL Java_org_libsodium_jni_SodiumJNI_crypto_1pwhash_1passwd_1min(JNIEnv *jenv, jclass jcls) { + return (jint) crypto_pwhash_PASSWD_MIN; +} + /* ***************************************************************************** * Advanced - Point*scalar multiplicaton * ***************************************************************************** diff --git a/android/src/main/java/org/libsodium/jni/SodiumJNI.java b/android/src/main/java/org/libsodium/jni/SodiumJNI.java index 1fbe6af..fa7ee57 100644 --- a/android/src/main/java/org/libsodium/jni/SodiumJNI.java +++ b/android/src/main/java/org/libsodium/jni/SodiumJNI.java @@ -33,6 +33,7 @@ public class SodiumJNI { public final static native int crypto_box_boxzerobytes(); public final static native int crypto_box_sealbytes(); public final static native int crypto_box_keypair(byte[] pk, byte[] sk); + public final static native int crypto_box_seed_keypair(byte[] pk, byte[] sk, final byte[] seed); public final static native int crypto_box_easy(byte[] c, final byte[] m, final long mlen, final byte[] n, final byte[] pk, final byte[] sk); public final static native int crypto_box_open_easy(byte[] m, final byte[] c, final long clen, final byte[] n, final byte[] pk, final byte[] sk); @@ -54,6 +55,10 @@ public class SodiumJNI { public final static native int crypto_pwhash_algo_default(); public final static native int crypto_pwhash_algo_argon2i13(); public final static native int crypto_pwhash_algo_argon2id13(); + public final static native int crypto_pwhash_bytes_max(); + public final static native int crypto_pwhash_bytes_min(); + public final static native int crypto_pwhash_passwd_max(); + public final static native int crypto_pwhash_passwd_min(); public final static native int crypto_scalarmult_bytes(); public final static native int crypto_scalarmult_scalarbytes(); diff --git a/android/src/main/java/org/libsodium/rn/RCTSodiumModule.java b/android/src/main/java/org/libsodium/rn/RCTSodiumModule.java index 54b1965..fb2950e 100644 --- a/android/src/main/java/org/libsodium/rn/RCTSodiumModule.java +++ b/android/src/main/java/org/libsodium/rn/RCTSodiumModule.java @@ -80,6 +80,10 @@ public Map getConstants() { constants.put("crypto_pwhash_ALG_DEFAULT", Sodium.crypto_pwhash_algo_default()); constants.put("crypto_pwhash_ALG_ARGON2I13", Sodium.crypto_pwhash_algo_argon2i13()); constants.put("crypto_pwhash_ALG_ARGON2ID13", Sodium.crypto_pwhash_algo_argon2id13()); + constants.put("crypto_pwhash_BYTES_MAX", Sodium.crypto_pwhash_bytes_max()); + constants.put("crypto_pwhash_BYTES_MIN", Sodium.crypto_pwhash_bytes_min()); + constants.put("crypto_pwhash_PASSWD_MAX", Sodium.crypto_pwhash_passwd_max()); + constants.put("crypto_pwhash_PASSWD_MIN", Sodium.crypto_pwhash_passwd_min()); constants.put("crypto_scalarmult_BYTES", Sodium.crypto_scalarmult_bytes()); constants.put("crypto_scalarmult_SCALARBYTES", Sodium.crypto_scalarmult_scalarbytes()); @@ -279,6 +283,28 @@ public void crypto_box_keypair(final Promise p){ p.reject(ESODIUM,ERR_FAILURE,t); } } + + @ReactMethod + public void crypto_box_seed_keypair(final String seed, final Promise p){ + try { + byte[] pk = new byte[Sodium.crypto_box_publickeybytes()]; + byte[] sk = new byte[Sodium.crypto_box_secretkeybytes()]; + byte[] seedb = Base64.decode(seed, Base64.NO_WRAP); + if (seedb.length != Sodium.crypto_box_seedbytes()) + p.reject(ESODIUM,ERR_BAD_SEED); + else if (Sodium.crypto_box_seed_keypair(pk, sk, seedb) != 0) + p.reject(ESODIUM,ERR_FAILURE); + else { + WritableNativeMap result = new WritableNativeMap(); + result.putString("pk",Base64.encodeToString(pk,Base64.NO_WRAP)); + result.putString("sk",Base64.encodeToString(sk,Base64.NO_WRAP)); + p.resolve(result); + } + } + catch (Throwable t) { + p.reject(ESODIUM,ERR_FAILURE,t); + } + } @ReactMethod public void crypto_box_easy(final String m, final String n, final String pk, final String sk, final Promise p) { diff --git a/index.d.ts b/index.d.ts index be6fade..78722a0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -125,6 +125,16 @@ declare module "react-native-sodium" { */ export const crypto_box_SECRETKEYBYTES: number; + /** + * Bytes of shared key computes by an public key and a secret key on public-key cryptography, authenticated encryption + */ + export const crypto_box_BEFORENMBYTES: number; + + /** + * Bytes of seed + */ + export const crypto_box_SEEDBYTES: number; + /** * Bytes of nonce on public-key cryptography, authenticated encryption */ @@ -136,12 +146,12 @@ declare module "react-native-sodium" { export const crypto_box_MACBYTES: number; /** - * + * Bytes internally used to prepended zeros */ export const crypto_box_ZEROBYTES: number; /** - * + * Bytes used on messages on public-key cryptography, sealed boxes */ export const crypto_box_SEALBYTES: number; @@ -150,6 +160,11 @@ declare module "react-native-sodium" { */ export function crypto_box_keypair(): Promise<{ sk: string; pk: string }>; + /** + * Deterministically derive from a single key seed, a secret key (sk) and a corresponding public key (pk). + */ + export function crypto_box_seed_keypair(seed: string): Promise<{ sk: string; pk: string }>; + /** * Encrypts a message, with a recipient's public key, a sender's secret key and a nonce. */ @@ -360,7 +375,7 @@ declare module "react-native-sodium" { export const crypto_pwhash_MEMLIMIT_MAX: number; /** - * Tthe currently recommended algorithm, which can change from one version of libsodium to another. + * The currently recommended algorithm, which can change from one version of libsodium to another. * On password hashing, the pwhash* API. */ export const crypto_pwhash_ALG_DEFAULT: number; @@ -374,4 +389,24 @@ 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; + + /** + * Max bytes of out key on password hashing, the pwhash* API. + */ + export const crypto_pwhash_BYTES_MAX: number; + + /** + * Min bytes of out key on password hashing, the pwhash* API. + */ + export const crypto_pwhash_BYTES_MIN: number; + + /** + * Max bytes of password on password hashing, the pwhash* API. + */ + export const crypto_pwhash_PASSWD_MAX: number; + + /** + * Min bytes of password on password hashing, the pwhash* API. + */ + export const crypto_pwhash_PASSWD_MIN: number; } diff --git a/ios/RCTSodium/RCTSodium.h b/ios/RCTSodium/RCTSodium.h index 969692e..eb2d798 100644 --- a/ios/RCTSodium/RCTSodium.h +++ b/ios/RCTSodium/RCTSodium.h @@ -26,6 +26,7 @@ - (void) crypto_auth_verify:(NSString*)h in:(NSString*)in k:(NSString*)k resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; - (void) crypto_box_keypair:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void) crypto_box_seed_keypair:(NSString*)seed resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; - (void) crypto_box_beforenm:(NSString*)pk sk:(NSString*)sk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; - (void) crypto_box_easy:(NSString*)m n:(NSString*)n pk:(NSString*)pk sk:(NSString*)sk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; diff --git a/ios/RCTSodium/RCTSodium.m b/ios/RCTSodium/RCTSodium.m index 5599c58..0a5f6a5 100644 --- a/ios/RCTSodium/RCTSodium.m +++ b/ios/RCTSodium/RCTSodium.m @@ -67,6 +67,10 @@ - (NSDictionary *)constantsToExport @"crypto_pwhash_ALG_DEFAULT":@crypto_pwhash_ALG_DEFAULT, @"crypto_pwhash_ALG_ARGON2I13":@crypto_pwhash_ALG_ARGON2I13, @"crypto_pwhash_ALG_ARGON2ID13":@crypto_pwhash_ALG_ARGON2ID13, + @"crypto_pwhash_BYTES_MAX":@crypto_pwhash_BYTES_MAX, + @"crypto_pwhash_BYTES_MIN":@crypto_pwhash_BYTES_MIN, + @"crypto_pwhash_PASSWD_MAX":@crypto_pwhash_PASSWD_MAX, + @"crypto_pwhash_PASSWD_MIN":@crypto_pwhash_PASSWD_MIN, @"crypto_scalarmult_BYTES":@crypto_scalarmult_BYTES, @"crypto_scalarmult_SCALARBYTES":@crypto_scalarmult_SCALARBYTES }; @@ -226,6 +230,21 @@ + (BOOL)requiresMainQueueSetup reject(ESODIUM,ERR_FAILURE,nil); } +RCT_EXPORT_METHOD(crypto_box_seed_keypair:(NSString*)seed resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +{ + unsigned char pk[crypto_box_PUBLICKEYBYTES],sk[crypto_box_SECRETKEYBYTES]; + const NSData *dseed = [[NSData alloc] initWithBase64EncodedString:seed options:0]; + if (!dseed) reject(ESODIUM,ERR_FAILURE,nil); + else if (dseed.length != crypto_box_SEEDBYTES) reject(ESODIUM,ERR_BAD_SEED,nil); + else if (crypto_box_seed_keypair(pk,sk,dseed) == 0) { + NSString *pk64 = [[NSData dataWithBytesNoCopy:pk length:sizeof(pk) freeWhenDone:NO] base64EncodedStringWithOptions:0]; + NSString *sk64 = [[NSData dataWithBytesNoCopy:sk length:sizeof(sk) freeWhenDone:NO] base64EncodedStringWithOptions:0]; + if (!pk64 || !sk64) reject(ESODIUM,ERR_FAILURE,nil); else resolve(@{@"pk":pk64, @"sk":sk64}); + } + else + reject(ESODIUM,ERR_FAILURE,nil); +} + RCT_EXPORT_METHOD(crypto_box_easy:(NSString*)m n:(NSString*)n pk:(NSString*)pk sk:(NSString*)sk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { const NSData *dm = [[NSData alloc] initWithBase64EncodedString:m options:0];