Skip to content
Merged
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
47 changes: 23 additions & 24 deletions .docs/implementation-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,25 @@ These algorithms provide quantum-resistant cryptography.
* ✅ `decipher.setAuthTag(buffer[, encoding])`
* ✅ `decipher.setAutoPadding([autoPadding])`
* ✅ `decipher.update(data[, inputEncoding][, outputEncoding])`
* Class: `DiffieHellman`
* `diffieHellman.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])`
* `diffieHellman.generateKeys([encoding])`
* `diffieHellman.getGenerator([encoding])`
* `diffieHellman.getPrime([encoding])`
* `diffieHellman.getPrivateKey([encoding])`
* `diffieHellman.getPublicKey([encoding])`
* `diffieHellman.setPrivateKey(privateKey[, encoding])`
* `diffieHellman.setPublicKey(publicKey[, encoding])`
* Class: `DiffieHellman`
* `diffieHellman.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])`
* `diffieHellman.generateKeys([encoding])`
* `diffieHellman.getGenerator([encoding])`
* `diffieHellman.getPrime([encoding])`
* `diffieHellman.getPrivateKey([encoding])`
* `diffieHellman.getPublicKey([encoding])`
* `diffieHellman.setPrivateKey(privateKey[, encoding])`
* `diffieHellman.setPublicKey(publicKey[, encoding])`
* ❌ `diffieHellman.verifyError`
* Class: `DiffieHellmanGroup`
* Class: `ECDH`
* Class: `DiffieHellmanGroup`
* Class: `ECDH`
* ❌ static `ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])`
* `ecdh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])`
* `ecdh.generateKeys([encoding[, format]])`
* `ecdh.getPrivateKey([encoding])`
* `ecdh.getPublicKey([encoding][, format])`
* `ecdh.setPrivateKey(privateKey[, encoding])`
* `ecdh.setPublicKey(publicKey[, encoding])`
* `ecdh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])`
* `ecdh.generateKeys([encoding[, format]])`
* `ecdh.getPrivateKey([encoding])`
* `ecdh.getPublicKey([encoding][, format])`
* `ecdh.setPrivateKey(privateKey[, encoding])`
* `ecdh.setPublicKey(publicKey[, encoding])`
* ✅ Class: `Hash`
* ✅ `hash.copy([options])`
* ✅ `hash.digest([encoding])`
Expand Down Expand Up @@ -109,10 +109,10 @@ These algorithms provide quantum-resistant cryptography.
* ✅ `crypto.constants`
* ✅ `crypto.createCipheriv(algorithm, key, iv[, options])`
* ✅ `crypto.createDecipheriv(algorithm, key, iv[, options])`
* `crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])`
* `crypto.createDiffieHellman(primeLength[, generator])`
* `crypto.createDiffieHellmanGroup(name)`
* `crypto.createECDH(curveName)`
* `crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])`
* `crypto.createDiffieHellman(primeLength[, generator])`
* `crypto.getDiffieHellman(groupName)`
* `crypto.createECDH(curveName)`
* ✅ `crypto.createHash(algorithm[, options])`
* ✅ `crypto.createHmac(algorithm, key[, options])`
* ✅ `crypto.createPrivateKey(key)`
Expand All @@ -133,7 +133,6 @@ These algorithms provide quantum-resistant cryptography.
* ❌ `crypto.getCipherInfo(nameOrNid[, options])`
* ✅ `crypto.getCiphers()`
* ❌ `crypto.getCurves()`
* ❌ `crypto.getDiffieHellman(groupName)`
* ❌ `crypto.getFips()`
* ✅ `crypto.getHashes()`
* ✅ `crypto.getRandomValues(typedArray)`
Expand Down Expand Up @@ -165,8 +164,8 @@ These algorithms provide quantum-resistant cryptography.
## `crypto.diffieHellman`
| type | Status |
| --------- | :----: |
| `dh` | |
| `ec` | |
| `dh` | |
| `ec` | |
| `x448` | ✅ |
| `x25519` | ✅ |

