Skip to content

Commit 8832302

Browse files
authored
fix: undo keccak256, update createHash to modern API (#779)
1 parent 1b24106 commit 8832302

File tree

11 files changed

+290
-235
lines changed

11 files changed

+290
-235
lines changed

bun.lock

Lines changed: 259 additions & 157 deletions
Large diffs are not rendered by default.

docs/test_suite_results_ios.png

-632 Bytes
Loading

example/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
"@noble/curves": "^1.7.0",
2727
"@noble/hashes": "^1.5.0",
2828
"@react-navigation/bottom-tabs": "^6.6.1",
29-
"@react-navigation/native": "6.1.18",
30-
"@react-navigation/native-stack": "7.3.25",
29+
"@react-navigation/native": "^6.1.18",
30+
"@react-navigation/native-stack": "^6.11.0",
3131
"buffer": "6.0.3",
3232
"chai": "<5.0.0",
3333
"crypto-browserify": "^3.12.0",

example/src/tests/hash/hash_tests.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
createHash,
99
getHashes,
1010
type Encoding,
11-
keccak256,
1211
} from 'react-native-quick-crypto';
1312
import { expect } from 'chai';
1413
import { test } from '../util';
@@ -45,21 +44,23 @@ test(SUITE, 'check openssl version', () => {
4544
}).to.not.throw();
4645
});
4746

