Skip to content

Commit

Permalink
feat: add hkdf 256
Browse files Browse the repository at this point in the history
  • Loading branch information
nikgraf committed Nov 28, 2023
1 parent fac49dc commit f0b2314
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 2 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ import {
to_string,
ready, // only needed for react-native-web
loadSumoVersion, // only relevant for react-native-web
_unstable_crypto_kdf_hkdf_sha256_BYTES_MAX, // has no counterpart in libsodium-wrappers yet
_unstable_crypto_kdf_hkdf_sha256_BYTES_MIN, // has no counterpart in libsodium-wrappers yet
_unstable_crypto_kdf_hkdf_sha256_KEYBYTES, // has no counterpart in libsodium-wrappers yet
_unstable_crypto_kdf_hkdf_sha256_extract, // has no counterpart in libsodium-wrappers yet
_unstable_crypto_kdf_hkdf_sha256_expand, // has no counterpart in libsodium-wrappers yet
} from 'react-native-libsodium';

// ...
Expand Down
78 changes: 78 additions & 0 deletions cpp/react-native-libsodium.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ namespace ReactNativeLibsodium
jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_sign_SEEDBYTES", static_cast<int>(crypto_sign_SEEDBYTES));
jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_auth_BYTES", static_cast<int>(crypto_auth_BYTES));
jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_auth_KEYBYTES", static_cast<int>(crypto_auth_KEYBYTES));
jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_kdf_hkdf_sha256_BYTES_MAX", static_cast<int>(crypto_kdf_hkdf_sha256_BYTES_MAX));
jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_kdf_hkdf_sha256_BYTES_MIN", static_cast<int>(crypto_kdf_hkdf_sha256_BYTES_MIN));
jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_kdf_hkdf_sha256_KEYBYTES", static_cast<int>(crypto_kdf_hkdf_sha256_KEYBYTES));

auto jsi_from_base64_to_arraybuffer = jsi::Function::createFromHostFunction(
jsiRuntime,
Expand Down Expand Up @@ -1341,5 +1344,80 @@ namespace ReactNativeLibsodium
});

jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_generichash", std::move(jsi_crypto_generichash));