Expand Down
203 changes: 118 additions & 85 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2773,7 +2773,7 @@ SPEC CHECKSUMS:
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
hermes-engine: 4f8246b1f6d79f625e0d99472d1f3a71da4d28ca
NitroModules: 1715fe0e22defd9e2cdd48fb5e0dbfd01af54bec
QuickCrypto: a90c6474ef5d724d14cc452d8d23146621e0fb99
QuickCrypto: d2f42ab176e55442e803586b4621d5c21e0f0f19
RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
RCTDeprecation: c4b9e2fd0ab200e3af72b013ed6113187c607077
RCTRequired: e97dd5dafc1db8094e63bc5031e0371f092ae92a
Expand Down
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"react-native-fast-encoder": "0.3.1",
"react-native-nitro-modules": "0.29.1",
"react-native-quick-base64": "2.2.2",
"react-native-quick-crypto": "1.0.7",
"react-native-quick-crypto": "workspace:*",
"react-native-safe-area-context": "5.6.2",
"react-native-screens": "4.18.0",
"react-native-vector-icons": "10.3.0",
Expand Down
59 changes: 59 additions & 0 deletions example/src/benchmarks/dh/dh.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import rnqc from 'react-native-quick-crypto';
// @ts-expect-error crypto-browserify missing types
import browserify from 'crypto-browserify';
import type { BenchFn } from '../../types/benchmarks';
import { Bench } from 'tinybench';

const dh_modp14_genKeys: BenchFn = () => {
const bench = new Bench({
name: 'DH modp14 KeyGen',
time: 200,
iterations: 10, // Cap iterations for slow JS implementations
});

bench
.add('rnqc', () => {
const dh = rnqc.getDiffieHellman('modp14');
dh.generateKeys();
})
.add('browserify', () => {
const dh = browserify.getDiffieHellman('modp14');
dh.generateKeys();
});

bench.warmupTime = 100;
return bench;
};

const dh_modp14_computeSecret: BenchFn = () => {
const bench = new Bench({
name: 'DH modp14 Compute',
time: 200,
iterations: 10,
});

const alice = rnqc.getDiffieHellman('modp14');
alice.generateKeys();
const bob = rnqc.getDiffieHellman('modp14');
bob.generateKeys();
const bobPub = bob.getPublicKey();

const bAlice = browserify.getDiffieHellman('modp14');
bAlice.generateKeys();
const bBob = browserify.getDiffieHellman('modp14');
bBob.generateKeys();
const bBobPub = bBob.getPublicKey();

bench
.add('rnqc', () => {
alice.computeSecret(bobPub);
})
.add('browserify', () => {
bAlice.computeSecret(bBobPub);
});

bench.warmupTime = 100;
return bench;
};

export default [dh_modp14_genKeys, dh_modp14_computeSecret];
57 changes: 57 additions & 0 deletions example/src/benchmarks/ecdh/ecdh.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import rnqc from 'react-native-quick-crypto';
import { p256 } from '@noble/curves/p256';
import type { BenchFn } from '../../types/benchmarks';
import { Bench } from 'tinybench';

const TIME_MS = 1000;

const ecdh_p256_genKeys: BenchFn = () => {
const bench = new Bench({
name: 'ECDH P-256 KeyGen',
time: TIME_MS,
});

bench
.add('rnqc', () => {
const ecdh = rnqc.createECDH('prime256v1');
ecdh.generateKeys();
})
.add('@noble/curves', () => {
// Generate private key and derive public key for fair comparison
const priv = p256.utils.randomPrivateKey();
p256.getPublicKey(priv);
});

bench.warmupTime = 100;
return bench;
};

const ecdh_p256_computeSecret: BenchFn = () => {
const bench = new Bench({
name: 'ECDH P-256 Compute',
time: TIME_MS,
});

const alice = rnqc.createECDH('prime256v1');
alice.generateKeys();
const bob = rnqc.createECDH('prime256v1');
bob.generateKeys();
const bobPub = bob.getPublicKey();

const nobleAlicePriv = p256.utils.randomPrivateKey();
const nobleBobPriv = p256.utils.randomPrivateKey();
const nobleBobPub = p256.getPublicKey(nobleBobPriv);

bench
.add('rnqc', () => {
alice.computeSecret(bobPub);
})
.add('@noble/curves', () => {
p256.getSharedSecret(nobleAlicePriv, nobleBobPub);
});

bench.warmupTime = 100;
return bench;
};