48-
test(SUITE, 'keccak256 function using provider-aware API', () => {
47+
test(SUITE, 'KECCAK-256 using createHash with provider-aware API', () => {
4948
// Test with a simple string
50-
const result1 = keccak256('test');
49+
const result1 = createHash('KECCAK-256').update('test').digest();
5150
expect(result1.toString('hex')).to.equal(
5251
'9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658',
5352
);
5453

5554
// Test with empty string
56-
const result2 = keccak256('');
55+
const result2 = createHash('KECCAK-256').update('').digest();
5756
expect(result2.toString('hex')).to.equal(
5857
'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470',
5958
);
6059

6160
// Test with Buffer
62-
const result3 = keccak256(Buffer.from('hello world'));
61+
const result3 = createHash('KECCAK-256')
62+
.update(Buffer.from('hello world'))
63+
.digest();
6364
expect(result3.toString('hex')).to.equal(
6465
'47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad',
6566
);

packages/react-native-quick-crypto/cpp/hash/HybridHash.cpp

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ HybridHash::~HybridHash() {
1616
EVP_MD_CTX_free(ctx);
1717
ctx = nullptr;
1818
}
19+
if (md && md_fetched) {
20+
EVP_MD_free(md);
21+
md = nullptr;
22+
}
1923
}
2024

2125
void HybridHash::createHash(const std::string& hashAlgorithmArg, const std::optional<double> outputLengthArg) {
@@ -28,18 +32,24 @@ void HybridHash::createHash(const std::string& hashAlgorithmArg, const std::opti
2832
throw std::runtime_error("Failed to create hash context: " + std::to_string(ERR_get_error()));
2933
}
3034

31-
// Get the message digest by name
32-
md = EVP_get_digestbyname(algorithm.c_str());
35+
// Fetch the message digest using modern provider-based API
36+
md = EVP_MD_fetch(nullptr, algorithm.c_str(), nullptr);
3337
if (!md) {
3438
EVP_MD_CTX_free(ctx);
3539
ctx = nullptr;
3640
throw std::runtime_error("Unknown hash algorithm: " + algorithm);
3741
}
42+
md_fetched = true;
3843

3944
// Initialize the digest
4045
if (EVP_DigestInit_ex(ctx, md, nullptr) != 1) {
4146
EVP_MD_CTX_free(ctx);
4247
ctx = nullptr;
48+
if (md_fetched) {
49+
EVP_MD_free(md);
50+
md = nullptr;
51+
md_fetched = false;
52+
}
4353
throw std::runtime_error("Failed to initialize hash digest: " + std::to_string(ERR_get_error()));
4454
}
4555
}
@@ -107,7 +117,7 @@ std::shared_ptr<margelo::nitro::crypto::HybridHashSpec> HybridHash::copy(const s
107117
throw std::runtime_error("Failed to copy hash context: " + std::to_string(ERR_get_error()));
108118
}
109119

110-
return std::make_shared<HybridHash>(newCtx, md, algorithm, outputLengthArg);
120+
return std::make_shared<HybridHash>(newCtx, md, algorithm, outputLengthArg, false);
111121
}
112122

113123
std::vector<std::string> HybridHash::getSupportedHashAlgorithms() {
@@ -144,6 +154,11 @@ void HybridHash::setParams() {
144154
if (EVP_MD_CTX_set_params(ctx, params) != 1) {
145155
EVP_MD_CTX_free(ctx);
146156
ctx = nullptr;
157+
if (md && md_fetched) {
158+
EVP_MD_free(md);
159+
md = nullptr;
160+
md_fetched = false;
161+
}
147162
throw std::runtime_error("Failed to set XOF length (outputLength) parameter: " + std::to_string(ERR_get_error()));
148163
}
149164
}
@@ -153,40 +168,4 @@ std::string HybridHash::getOpenSSLVersion() {
153168
return OpenSSL_version(OPENSSL_VERSION);
154169
}
155170

156-
std::shared_ptr<ArrayBuffer> HybridHash::keccak256(const std::shared_ptr<ArrayBuffer>& data) {
157-
// 1. Obtain the Keccak-256 message-digest implementation from any loaded provider.
158-
const EVP_MD* md = EVP_MD_fetch(nullptr, "KECCAK-256", nullptr);
159-
if (!md) {
160-
throw std::runtime_error("KECCAK-256 digest not available in the current OpenSSL build (provider not loaded?)");
161-
}
162-
163-
// 2. Create and initialise a digest context.
164-
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
165-
if (!ctx) {
166-
throw std::runtime_error("Failed to allocate EVP_MD_CTX");
167-
}
168-
auto ctx_guard = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(ctx, &EVP_MD_CTX_free);
169-
170-
if (EVP_DigestInit_ex(ctx, md, nullptr) != 1) {
171-
throw std::runtime_error("Failed to initialise KECCAK-256 digest");
172-
}
173-
174-
// 3. Feed the data.
175-
if (EVP_DigestUpdate(ctx, data->data(), data->size()) != 1) {
176-
throw std::runtime_error("Failed to update KECCAK-256 digest");
177-
}
178-
179-
// 4. Finalise and collect the output.
180-
unsigned char hash[EVP_MAX_MD_SIZE];
181-
unsigned int out_len = 0;
182-
if (EVP_DigestFinal_ex(ctx, hash, &out_len) != 1) {
183-
throw std::runtime_error("Failed to finalise KECCAK-256 digest");
184-
}
185-
186-
// 5. Move the result into a managed ArrayBuffer.
187-
unsigned char* out_buf = new unsigned char[out_len];
188-
std::memcpy(out_buf, hash, out_len);
189-
return std::make_shared<NativeArrayBuffer>(out_buf, out_len, [out_buf]() { delete[] out_buf; });
190-
}
191-
192171
} // namespace margelo::nitro::crypto

packages/react-native-quick-crypto/cpp/hash/HybridHash.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ using namespace facebook;
1414
class HybridHash : public HybridHashSpec {
1515
public:
1616
HybridHash() : HybridObject(TAG) {}
17-
HybridHash(EVP_MD_CTX* ctx, const EVP_MD* md, const std::string& algorithm, const std::optional<double> outputLength)
18-
: HybridObject(TAG), ctx(ctx), md(md), algorithm(algorithm), outputLength(outputLength) {}
17+
HybridHash(EVP_MD_CTX* ctx, EVP_MD* md, const std::string& algorithm, const std::optional<double> outputLength, bool md_fetched = false)
18+
: HybridObject(TAG), ctx(ctx), md(md), md_fetched(md_fetched), algorithm(algorithm), outputLength(outputLength) {}
1919
~HybridHash();
2020

2121
public:
@@ -26,7 +26,6 @@ class HybridHash : public HybridHashSpec {
2626
std::shared_ptr<margelo::nitro::crypto::HybridHashSpec> copy(const std::optional<double> outputLength) override;
2727
std::vector<std::string> getSupportedHashAlgorithms() override;
2828
std::string getOpenSSLVersion() override;
29-
std::shared_ptr<ArrayBuffer> keccak256(const std::shared_ptr<ArrayBuffer>& data) override;
3029

3130
private:
3231
// Methods
@@ -35,7 +34,8 @@ class HybridHash : public HybridHashSpec {
3534
private:
3635
// Properties
3736
EVP_MD_CTX* ctx = nullptr;
38-
const EVP_MD* md = nullptr;
37+
EVP_MD* md = nullptr;
38+
bool md_fetched = false;
3939
std::string algorithm = "";
4040
std::optional<double> outputLength = std::nullopt;
4141
};

packages/react-native-quick-crypto/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Umbrella.hpp

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridHashSpec.cpp

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-quick-crypto/nitrogen/generated/shared/c++/HybridHashSpec.hpp

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/react-native-quick-crypto/src/hash.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,12 @@ class HashUtils {
1010
public static getSupportedHashAlgorithms(): string[] {
1111
return this.native.getSupportedHashAlgorithms();
1212
}
13-
public static keccak256(data: BinaryLike): Buffer {
14-
const nativeDigest = this.native.keccak256(
15-
binaryLikeToArrayBuffer(data, 'utf8'),
16-
);
17-
return Buffer.from(nativeDigest);
18-
}
1913
}
2014

2115
export function getHashes() {
2216
return HashUtils.getSupportedHashAlgorithms();
2317
}
2418

25-
export function keccak256(data: BinaryLike): Buffer {
26-
return HashUtils.keccak256(data);
27-
}
28-
2919
interface HashOptions extends TransformOptions {
3020
/**
3121
* For XOF hash functions such as `shake256`, the
@@ -175,19 +165,6 @@ class Hash extends Stream.Transform {
175165
return this.native.getOpenSSLVersion();
176166
}
177167

178-
/**
179-
* Computes KECCAK-256 hash of the provided data using OpenSSL's provider-aware API
180-
* @since v1.0.0
181-
* @param data The data to hash
182-
* @returns Buffer containing the KECCAK-256 hash
183-
*/
184-
keccak256(data: BinaryLike): Buffer {
185-
const nativeDigest = this.native.keccak256(
186-
binaryLikeToArrayBuffer(data, 'utf8'),
187-
);
188-
return Buffer.from(nativeDigest);
189-
}
190-
191168
// stream interface
192169
_transform(
193170
chunk: BinaryLike,
@@ -236,5 +213,4 @@ export function createHash(algorithm: string, options?: HashOptions): Hash {
236213
export const hashExports = {
237214
createHash,
238215
getHashes,
239-
keccak256,
240216
};

0 commit comments

Comments
 (0)