Skip to content

Commit c7f06ba

Browse files
author
Ernie Turner
committedSep 27, 2018
Initial open source release
0 parents  commit c7f06ba

26 files changed

+5937
-0
lines changed
 

‎.gitignore

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
**/node_modules
2+
**/.DS_Store
3+
.vscode
4+
.babelrc
5+
npm-debug.log
6+
yarn-error.log
7+
native/target
8+
native/artifacts.json
9+
native/index.node
10+
Cargo.lock
11+
dist/*

‎.travis.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
sudo: false
2+
language: rust
3+
rust:
4+
- 1.29.0
5+
branches:
6+
only:
7+
- master
8+
notifications:
9+
email:
10+
on_success: change
11+
on_failure: always
12+
cache:
13+
yarn: true
14+
cargo: true
15+
directories:
16+
- node_modules
17+
before_script:
18+
- rustup component add rustfmt-preview
19+
script:
20+
- pushd native/ && cargo fmt -- --check && popd
21+
- yarn
22+
- yarn run compile
23+
- yarn test

‎LICENSE

+661
Large diffs are not rendered by default.

‎README.md

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Recrypt Node Binding
2+
3+
[![Build Status](https://travis-ci.com/IronCoreLabs/recrypt-node-binding.svg?branch=master)](https://travis-ci.com/IronCoreLabs/recrypt-node-binding)
4+
5+
Bindings to be able to use [Recrypt Rust](https://github.com/IronCoreLabs/recrypt-rs) from NodeJS code. Improves the performance of Recrypt operations by using native code.
6+
7+
## NodeJS Support
8+
9+
| Node 8 | Node 10 |
10+
| ------ | ------- |
11+
|||
12+
13+
## Details
14+
15+
This library uses the [Neon Bindings](https://www.neon-bindings.com) toolchain to compile the [Recrypt Rust](https://github.com/IronCoreLabs/recrypt-rs) library into a binary NodeJS file that can be used from Node applications. The Neon Bindings provide a way to write a shim which converts data in/out of the [Recrypt Rust](https://github.com/IronCoreLabs/recrypt-rs) code. The resulting binary Node file can then be imported into a NodeJS module just like any other dependency.
16+
17+
## Getting Started
18+
19+
In order to build the binary Node file for Recrypt, you'll need the dependencies specified on the [Neon Bindings site](https://guides.neon-bindings.com/getting-started/). Follow their getting started directions and install Rust and the Node Build Tools. The Neon CLI is already installed as a dependecy of this project so you don't have to install that as a global dependency.
20+
21+
Once all of those dependencies are installed, the following can be run.
22+
23+
```
24+
npm run compile
25+
```
26+
or
27+
```
28+
yarn run compile
29+
```
30+
31+
This will produce an `index.node` file within the `native` directory. This file can then be included within a NodeJS file by simply requiring the file, e.g.
32+
33+
```
34+
const recrypt = require('index.node');
35+
```
36+
37+
## Types
38+
39+
This library contains [TypeScript definitions](index.d.ts) file which shows the available classes and methods.
40+
41+
## Benchmarks
42+
43+
+ From this repos root, run `npm i` or `yarn`.
44+
+ Run `npm/yarn run compile` to compile the Rust source into a `native/index.node` module.
45+
+ Run `npm/yarn run benchmark`.
46+
47+
## Unit Tests
48+
49+
+ From this repos root, run `npm i` or `yarn`.
50+
+ Run `npm/yarn run compile` to compile the Rust source into a `native/index.node` module.
51+
+ Run `npm/yarn run test`.
52+
53+
## Examples
54+
55+
The following examples show how to use this library from a NodeJS application
56+
57+
#### Basic Encrypt/Decrypt Example
58+
```js
59+
const assert = require("assert");
60+
const Recrypt = require("index.node");
61+
62+
//Create a new Recrypt API instance
63+
const Api256 = new Recrypt.Api256();
64+
65+
//Generate both a user key pair and a signing key pair
66+
const keys = Api256.generateKeyPair();
67+
const signingKeys = Api256.generateEd25519KeyPair();
68+
69+
//Generate a plaintext to encrypt
70+
const plaintext = Api256.generatePlaintext();
71+
72+
//Encrypt the data to the public key and then attempt to decrypt with the private key
73+
const encryptedValue = Api256.encrypt(plaintext, keys.publicKey, signingKeys.publicKey, signingKeys.privateKey);
74+
const decryptedValue = Api256.decrypt(encryptedValue, keys.privateKey);
75+
76+
assert.equal(decryptedValue, plaintext);
77+
```
78+
79+
#### Single-hop Transform Encryption Example
80+
```js
81+
const assert = require("assert");
82+
const Recrypt = require("index.node");
83+
84+
//Create a new Recrypt API instance
85+
const Api256 = new Recrypt.Api256();
86+
87+
//Generate both a user key pair and a signing key pair
88+
const userKeys = Api256.generateKeyPair();
89+
const signingKeys = Api256.generateEd25519KeyPair();
90+
91+
//Generate a plaintext to encrypt
92+
const plaintext = Api256.generatePlaintext();
93+
94+
//Encrypt the data to the user public key
95+
const encryptedValue = Api256.encrypt(plaintext, userKeys.publicKey, signingKeys.publicKey, signingKeys.privateKey);
96+
97+
//Generate a second public/private key pair as the target of the transform. This will allow the encrypted data to be
98+
//transformed to this second key pair and allow it to be decrypted.
99+
const deviceKeys = Api256.generateKeyPair();
100+
101+
//Generate a transform key from the user private key to the device public key
102+
const userToDeviceTransformKey = Api256.generateTransformKey(userKeys.privateKey, deviceKeys.publicKey, signingKeys.publicKey, signingKeys.privateKey);
103+
104+
//Transform the encrypted data (without decrypting it!) so that it can be decrypted with the second key pair
105+
const transformedEncryptedValue = Api256.transform(encryptedValue, userToDeviceTransformKey, signingKeys.publicKey, signingKeys.privateKey);
106+
107+
//Decrypt the data using the second private key
108+
const decryptedValue = Api256.decrypt(transformedEncryptedValue, deviceKeys.privateKey);
109+
110+
assert.equal(decryptedValue, plaintext);
111+
```

‎index.d.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
export type PrivateKey = Buffer;
2+
export type PublicSigningKey = Buffer;
3+
export type PrivateSigningKey = Buffer;
4+
export interface PublicKey {
5+
x: Buffer;
6+
y: Buffer;
7+
}
8+
export interface KeyPair {
9+
publicKey: PublicKey;
10+
privateKey: PrivateKey;
11+
}
12+
export interface SigningKeyPair {
13+
publicKey: PublicSigningKey;
14+
privateKey: PrivateSigningKey;
15+
}
16+
export type Plaintext = Buffer;
17+
export interface TransformBlock {
18+
publicKey: PublicKey;
19+
encryptedTempKey: Buffer;
20+
randomTransformPublicKey: PublicKey;
21+
randomTransformEncryptedTempKey: Buffer;
22+
}
23+
export interface EncryptedValue {
24+
ephemeralPublicKey: PublicKey;
25+
encryptedMessage: Buffer;
26+
authHash: Buffer;
27+
transformBlocks: TransformBlock[];
28+
publicSigningKey: PublicSigningKey;
29+
signature: Buffer;
30+
}
31+
32+
export interface TransformKey {
33+
ephemeralPublicKey: PublicKey;
34+
toPublicKey: PublicKey;
35+
encryptedTempKey: Buffer;
36+
hashedTempKey: Buffer;
37+
publicSigningKey: PublicSigningKey;
38+
signature: Buffer;
39+
}
40+
41+
export function augmentPublicKey256(publicKey: PublicKey, otherPublicKey: PublicKey): PublicKey;
42+
export function augmentTransformKey(transformKey: TransformKey, privateKey: PrivateKey): TransformKey;
43+
export class Api256 {
44+
constructor();
45+
generateKeyPair(): KeyPair;
46+
generateEd25519KeyPair(): SigningKeyPair;
47+
generatePlaintext(): Plaintext;
48+
generateTransformKey(
49+
fromPrivateKey: PrivateKey,
50+
toPublicKey: PublicKey,
51+
publicSigningKey: PublicSigningKey,
52+
privateSigningKey: PrivateSigningKey
53+
): TransformKey;
54+
computePublicKey(privateKey: PrivateKey): PublicKey;
55+
deriveSymmetricKey(plaintext: Plaintext): Buffer;
56+
encrypt(plaintext: Plaintext, toPublicKey: PublicKey, publicSigningKey: PublicSigningKey, privateSigningKey: PrivateSigningKey): EncryptedValue;
57+
transform(
58+
encryptedValue: EncryptedValue,
59+
transformKey: TransformKey,
60+
publicSigningKey: PublicSigningKey,
61+
privateSigningKey: PrivateSigningKey
62+
): EncryptedValue;
63+
decrypt(encryptedValue: EncryptedValue, privateKey: PrivateKey): Plaintext;
64+
}

‎lib/benchmark/computePublicKey.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const Benchmark = require("benchmark");
2+
const recrypt = require("../../native/index.node");
3+
4+
const api = new recrypt.Api256();
5+
6+
let keypair;
7+
8+
function onCycle() {
9+
keypair = api.generateKeyPair();
10+
}
11+
onCycle();
12+
module.exports = new Benchmark("computePublicKey", {
13+
fn: () => {
14+
api.computePublicKey(keypair.privateKey);
15+
},
16+
onError: (err) => {
17+
console.log(err);
18+
},
19+
onCycle,
20+
onComplete: (result) => {
21+
console.log(result.currentTarget.toString());
22+
},
23+
});

‎lib/benchmark/decryptLevelOne.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const Benchmark = require("benchmark");
2+
const recrypt = require("../../native/index.node");
3+
//Randomly generated legit ED25519 keypair
4+
//prettier-ignore
5+
const publicSigningKey = Buffer.from([138, 136, 227, 221, 116, 9, 241, 149, 253, 82, 219, 45, 60, 186, 93, 114, 202, 103, 9, 191, 29, 148, 18, 27, 243, 116, 136, 1, 180, 15, 111, 92]);
6+
//prettier-ignore
7+
const privateSigningKey = Buffer.from([88, 232, 110, 251, 117, 250, 78, 44, 65, 15, 70, 225, 109, 233, 246, 172, 174, 26, 23, 3, 82, 134, 81, 182, 155, 193, 118, 192, 136, 190, 243, 110, 177, 122, 42, 44, 243, 212, 164, 26, 142, 78, 24, 204, 69, 200, 101, 109, 85, 142, 206, 221, 176, 173, 180, 107, 250, 8, 138, 95, 83, 190, 210, 82]);
8+
9+
const api = new recrypt.Api256();
10+
11+
let devicePrivateKey, lvl1EncryptedValue;
12+
13+
function onCycle() {
14+
const plaintext = api.generatePlaintext();
15+
const userKeys = api.generateKeyPair();
16+
const deviceKeys = api.generateKeyPair();
17+
devicePrivateKey = deviceKeys.privateKey;
18+
const transformKey = api.generateTransformKey(userKeys.privateKey, deviceKeys.publicKey, publicSigningKey, privateSigningKey);
19+
20+
const lvl0EncryptedValue = api.encrypt(plaintext, userKeys.publicKey, publicSigningKey, privateSigningKey);
21+
lvl1EncryptedValue = api.transform(lvl0EncryptedValue, transformKey, publicSigningKey, privateSigningKey);
22+
}
23+
onCycle();
24+
module.exports = new Benchmark("decryptLevel1", {
25+
fn: () => {
26+
api.decrypt(lvl1EncryptedValue, devicePrivateKey);
27+
},
28+
onError: (err) => {
29+
console.log(err);
30+
},
31+
onCycle,
32+
onComplete: (result) => {
33+
console.log(result.currentTarget.toString());
34+
},
35+
});

‎lib/benchmark/decryptLevelTwo.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const Benchmark = require("benchmark");
2+
const recrypt = require("../../native/index.node");
3+
//Randomly generated legit ED25519 keypair
4+
//prettier-ignore
5+
const publicSigningKey = Buffer.from([138, 136, 227, 221, 116, 9, 241, 149, 253, 82, 219, 45, 60, 186, 93, 114, 202, 103, 9, 191, 29, 148, 18, 27, 243, 116, 136, 1, 180, 15, 111, 92]);
6+
//prettier-ignore
7+
const privateSigningKey = Buffer.from([88, 232, 110, 251, 117, 250, 78, 44, 65, 15, 70, 225, 109, 233, 246, 172, 174, 26, 23, 3, 82, 134, 81, 182, 155, 193, 118, 192, 136, 190, 243, 110, 177, 122, 42, 44, 243, 212, 164, 26, 142, 78, 24, 204, 69, 200, 101, 109, 85, 142, 206, 221, 176, 173, 180, 107, 250, 8, 138, 95, 83, 190, 210, 82]);
8+
9+
const api = new recrypt.Api256();
10+
11+
let devicePrivateKey, lvl2EncryptedValue;
12+
13+
function onCycle() {
14+
const plaintext = api.generatePlaintext();
15+
const groupKeys = api.generateKeyPair();
16+
const userKeys = api.generateKeyPair();
17+
const deviceKeys = api.generateKeyPair();
18+
devicePrivateKey = deviceKeys.privateKey;
19+
20+
const groupToUserTransform = api.generateTransformKey(groupKeys.privateKey, userKeys.publicKey, publicSigningKey, privateSigningKey);
21+
const userToDeviceTransform = api.generateTransformKey(userKeys.privateKey, deviceKeys.publicKey, publicSigningKey, privateSigningKey);
22+
23+
const lvl0EncryptedValue = api.encrypt(plaintext, groupKeys.publicKey, publicSigningKey, privateSigningKey);
24+
const lvl1EncryptedValue = api.transform(lvl0EncryptedValue, groupToUserTransform, publicSigningKey, privateSigningKey);
25+
lvl2EncryptedValue = api.transform(lvl1EncryptedValue, userToDeviceTransform, publicSigningKey, privateSigningKey);
26+
}
27+
onCycle();
28+
module.exports = new Benchmark("decryptLevel2", {
29+
fn: () => {
30+
api.decrypt(lvl2EncryptedValue, devicePrivateKey);
31+
},
32+
onError: (err) => {
33+
console.log(err);
34+
},
35+
onCycle,
36+
onComplete: (result) => {
37+
console.log(result.currentTarget.toString());
38+
},
39+
});

‎lib/benchmark/decryptLevelZero.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const Benchmark = require("benchmark");
2+
const recrypt = require("../../native/index.node");
3+
//Randomly generated legit ED25519 keypair
4+
//prettier-ignore
5+
const publicSigningKey = Buffer.from([138, 136, 227, 221, 116, 9, 241, 149, 253, 82, 219, 45, 60, 186, 93, 114, 202, 103, 9, 191, 29, 148, 18, 27, 243, 116, 136, 1, 180, 15, 111, 92]);
6+
//prettier-ignore
7+
const privateSigningKey = Buffer.from([88, 232, 110, 251, 117, 250, 78, 44, 65, 15, 70, 225, 109, 233, 246, 172, 174, 26, 23, 3, 82, 134, 81, 182, 155, 193, 118, 192, 136, 190, 243, 110, 177, 122, 42, 44, 243, 212, 164, 26, 142, 78, 24, 204, 69, 200, 101, 109, 85, 142, 206, 221, 176, 173, 180, 107, 250, 8, 138, 95, 83, 190, 210, 82]);
8+
9+
const api = new recrypt.Api256();
10+
11+
let privateKey, lvl0EncryptedValue;
12+
13+
function onCycle() {
14+
const plaintext = api.generatePlaintext();
15+
const keys = api.generateKeyPair();
16+
privateKey = keys.privateKey;
17+
lvl0EncryptedValue = api.encrypt(plaintext, keys.publicKey, publicSigningKey, privateSigningKey);
18+
}
19+
onCycle();
20+
module.exports = new Benchmark("decryptLevel0", {
21+
fn: () => {
22+
api.decrypt(lvl0EncryptedValue, privateKey);
23+
},
24+
onError: (err) => {
25+
console.log(err);
26+
},
27+
onCycle,
28+
onComplete: (result) => {
29+
console.log(result.currentTarget.toString());
30+
},
31+
});

‎lib/benchmark/deriveSymmetricKey.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const Benchmark = require("benchmark");
2+
const recrypt = require("../../native/index.node");
3+
4+
const api = new recrypt.Api256();
5+
6+
let plaintext;
7+
8+
function onCycle() {
9+
plaintext = api.generatePlaintext();
10+
}
11+
onCycle();
12+
module.exports = new Benchmark("deriveSymmetricKey", {
13+
fn: () => {
14+
api.deriveSymmetricKey(plaintext);
15+
},
16+
onError: (err) => {
17+
console.log(err);
18+
},
19+
onCycle,
20+
onComplete: (result) => {
21+
console.log(result.currentTarget.toString());
22+
},
23+
});

‎lib/benchmark/encrypt.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const crypto = require("crypto");
2+
const Benchmark = require("benchmark");
3+
const recrypt = require("../../native/index.node");
4+
5+
const api = new recrypt.Api256();
6+
7+
let plaintext, toPublicKey;
8+
9+
function onCycle() {
10+
plaintext = api.generatePlaintext();
11+
toPublicKey = api.generateKeyPair().publicKey;
12+
}
13+
onCycle();
14+
module.exports = new Benchmark("encrypt", {
15+
fn: () => {
16+
api.encrypt(plaintext, toPublicKey, crypto.randomBytes(32), crypto.randomBytes(64));
17+
},
18+
onError: (err) => {
19+
console.log(err);
20+
},
21+
onCycle,
22+
onComplete: (result) => {
23+
console.log(result.currentTarget.toString());
24+
},
25+
});
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const Benchmark = require("benchmark");
2+
const recrypt = require("../../native/index.node");
3+
4+
const api = new recrypt.Api256();
5+
6+
module.exports = new Benchmark("generateEd25519KeyPair", {
7+
fn: () => {
8+
api.generateEd25519KeyPair();
9+
},
10+
onError: (err) => {
11+
console.log(err);
12+
},
13+
onComplete: (result) => {
14+
console.log(result.currentTarget.toString());
15+
},
16+
});

‎lib/benchmark/generateKeyPair.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const Benchmark = require("benchmark");
2+
const recrypt = require("../../native/index.node");
3+
4+
const api = new recrypt.Api256();
5+
6+
module.exports = new Benchmark("generateKeyPair", {
7+
fn: () => {
8+
api.generateKeyPair();
9+
},
10+
onError: (err) => {
11+
console.log(err);
12+
},
13+
onComplete: (result) => {
14+
console.log(result.currentTarget.toString());
15+
},
16+
});

‎lib/benchmark/generatePlaintext.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const Benchmark = require("benchmark");
2+
const recrypt = require("../../native/index.node");
3+
4+
const api = new recrypt.Api256();
5+
6+
module.exports = new Benchmark("generatePlaintext", {
7+
fn: () => {
8+
api.generatePlaintext();
9+
},
10+
onError: (err) => {
11+
console.log(err);
12+
},
13+
onComplete: (result) => {
14+
console.log(result.currentTarget.toString());
15+
},
16+
});

‎lib/benchmark/generateTransformKey.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const crypto = require("crypto");
2+
const Benchmark = require("benchmark");
3+
const recrypt = require("../../native/index.node");
4+
5+
const api = new recrypt.Api256();
6+
7+
let fromPrivateKey = api.generateKeyPair().privateKey;
8+
let toPublicKey = api.generateKeyPair().publicKey;
9+
module.exports = new Benchmark("generateTransformKey", {
10+
fn: () => {
11+
api.generateTransformKey(fromPrivateKey, toPublicKey, crypto.randomBytes(32), crypto.randomBytes(64));
12+
},
13+
onError: (err) => {
14+
console.log(err);
15+
},
16+
onCycle: () => {
17+
fromPrivateKey = api.generateKeyPair().privateKey;
18+
toPublicKey = api.generateKeyPair().publicKey;
19+
},
20+
onComplete: (result) => {
21+
console.log(result.currentTarget.toString());
22+
},
23+
});

‎lib/benchmark/index.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const generateKeyPair = require("./generateKeyPair");
2+
const generateEd25519KeyPair = require("./generateEd25519KeyPair");
3+
const generatePlaintext = require("./generatePlaintext");
4+
const generateTransformKey = require("./generateTransformKey");
5+
const computePublicKey = require("./computePublicKey");
6+
const deriveSymmetricKey = require("./deriveSymmetricKey");
7+
const encrypt = require("./encrypt");
8+
const transformLevelOne = require("./transformLevelOne");
9+
const transformLevelTwo = require("./transformLevelTwo");
10+
const decryptLevelZero = require("./decryptLevelZero");
11+
const decryptLevelOne = require("./decryptLevelOne");
12+
const decryptLevelTwo = require("./decryptLevelTwo");
13+
14+
generateKeyPair.on("complete", () => {
15+
generateEd25519KeyPair.run({async: true});
16+
});
17+
18+
generateEd25519KeyPair.on("complete", () => {
19+
generatePlaintext.run({async: true});
20+
});
21+
22+
generatePlaintext.on("complete", () => {
23+
generateTransformKey.run({async: true});
24+
});
25+
26+
generateTransformKey.on("complete", () => {
27+
computePublicKey.run({async: true});
28+
});
29+
30+
computePublicKey.on("complete", () => {
31+
deriveSymmetricKey.run({async: true});
32+
});
33+
34+
deriveSymmetricKey.on("complete", () => {
35+
encrypt.run({async: true});
36+
});
37+
38+
encrypt.on("complete", () => {
39+
transformLevelOne.run({async: true});
40+
});
41+
42+
transformLevelOne.on("complete", () => {
43+
transformLevelTwo.run({async: true});
44+
});
45+
46+
transformLevelTwo.on("complete", () => {
47+
decryptLevelZero.run({async: true});
48+
});
49+
50+
decryptLevelZero.on("complete", () => {
51+
decryptLevelOne.run({async: true});
52+
});
53+
54+
decryptLevelOne.on("complete", () => {
55+
decryptLevelTwo.run({async: true});
56+
});
57+
58+
generateKeyPair.run({async: true});

‎lib/benchmark/transformLevelOne.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const crypto = require("crypto");
2+
const Benchmark = require("benchmark");
3+
const recrypt = require("../../native/index.node");
4+
//Randomly generated legit ED25519 keypair
5+
//prettier-ignore
6+
const publicSigningKey = Buffer.from([138, 136, 227, 221, 116, 9, 241, 149, 253, 82, 219, 45, 60, 186, 93, 114, 202, 103, 9, 191, 29, 148, 18, 27, 243, 116, 136, 1, 180, 15, 111, 92]);
7+
//prettier-ignore
8+
const privateSigningKey = Buffer.from([88, 232, 110, 251, 117, 250, 78, 44, 65, 15, 70, 225, 109, 233, 246, 172, 174, 26, 23, 3, 82, 134, 81, 182, 155, 193, 118, 192, 136, 190, 243, 110, 177, 122, 42, 44, 243, 212, 164, 26, 142, 78, 24, 204, 69, 200, 101, 109, 85, 142, 206, 221, 176, 173, 180, 107, 250, 8, 138, 95, 83, 190, 210, 82]);
9+
10+
const api = new recrypt.Api256();
11+
12+
let lvl0EncryptedValue, userToDeviceTransform;
13+
14+
function onCycle() {
15+
const userKeys = api.generateKeyPair();
16+
const deviceKeys = api.generateKeyPair();
17+
lvl0EncryptedValue = api.encrypt(api.generatePlaintext(), userKeys.publicKey, publicSigningKey, privateSigningKey);
18+
userToDeviceTransform = api.generateTransformKey(userKeys.privateKey, deviceKeys.publicKey, publicSigningKey, privateSigningKey);
19+
}
20+
onCycle();
21+
module.exports = new Benchmark("transformLevelOne", {
22+
fn: () => {
23+
api.transform(lvl0EncryptedValue, userToDeviceTransform, Buffer.alloc(32), Buffer.alloc(64));
24+
},
25+
onError: (err) => {
26+
console.log(err);
27+
},
28+
onCycle,
29+
onComplete: (result) => {
30+
console.log(result.currentTarget.toString());
31+
},
32+
});

‎lib/benchmark/transformLevelTwo.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const crypto = require("crypto");
2+
const Benchmark = require("benchmark");
3+
const recrypt = require("../../native/index.node");
4+
//Randomly generated legit ED25519 keypair
5+
//prettier-ignore
6+
const publicSigningKey = Buffer.from([138, 136, 227, 221, 116, 9, 241, 149, 253, 82, 219, 45, 60, 186, 93, 114, 202, 103, 9, 191, 29, 148, 18, 27, 243, 116, 136, 1, 180, 15, 111, 92]);
7+
//prettier-ignore
8+
const privateSigningKey = Buffer.from([88, 232, 110, 251, 117, 250, 78, 44, 65, 15, 70, 225, 109, 233, 246, 172, 174, 26, 23, 3, 82, 134, 81, 182, 155, 193, 118, 192, 136, 190, 243, 110, 177, 122, 42, 44, 243, 212, 164, 26, 142, 78, 24, 204, 69, 200, 101, 109, 85, 142, 206, 221, 176, 173, 180, 107, 250, 8, 138, 95, 83, 190, 210, 82]);
9+
10+
const api = new recrypt.Api256();
11+
12+
let groupToUserTransform, userToDeviceTransform, lvl0EncryptedValue;
13+
14+
function onCycle() {
15+
const groupKeys = api.generateKeyPair();
16+
const userKeys = api.generateKeyPair();
17+
const deviceKeys = api.generateKeyPair();
18+
lvl0EncryptedValue = api.encrypt(api.generatePlaintext(), userKeys.publicKey, publicSigningKey, privateSigningKey);
19+
groupToUserTransform = api.generateTransformKey(groupKeys.privateKey, userKeys.publicKey, publicSigningKey, privateSigningKey);
20+
userToDeviceTransform = api.generateTransformKey(userKeys.privateKey, deviceKeys.publicKey, publicSigningKey, privateSigningKey);
21+
}
22+
onCycle();
23+
module.exports = new Benchmark("transformLevelTwo", {
24+
fn: () => {
25+
const lvl1EncryptedValue = api.transform(lvl0EncryptedValue, groupToUserTransform, publicSigningKey, privateSigningKey);
26+
api.transform(lvl1EncryptedValue, userToDeviceTransform, publicSigningKey, privateSigningKey);
27+
},
28+
onError: (err) => {
29+
console.log(err);
30+
},
31+
onCycle,
32+
onComplete: (result) => {
33+
console.log(result.currentTarget.toString());
34+
},
35+
});

‎lib/test/recrypt-node.test.js

+381
Large diffs are not rendered by default.

‎native/Cargo.toml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "recrypt-node-binding"
3+
version = "0.1.0"
4+
authors = ["IronCore Labs <code@ironcorelabs.com>"]
5+
6+
[lib]
7+
name = "recrypt_node"
8+
crate-type = ["dylib"]
9+
10+
[dependencies]
11+
rand = "0.5.5"
12+
recrypt = "0.1.0"
13+
neon = "0.2.0"
14+
15+
[build-dependencies]
16+
neon-build = "0.2.0"

‎native/src/api256.rs

+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
use neon::prelude::*;
2+
use neon::types::JsBuffer;
3+
use rand;
4+
use recrypt::api::{
5+
Api, CryptoOps, Ed25519, Ed25519Ops, KeyGenOps, PrivateSigningKey, PublicSigningKey,
6+
RandomBytes, Sha256,
7+
};
8+
use util;
9+
10+
pub struct RecryptApi256 {
11+
api: Api<Sha256, Ed25519, RandomBytes<rand::ThreadRng>>,
12+
}
13+
14+
declare_types! {
15+
pub class Api256 for RecryptApi256 {
16+
init(_cx) {
17+
Ok(RecryptApi256 {api: Api::new()})
18+
}
19+
20+
method generateKeyPair(mut cx) {
21+
let (priv_key, pub_key) = {
22+
let mut this = cx.this();
23+
let guard = cx.lock();
24+
let mut recrypt_api_256 = this.borrow_mut(&guard);
25+
recrypt_api_256.api.generate_key_pair().unwrap()
26+
};
27+
28+
let key_pair: Handle<JsObject> = cx.empty_object();
29+
30+
let priv_key_buffer = util::bytes_to_buffer(&mut cx, priv_key.bytes())?;
31+
let public_key_obj = util::public_key_to_js_object(&mut cx, &pub_key)?;
32+
33+
key_pair.set(&mut cx, "privateKey", priv_key_buffer)?;
34+
key_pair.set(&mut cx, "publicKey", public_key_obj)?;
35+
36+
Ok(key_pair.upcast())
37+
}
38+
39+
method generateEd25519KeyPair(mut cx) {
40+
let (priv_key, pub_key) = {
41+
let mut this = cx.this();
42+
let guard = cx.lock();
43+
let mut recrypt_api_256 = this.borrow_mut(&guard);
44+
recrypt_api_256.api.generate_ed25519_key_pair()
45+
};
46+
47+
let signing_key_pair: Handle<JsObject> = cx.empty_object();
48+
let priv_key_buffer = util::bytes_to_buffer(&mut cx, priv_key.bytes())?;
49+
let pub_key_buffer = util::bytes_to_buffer(&mut cx, pub_key.bytes())?;
50+
51+
signing_key_pair.set(&mut cx, "privateKey", priv_key_buffer)?;
52+
signing_key_pair.set(&mut cx, "publicKey", pub_key_buffer)?;
53+
54+
Ok(signing_key_pair.upcast())
55+
}
56+
57+
method generatePlaintext(mut cx) {
58+
let plaintext = {
59+
let mut this = cx.this();
60+
let guard = cx.lock();
61+
let mut recrypt_api_256 = this.borrow_mut(&guard);
62+
recrypt_api_256.api.gen_plaintext()
63+
};
64+
65+
let plaintext_buffer = util::bytes_to_buffer(&mut cx, plaintext.bytes())?;
66+
Ok(plaintext_buffer.upcast())
67+
}
68+
69+
method generateTransformKey(mut cx) {
70+
let from_private_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(0)?;
71+
let to_public_key_obj: Handle<JsObject> = cx.argument::<JsObject>(1)?;
72+
let public_signing_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(2)?;
73+
let private_signing_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(3)?;
74+
75+
let to_public_key = util::js_object_to_public_key(&mut cx, to_public_key_obj);
76+
let public_signing_key = PublicSigningKey::new(util::buffer_to_fixed_32_bytes(&mut cx, public_signing_key_buffer, "publicSigningKey"));
77+
let private_signing_key = PrivateSigningKey::new(util::buffer_to_fixed_64_bytes(&mut cx, private_signing_key_buffer, "privateSigningKey"));
78+
79+
let transform_key = {
80+
let mut this = cx.this();
81+
let guard = cx.lock();
82+
let mut recrypt_api_256 = this.borrow_mut(&guard);
83+
recrypt_api_256.api.generate_transform_key(
84+
util::buffer_to_private_key(&cx, from_private_key_buffer),
85+
to_public_key,
86+
public_signing_key,
87+
private_signing_key
88+
).unwrap()
89+
};
90+
91+
Ok(util::transform_key_to_js_object(&mut cx, transform_key)?.upcast())
92+
}
93+
94+
method computePublicKey(mut cx){
95+
let private_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(0)?;
96+
let derived_public_key = {
97+
let this = cx.this();
98+
let guard = cx.lock();
99+
let recrypt_api_256 = &this.borrow(&guard).api;
100+
recrypt_api_256.compute_public_key(&util::buffer_to_private_key(&cx, private_key_buffer)).unwrap()
101+
};
102+
103+
Ok(util::public_key_to_js_object(&mut cx, &derived_public_key)?.upcast())
104+
}
105+
106+
method deriveSymmetricKey(mut cx){
107+
let plaintext_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(0)?;
108+
109+
let decrypted_symmetric_key = {
110+
let mut this = cx.this();
111+
let guard = cx.lock();
112+
let mut recrypt_api_256 = this.borrow_mut(&guard);
113+
recrypt_api_256.api.derive_symmetric_key(&util::buffer_to_plaintext(&cx, plaintext_buffer))
114+
};
115+
116+
Ok(util::bytes_to_buffer(&mut cx, decrypted_symmetric_key.bytes())?.upcast())
117+
}
118+
119+
method encrypt(mut cx) {
120+
let plaintext_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(0)?;
121+
let to_public_key_obj: Handle<JsObject> = cx.argument::<JsObject>(1)?;
122+
let public_signing_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(2)?;
123+
let private_signing_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(3)?;
124+
125+
let public_key = util::js_object_to_public_key(&mut cx, to_public_key_obj);
126+
let public_signing_key = PublicSigningKey::new(util::buffer_to_fixed_32_bytes(&mut cx, public_signing_key_buffer, "publicSigningKey"));
127+
let private_signing_key = PrivateSigningKey::new(util::buffer_to_fixed_64_bytes(&mut cx, private_signing_key_buffer, "privateSigningKey"));
128+
129+
let encrypted_value = {
130+
let mut this = cx.this();
131+
let guard = cx.lock();
132+
let mut recrypt_api_256 = this.borrow_mut(&guard);
133+
recrypt_api_256.api.encrypt(
134+
util::buffer_to_plaintext(&cx, plaintext_buffer),
135+
public_key,
136+
public_signing_key,
137+
private_signing_key
138+
).unwrap()
139+
};
140+
141+
Ok(util::encrypted_value_to_js_object(&mut cx, encrypted_value)?.upcast())
142+
}
143+
144+
method transform(mut cx) {
145+
let encrypted_value_obj: Handle<JsObject> = cx.argument::<JsObject>(0)?;
146+
let transform_key_obj: Handle<JsObject> = cx.argument::<JsObject>(1)?;
147+
let public_signing_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(2)?;
148+
let private_signing_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(3)?;
149+
150+
let encrypted_value = util::js_object_to_encrypted_value(&mut cx, encrypted_value_obj);
151+
let transform_key = util::js_object_to_transform_key(&mut cx, transform_key_obj);
152+
let public_signing_key = PublicSigningKey::new(util::buffer_to_fixed_32_bytes(&mut cx, public_signing_key_buffer, "publicSigningKey"));
153+
let private_signing_key = PrivateSigningKey::new(util::buffer_to_fixed_64_bytes(&mut cx, private_signing_key_buffer, "privateSigningKey"));
154+
155+
let transformed_encrypted_value = {
156+
let mut this = cx.this();
157+
let guard = cx.lock();
158+
let mut recrypt_api_256 = this.borrow_mut(&guard);
159+
recrypt_api_256.api.transform(encrypted_value, transform_key, public_signing_key, private_signing_key).unwrap()
160+
};
161+
162+
Ok(util::encrypted_value_to_js_object(&mut cx, transformed_encrypted_value)?.upcast())
163+
}
164+
165+
method decrypt(mut cx) {
166+
let encrypted_value_obj: Handle<JsObject> = cx.argument::<JsObject>(0)?;
167+
let private_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(1)?;
168+
169+
let encrypted_value = util::js_object_to_encrypted_value(&mut cx, encrypted_value_obj);
170+
171+
let decrypted_value = {
172+
let this = cx.this();
173+
let guard = cx.lock();
174+
let recrypt_api_256 = &this.borrow(&guard).api;
175+
recrypt_api_256.decrypt(
176+
encrypted_value,
177+
util::buffer_to_private_key(&cx, private_key_buffer)
178+
).unwrap()
179+
};
180+
181+
Ok(util::bytes_to_buffer(&mut cx, decrypted_value.bytes())?.upcast())
182+
}
183+
}
184+
}
185+
186+
///
187+
/// Augment the provided transform key with the provided private key. Returns an augmented TransformKey object.
188+
///
189+
pub fn augment_transform_key_256(mut cx: FunctionContext) -> JsResult<JsObject> {
190+
let transform_key_obj: Handle<JsObject> = cx.argument::<JsObject>(0)?;
191+
let private_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(1)?;
192+
let transform_key = util::js_object_to_transform_key(&mut cx, transform_key_obj);
193+
194+
let augmented_transform_key = transform_key
195+
.augment(&util::buffer_to_private_key(&cx, private_key_buffer))
196+
.unwrap();
197+
198+
Ok(util::transform_key_to_js_object(&mut cx, augmented_transform_key)?.upcast())
199+
}
200+
201+
///
202+
/// Augment the provided public key with the other provided public key. Returns a new augmented PublicKey object.
203+
///
204+
pub fn augment_public_key_256(mut cx: FunctionContext) -> JsResult<JsObject> {
205+
let current_public_key_obj: Handle<JsObject> = cx.argument::<JsObject>(0)?;
206+
let other_public_key_obj: Handle<JsObject> = cx.argument::<JsObject>(1)?;
207+
208+
let current_public_key = util::js_object_to_public_key(&mut cx, current_public_key_obj);
209+
210+
let augmented_public_key = current_public_key
211+
.augment(&util::js_object_to_public_key(
212+
&mut cx,
213+
other_public_key_obj,
214+
)).unwrap();
215+
216+
Ok(util::public_key_to_js_object(&mut cx, &augmented_public_key)?.upcast())
217+
}

‎native/src/lib.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#[macro_use]
2+
extern crate neon;
3+
extern crate rand;
4+
extern crate recrypt;
5+
6+
mod api256;
7+
mod util;
8+
9+
register_module!(mut cx, {
10+
cx.export_function("augmentTransformKey256", api256::augment_transform_key_256)?;
11+
cx.export_function("augmentPublicKey256", api256::augment_public_key_256)?;
12+
cx.export_class::<api256::Api256>("Api256")
13+
});

‎native/src/util.rs

+404
Large diffs are not rendered by default.

‎package.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "@ironcorelabs/recrypt-node-binding",
3+
"version": "0.1.0",
4+
"description": "Bindings to allow the recrypt-rust library to work via NodeJS.",
5+
"repository": "https://github.com/IronCoreLabs/recrypt-node-bindings",
6+
"homepage": "https://ironcorelabs.com",
7+
"author": "IronCore Labs",
8+
"license": "AGPL-3.0-only",
9+
"main": "index.node",
10+
"types": "index.d.ts",
11+
"scripts": {
12+
"compile": "neon build -r",
13+
"clean": "neon clean",
14+
"benchmark": "node lib/benchmark/index.js",
15+
"test": "jest"
16+
},
17+
"devDependencies": {
18+
"@types/node": "^10.11.0",
19+
"benchmark": "^2.1.4",
20+
"jest": "^23.6.0",
21+
"jest-extended": "^0.10.0",
22+
"neon-cli": "^0.2.0",
23+
"shelljs": "^0.8.2"
24+
},
25+
"prettier": {
26+
"printWidth": 160,
27+
"tabWidth": 4,
28+
"trailingComma": "es5",
29+
"bracketSpacing": false,
30+
"jsxBracketSameLine": true,
31+
"arrowParens": "always"
32+
},
33+
"jest": {
34+
"testEnvironment": "node",
35+
"setupTestFrameworkScriptFile": "jest-extended"
36+
}
37+
}

‎publish.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* recrypt-node-binding NPM publish script
5+
* ==================================
6+
*
7+
* This script is responsible for compiling and building the NPM release bundle for this repo. The following steps are taken:
8+
*
9+
* + Clean up any existing Rust builds by running `cargo clean`.
10+
* + Run `cargo update` to make sure all dependencies are available.
11+
* + Compile rust code into index.node file.
12+
* + Run unit tests to ensure the library is in good shape for publishing.
13+
* + Move all expected content into a `dist` directory.
14+
* + Do a dry run of npm publishing via irish-pub or perform an actual publish step if `--publish` option is provided.
15+
*/
16+
17+
const fs = require("fs");
18+
const path = require("path");
19+
const shell = require("shelljs");
20+
21+
//Fail this script if any of these commands fail
22+
shell.set("-e");
23+
24+
//Ensure that our directory is set to the root of the repo
25+
const rootDirectory = path.dirname(process.argv[1]);
26+
const shouldPublish = process.argv.slice(2).indexOf("--publish") !== -1;
27+
28+
//Cleanup the previous build, if it exists
29+
shell.rm("-rf", "./dist");
30+
31+
//Cleanup any previous Rust builds, update deps, and compile
32+
shell.exec("yarn");
33+
shell.exec("yarn run clean");
34+
shell.pushd("./native");
35+
shell.exec("cargo update");
36+
shell.popd();
37+
shell.exec("yarn run compile");
38+
39+
shell.exec("yarn test");
40+
shell.mkdir("./dist");
41+
42+
shell.cp(["README.md", "package.json", "index.d.ts", "./native/index.node", "LICENSE"], "./dist");
43+
44+
shell.pushd("./dist");
45+
46+
shell.exec(shouldPublish ? "npm publish --access private" : "irish-pub");
47+
48+
shell.popd();

‎yarn.lock

+3,579
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.