export default [ecdh_p256_genKeys, ecdh_p256_computeSecret];
4 changes: 4 additions & 0 deletions example/src/hooks/useBenchmarks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import hkdf from '../benchmarks/hkdf/hkdf';
import hash from '../benchmarks/hash/hash';
import hmac from '../benchmarks/hmac/hmac';
import pbkdf2 from '../benchmarks/pbkdf2/pbkdf2';
import ecdh from '../benchmarks/ecdh/ecdh';
import dh from '../benchmarks/dh/dh';
import random from '../benchmarks/random/randomBytes';
import scrypt from '../benchmarks/scrypt/scrypt';
import xsalsa20 from '../benchmarks/cipher/xsalsa20';
Expand All @@ -32,6 +34,8 @@ export const useBenchmarks = (): [
newSuites.push(new BenchmarkSuite('hash', hash));
newSuites.push(new BenchmarkSuite('hmac', hmac));
newSuites.push(new BenchmarkSuite('hkdf', hkdf));
newSuites.push(new BenchmarkSuite('ecdh', ecdh));
newSuites.push(new BenchmarkSuite('dh', dh));
newSuites.push(
new BenchmarkSuite('random', random, {
'browserify/randombytes':
Expand Down
2 changes: 2 additions & 0 deletions example/src/hooks/useTestsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import '../tests/keys/public_cipher';
import '../tests/keys/sign_verify_streaming';
import '../tests/keys/sign_verify_oneshot';
import '../tests/pbkdf2/pbkdf2_tests';
import '../tests/ecdh/ecdh_tests';
import '../tests/dh/dh_tests';
import '../tests/random/random_tests';
import '../tests/scrypt/scrypt_tests';
import '../tests/subtle/deriveBits';
Expand Down
91 changes: 91 additions & 0 deletions example/src/tests/dh/dh_tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { test } from '../util';
import { Buffer } from '@craftzdog/react-native-buffer';
import crypto from 'react-native-quick-crypto';
import { assert } from 'chai';

const SUITE = 'dh';

// RFC 3526 MODP Group 14 prime (2048-bit) for testing with explicit prime
const MODP14_PRIME =
'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1' +
'29024E088A67CC74020BBEA63B139B22514A08798E3404DD' +
'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245' +
'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' +
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D' +
'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F' +
'83655D23DCA3AD961C62F356208552BB9ED529077096966D' +
'670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' +
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9' +
'DE2BCBF6955817183995497CEA956AE515D2261898FA0510' +
'15728E5A8AACAA68FFFFFFFFFFFFFFFF';

test(
SUITE,
'should create DiffieHellman with prime and numeric generator',
() => {
const prime = Buffer.from(MODP14_PRIME, 'hex');
const dh = crypto.createDiffieHellman(prime, 2);

assert.strictEqual(dh.getPrime('hex'), prime.toString('hex').toLowerCase());
assert.strictEqual(dh.getGenerator('hex'), '02');
},
);

test(
SUITE,
'should create DiffieHellman with prime and Buffer generator',
() => {
const prime = Buffer.from(MODP14_PRIME, 'hex');
const generator = Buffer.from([2]);
const dh = crypto.createDiffieHellman(prime, generator);

assert.strictEqual(dh.getPrime('hex'), prime.toString('hex').toLowerCase());
assert.strictEqual(
dh.getGenerator('hex'),
generator.toString('hex').toLowerCase(),
);
},
);

test(SUITE, 'should compute shared secret', () => {
const alice = crypto.getDiffieHellman('modp14');
alice.generateKeys();

const bob = crypto.getDiffieHellman('modp14');
bob.generateKeys();

const aliceSecret = alice.computeSecret(bob.getPublicKey());
const bobSecret = bob.computeSecret(alice.getPublicKey());

assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
});

test(SUITE, 'should set keys', () => {
const alice = crypto.getDiffieHellman('modp14');
alice.generateKeys();

const bob = crypto.createDiffieHellman(
alice.getPrime(),
alice.getGenerator(),
);
bob.setPublicKey(alice.getPublicKey());
bob.setPrivateKey(alice.getPrivateKey());

assert.strictEqual(bob.getPublicKey('hex'), alice.getPublicKey('hex'));
assert.strictEqual(bob.getPrivateKey('hex'), alice.getPrivateKey('hex'));
});

test(SUITE, 'should create DiffieHellman from standard group', () => {
const dh = crypto.getDiffieHellman('modp14');
assert.isOk(dh);
const prime = dh.getPrime();
assert.isTrue(Buffer.isBuffer(prime));
assert.strictEqual(prime.length, 256);
assert.strictEqual(dh.getGenerator('hex'), '02');
});

test(SUITE, 'should reject prime length below 2048 bits', () => {
assert.throws(() => {
crypto.createDiffieHellman(512);
}, /prime length must be at least 2048 bits/);
});
Loading
Loading