auto jsi_crypto_kdf_hkdf_sha256_extract = jsi::Function::createFromHostFunction(
jsiRuntime,
jsi::PropNameID::forUtf8(jsiRuntime, "jsi_crypto_kdf_hkdf_sha256_extract"),
2,
[](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value
{
const std::string functionName = "jsi_crypto_kdf_hkdf_sha256_extract";

std::string keyArgumentName = "key";
unsigned int keyArgumentPosition = 0;
validateIsArrayBuffer(functionName, runtime, arguments[keyArgumentPosition], keyArgumentName, true);

std::string saltArgumentName = "salt";
unsigned int saltArgumentPosition = 1;
validateIsArrayBuffer(functionName, runtime, arguments[saltArgumentPosition], saltArgumentName, true);

std::vector<uint8_t> subkey(crypto_kdf_hkdf_sha256_KEYBYTES);
int result = -1;

auto keyArrayBuffer = arguments[keyArgumentPosition].asObject(runtime).getArrayBuffer(runtime);
auto saltArrayBuffer = arguments[saltArgumentPosition].asObject(runtime).getArrayBuffer(runtime);

result = crypto_kdf_hkdf_sha256_extract(
subkey.data(),
saltArrayBuffer.data(runtime),
saltArrayBuffer.length(runtime),
keyArrayBuffer.data(runtime),
keyArrayBuffer.length(runtime));

throwOnBadResult(functionName, runtime, result);
return arrayBufferAsObject(runtime, subkey);
});

jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_kdf_hkdf_sha256_extract", std::move(jsi_crypto_kdf_hkdf_sha256_extract));

auto jsi_crypto_kdf_hkdf_sha256_expand = jsi::Function::createFromHostFunction(
jsiRuntime,
jsi::PropNameID::forUtf8(jsiRuntime, "jsi_crypto_kdf_hkdf_sha256_expand"),
3,
[](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value
{
const std::string functionName = "jsi_crypto_kdf_hkdf_sha256_expand";

std::string keyArgumentName = "key";
unsigned int keyArgumentPosition = 0;
validateIsArrayBuffer(functionName, runtime, arguments[keyArgumentPosition], keyArgumentName, true);

std::string infoArgumentName = "info";
unsigned int infoArgumentPosition = 1;
validateIsString(functionName, runtime, arguments[infoArgumentPosition], infoArgumentName, true);

std::string subkeyLengthArgumentName = "subkeyLength";
unsigned int subkeyLengthArgumentPosition = 1;
validateIsNumber(functionName, runtime, arguments[subkeyLengthArgumentPosition], subkeyLengthArgumentName, true);

std::string info = arguments[infoArgumentPosition].asString(runtime).utf8(runtime);
int subkeyLength = arguments[subkeyLengthArgumentPosition].asNumber();
std::vector<uint8_t> subkey(subkeyLength);
int result = -1;

auto keyArrayBuffer = arguments[keyArgumentPosition].asObject(runtime).getArrayBuffer(runtime);

result = crypto_kdf_hkdf_sha256_expand(
subkey.data(),
subkey.size(),
reinterpret_cast<const char *>(info.data()),
info.length(),
keyArrayBuffer.length(runtime));

throwOnBadResult(functionName, runtime, result);
return arrayBufferAsObject(runtime, subkey);
});

jsiRuntime.global().setProperty(jsiRuntime, "jsi_crypto_kdf_hkdf_sha256_expand", std::move(jsi_crypto_kdf_hkdf_sha256_expand));
}
} // namespace ReactNativeLibsodium
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ PODS:
- React-jsinspector (0.71.6)
- React-logger (0.71.6):
- glog
- react-native-libsodium (0.7.0):
- react-native-libsodium (1.1.2):
- React-Core
- React-perflogger (0.71.6)
- React-RCTActionSheet (0.71.6):
Expand Down Expand Up @@ -606,7 +606,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 7894956638ff3e00819dd3f9f6f4a84da38f2409
React-jsinspector: d5ce2ef3eb8fd30c28389d0bc577918c70821bd6
React-logger: 9332c3e7b4ef007a0211c0a9868253aac3e1da82
react-native-libsodium: 532974631ce56ac3309c9e40040582982d624cc7
react-native-libsodium: 070bd408c7ccf5ca931077aeb4277f0929299bc1
React-perflogger: 43392072a5b867a504e2b4857606f8fc5a403d7f
React-RCTActionSheet: c7b67c125bebeda9fb19fc7b200d85cb9d6899c4
React-RCTAnimation: c2de79906f607986633a7114bee44854e4c7e2f5
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
]
},
"dependencies": {
"@noble/hashes": "^1.3.2",
"@types/libsodium-wrappers": "^0.7.13",
"@types/libsodium-wrappers-sumo": "^0.7.8",
"libsodium-wrappers": "^0.7.13",
Expand Down
44 changes: 44 additions & 0 deletions src/lib.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ declare global {
var jsi_crypto_pwhash_MEMLIMIT_INTERACTIVE: number;
var jsi_crypto_pwhash_BYTES_MIN: number;
var jsi_crypto_pwhash_BYTES_MAX: number;
var jsi_crypto_kdf_hkdf_sha256_BYTES_MAX: number;
var jsi_crypto_kdf_hkdf_sha256_BYTES_MIN: number;
var jsi_crypto_kdf_hkdf_sha256_KEYBYTES: number;

function jsi_crypto_auth(
message: string | ArrayBuffer,
Expand Down Expand Up @@ -146,6 +149,21 @@ declare global {
public_nonce: ArrayBuffer,
key: ArrayBuffer
): ArrayBuffer;
function jsi_crypto_aead_xchacha20poly1305_ietf_decrypt(
ciphertext: string | ArrayBuffer,
additionalData: string,
public_nonce: ArrayBuffer,
key: ArrayBuffer
): ArrayBuffer;
function jsi_crypto_kdf_hkdf_sha256_extract(
key: ArrayBuffer,
salt: ArrayBuffer
): ArrayBuffer;
function jsi_crypto_kdf_hkdf_sha256_expand(
key: ArrayBuffer,
info: string,
length: number
): ArrayBuffer;
}

export const crypto_auth_BYTES = global.jsi_crypto_auth_BYTES;
Expand Down Expand Up @@ -182,6 +200,12 @@ export const crypto_pwhash_MEMLIMIT_INTERACTIVE =
global.jsi_crypto_pwhash_MEMLIMIT_INTERACTIVE;
export const crypto_pwhash_BYTES_MIN = global.jsi_crypto_pwhash_BYTES_MIN;
export const crypto_pwhash_BYTES_MAX = global.jsi_crypto_pwhash_BYTES_MAX;
export const _unstable_crypto_kdf_hkdf_sha256_BYTES_MAX =
global.jsi_crypto_kdf_hkdf_sha256_BYTES_MAX;
export const _unstable_crypto_kdf_hkdf_sha256_BYTES_MIN =
global.jsi_crypto_kdf_hkdf_sha256_BYTES_MIN;
export const _unstable_crypto_kdf_hkdf_sha256_KEYBYTES =
global.jsi_crypto_kdf_hkdf_sha256_KEYBYTES;

export const from_base64 = (
input: string,
Expand Down Expand Up @@ -692,6 +716,21 @@ export function crypto_aead_xchacha20poly1305_ietf_decrypt(
return convertToOutputFormat(result, outputFormat);
}

export function _unstable_crypto_kdf_hkdf_sha256_extract(
key: Uint8Array,
salt: Uint8Array
) {
return global.jsi_crypto_kdf_hkdf_sha256_extract(key.buffer, salt.buffer);
}

export function _unstable_crypto_kdf_hkdf_sha256_expand(
key: Uint8Array,
info: string,
length: number
) {
return global.jsi_crypto_kdf_hkdf_sha256_expand(key.buffer, info, length);
}

// add no-op ready to match the libsodium-wrappers API
export const ready: Promise<void> = new Promise((resolve) => resolve());

Expand Down Expand Up @@ -748,4 +787,9 @@ export default {
to_base64,
to_hex,
to_string,
_unstable_crypto_kdf_hkdf_sha256_BYTES_MAX,
_unstable_crypto_kdf_hkdf_sha256_BYTES_MIN,
_unstable_crypto_kdf_hkdf_sha256_KEYBYTES,
_unstable_crypto_kdf_hkdf_sha256_extract,
_unstable_crypto_kdf_hkdf_sha256_expand,
};
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1754,6 +1754,11 @@
dependencies:
eslint-scope "5.1.1"

"@noble/hashes@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==

"@nodelib/[email protected]":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
Expand Down

0 comments on commit f0b2314

Please sign in to comment.