Skip to content

Commit 700cf26

Browse files
author
Ernie Turner
authored
#39 Expose methods to add/subtract private keys for key rotation (#40)
* #39 Expose methods to add/subtract private keys for key rotation * Try specific version of alpine * Try alpine 3.9 * Add note about why use a specific version of Alpine for Node 10
1 parent 822830f commit 700cf26

File tree

11 files changed

+1458
-1134
lines changed

11 files changed

+1458
-1134
lines changed

.travis.yml

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
language: rust
22
rust:
3-
- 1.38.0
3+
- 1.41.0
44

55
services:
66
- docker
@@ -14,25 +14,6 @@ jobs:
1414
include:
1515
# PRs, pushes to master, and tags build on all target arches
1616
# if this is release tag, the resultant binary will be uploaded to github
17-
- name: "Linux - Node 8 - glibc"
18-
os: linux
19-
env:
20-
- TRAVIS_NODE_VERSION="8"
21-
- SKIP_DEPLOY=0
22-
if: tag =~ /^\d+\.\d+\.\d+/ OR branch = master OR type = pull_request
23-
- name: "Linux - Node 8 - musl"
24-
os: linux
25-
env:
26-
- SKIP_DEPLOY=0
27-
- IMAGE=8-alpine
28-
- INDOCKER="docker exec target"
29-
if: tag =~ /^\d+\.\d+\.\d+/ OR branch = master OR type = pull_request
30-
- name: "OSX - Node 8"
31-
os: osx
32-
env:
33-
- TRAVIS_NODE_VERSION="8"
34-
- SKIP_DEPLOY=0
35-
if: tag =~ /^\d+\.\d+\.\d+/ OR branch = master OR type = pull_request
3617
- name: "Linux - Node 10 - glibc"
3718
os: linux
3819
env:
@@ -43,7 +24,10 @@ jobs:
4324
os: linux
4425
env:
4526
- SKIP_DEPLOY=0
46-
- IMAGE=10-alpine
27+
# Node 10 and Alpine 3.10/3.11 do not play well together and causes a random
28+
# segfault when we try to run jest. So use Alpine 3.9 which does work.
29+
# Ref: https://github.com/nodejs/docker-node/issues/1158
30+
- IMAGE=10-alpine3.9
4731
- INDOCKER="docker exec target"
4832
if: tag =~ /^\d+\.\d+\.\d+/ OR branch = master OR type = pull_request
4933
- name: "OSX - Node 10"
@@ -77,7 +61,7 @@ jobs:
7761
name: "Publish to npm"
7862
os: linux
7963
env:
80-
- TRAVIS_NODE_VERSION="8"
64+
- TRAVIS_NODE_VERSION="10"
8165
- SKIP_DEPLOY=1
8266

8367
# NPM_TOKEN

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## 0.7.0
2+
3+
### Breaking Changes
4+
5+
- Removed support for Node 8.
6+
7+
### Changed
8+
9+
- Added Windows builds.
10+
- Added method `addPrivateKeys(privKeyA: PrivateKey, privKeyB: PrivateKey): PrivateKey` which takes two private keys and adds them together to return a new private key.
11+
- Added method `subtractPrivateKeys(privKeyA: PrivateKey, privKeyB: PrivateKey): PrivateKey` which takes two private keys and subtracts `privKeyB` from `privKeyA` to return a new private key.
12+
113
## 0.6.1
214

315
### Breaking Changes

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ This library uses the [Neon Bindings](https://www.neon-bindings.com) toolchain t
99

1010
## Supported Platforms
1111

12-
| | Node 8 | Node 10 | Node 12 |
13-
| --------------------- | ------ | ------- | ------- |
14-
| Linux x64 - glibc || ||
15-
| Linux x64 - musl-libc || ||
16-
| OSX x64 || ||
12+
| | Node 10 | Node 12 |
13+
| --------------------- | ------- | ------- |
14+
| Linux x64 - glibc |||
15+
| Linux x64 - musl-libc |||
16+
| OSX x64 |||
1717

1818
## Install
1919

index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export interface TransformKey {
4242
export function augmentPublicKey256(publicKey: PublicKey, otherPublicKey: PublicKey): PublicKey;
4343
export function augmentTransformKey256(transformKey: TransformKey, privateKey: PrivateKey): TransformKey;
4444
export function transformKeyToBytes256(transformKey: TransformKey): Buffer;
45+
export function addPrivateKeys(privateKeyA: PrivateKey, privateKeyB: PrivateKey): PrivateKey;
46+
export function subtractPrivateKeys(privateKeyA: PrivateKey, privateKeyB: PrivateKey): PrivateKey;
4547
export class Api256 {
4648
constructor();
4749
generateKeyPair(): KeyPair;

native/Cargo.lock

Lines changed: 46 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

native/src/api256.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
use neon::prelude::*;
2-
use neon::types::JsBuffer;
3-
use recrypt::api::Hashable;
1+
use neon::{prelude::*, types::JsBuffer};
42
use recrypt::api::{
5-
CryptoOps, DefaultRng, Ed25519, Ed25519Ops, KeyGenOps, PublicSigningKey, RandomBytes, Recrypt,
6-
SchnorrOps, Sha256, SigningKeypair,
3+
CryptoOps, DefaultRng, Ed25519, Ed25519Ops, Hashable, KeyGenOps, PublicSigningKey, RandomBytes,
4+
Recrypt, SchnorrOps, Sha256, SigningKeypair,
75
};
86
use util;
97

@@ -268,9 +266,7 @@ declare_types! {
268266
}
269267
}
270268

271-
///
272269
/// Augment the provided transform key with the provided private key. Returns an augmented TransformKey object.
273-
///
274270
pub fn augment_transform_key_256(mut cx: FunctionContext) -> JsResult<JsObject> {
275271
let transform_key_obj: Handle<JsObject> = cx.argument::<JsObject>(0)?;
276272
let private_key_buffer: Handle<JsBuffer> = cx.argument::<JsBuffer>(1)?;
@@ -283,9 +279,7 @@ pub fn augment_transform_key_256(mut cx: FunctionContext) -> JsResult<JsObject>
283279
Ok(util::transform_key_to_js_object(&mut cx, augmented_transform_key)?.upcast())
284280
}
285281

286-
///
287282
/// Augment the provided public key with the other provided public key. Returns a new augmented PublicKey object.
288-
///
289283
pub fn augment_public_key_256(mut cx: FunctionContext) -> JsResult<JsObject> {
290284
let current_public_key_obj: Handle<JsObject> = cx.argument::<JsObject>(0)?;
291285
let other_public_key_obj: Handle<JsObject> = cx.argument::<JsObject>(1)?;
@@ -302,10 +296,8 @@ pub fn augment_public_key_256(mut cx: FunctionContext) -> JsResult<JsObject> {
302296
Ok(util::public_key_to_js_object(&mut cx, &augmented_public_key)?.upcast())
303297
}
304298

305-
///
306299
/// Hash the provided transform key into a buffer of bytes. The various transform key object fields are concatenated
307300
/// in a specific order in order for transform keys to be signed over.
308-
///
309301
pub fn transform_key_to_bytes_256(mut cx: FunctionContext) -> JsResult<JsBuffer> {
310302
let transform_key_obj: Handle<JsObject> = cx.argument::<JsObject>(0)?;
311303
let transform_key = util::js_object_to_transform_key(&mut cx, transform_key_obj);
@@ -314,3 +306,23 @@ pub fn transform_key_to_bytes_256(mut cx: FunctionContext) -> JsResult<JsBuffer>
314306

315307
Ok(transform_key_bytes)
316308
}
309+
310+
/// Add the two provided private keys together. Used when performing key rotation.
311+
pub fn add_private_keys(mut cx: FunctionContext) -> JsResult<JsBuffer> {
312+
let pub_key_a: Handle<JsBuffer> = cx.argument::<JsBuffer>(0)?;
313+
let pub_key_b: Handle<JsBuffer> = cx.argument::<JsBuffer>(1)?;
314+
let augmented = util::buffer_to_private_key(&cx, pub_key_a)
315+
.augment_plus(&util::buffer_to_private_key(&cx, pub_key_b));
316+
317+
Ok(util::bytes_to_buffer(&mut cx, &augmented.to_bytes())?)
318+
}
319+
320+
/// Subtract the second provided private key from the first provided private key. Used when performing key rotation
321+
pub fn subtract_private_keys(mut cx: FunctionContext) -> JsResult<JsBuffer> {
322+
let pub_key_a: Handle<JsBuffer> = cx.argument::<JsBuffer>(0)?;
323+
let pub_key_b: Handle<JsBuffer> = cx.argument::<JsBuffer>(1)?;
324+
let augmented = util::buffer_to_private_key(&cx, pub_key_a)
325+
.augment_minus(&util::buffer_to_private_key(&cx, pub_key_b));
326+
327+
Ok(util::bytes_to_buffer(&mut cx, &augmented.to_bytes())?)
328+
}

native/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ register_module!(mut cx, {
99
cx.export_function("augmentTransformKey256", api256::augment_transform_key_256)?;
1010
cx.export_function("augmentPublicKey256", api256::augment_public_key_256)?;
1111
cx.export_function("transformKeyToBytes256", api256::transform_key_to_bytes_256)?;
12+
cx.export_function("addPrivateKeys", api256::add_private_keys)?;
13+
cx.export_function("subtractPrivateKeys", api256::subtract_private_keys)?;
1214
cx.export_class::<api256::Api256>("Api256")
1315
});

native/src/util.rs

Lines changed: 7 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
use neon::prelude::*;
2-
use neon::types::JsBuffer;
1+
use neon::{prelude::*, types::JsBuffer};
32
use recrypt::api::{
43
AuthHash, Ed25519Signature, EncryptedMessage, EncryptedTempKey, EncryptedValue, HashedValue,
54
Plaintext, PrivateKey, PublicKey, PublicSigningKey, SchnorrSignature, TransformBlock,
65
TransformKey,
76
};
87
use recrypt::nonemptyvec::NonEmptyVec;
98

10-
///
119
/// Create an `$n` byte fixed u8 array given the provided JsBuffer handle. Throws an error if the provided Buffer
1210
/// is not of the required length.
13-
///
1411
macro_rules! buffer_to_fixed_bytes { ($($fn_name: ident, $n: expr); *) => {
1512
$(pub fn $fn_name<'a, T>(cx: &T, mut buffer: Handle<JsBuffer>, field_name: &str) -> [u8; $n]
1613
where T: Context<'a>{
@@ -28,12 +25,8 @@ macro_rules! buffer_to_fixed_bytes { ($($fn_name: ident, $n: expr); *) => {
2825
// Create the various methods we need to convert buffers into fixed length bytes
2926
buffer_to_fixed_bytes! {buffer_to_fixed_32_bytes, 32; buffer_to_fixed_64_bytes, 64; buffer_to_fixed_128_bytes, 128; buffer_to_fixed_384_bytes, 384}
3027

31-
///
32-
/// Create a macro for converting JsBuffers to different types of signature objects which all have the same size. Marked as dead code because usage
33-
/// of this function in the wrapped macro in `api256.rs` can't be parsed by Rust.
34-
///
28+
/// Create a macro for converting JsBuffers to different types of signature objects which all have the same size.
3529
macro_rules! buffer_to_signature { ($($fn_name: ident, $sig_type: expr, $ret_type: ty); *) => {
36-
#[allow(dead_code)]
3730
$(pub fn $fn_name<'a, T: Context<'a>>(cx: &T, buffer: Handle<JsBuffer>) -> $ret_type {
3831
$sig_type(buffer_to_fixed_64_bytes(cx, buffer, "signature"))
3932
})+
@@ -42,9 +35,7 @@ macro_rules! buffer_to_signature { ($($fn_name: ident, $sig_type: expr, $ret_typ
4235
// Create two methods from the macro for Schnorr and ED25519 signatures
4336
buffer_to_signature! {buffer_to_schnorr_signature, SchnorrSignature::new, SchnorrSignature; buffer_to_ed25519_signature, Ed25519Signature::new, Ed25519Signature}
4437

45-
///
4638
/// Convert a JsBuffer handle of variable size into a vector
47-
///
4839
pub fn buffer_to_variable_bytes<'a, T: Context<'a>>(
4940
cx: &T,
5041
mut buffer: Handle<JsBuffer>,
@@ -54,9 +45,7 @@ pub fn buffer_to_variable_bytes<'a, T: Context<'a>>(
5445
slice.to_vec()
5546
}
5647

57-
///
5848
/// Copy the bytes from the provided u8 slice into the provided JS Buffer object
59-
///
6049
pub fn bytes_to_buffer<'a, T: Context<'a>>(
6150
cx: &mut T,
6251
data: &[u8],
@@ -68,25 +57,17 @@ pub fn bytes_to_buffer<'a, T: Context<'a>>(
6857
Ok(buffer)
6958
}
7059

71-
///
7260
/// Convert a JsBuffer handle into a PrivateKey
73-
///
7461
pub fn buffer_to_private_key<'a, T: Context<'a>>(cx: &T, buffer: Handle<JsBuffer>) -> PrivateKey {
7562
PrivateKey::new(buffer_to_fixed_32_bytes(cx, buffer, "privateKey"))
7663
}
7764

78-
///
79-
/// Convert a JsBuffer handle to a Plaintext object. Marked as dead code because usage
80-
/// of this function in the wrapped macro in `api256.rs` can't be parsed by Rust
81-
///
82-
#[allow(dead_code)]
65+
/// Convert a JsBuffer handle to a Plaintext object.
8366
pub fn buffer_to_plaintext<'a, T: Context<'a>>(cx: &T, buffer: Handle<JsBuffer>) -> Plaintext {
8467
Plaintext::new(buffer_to_fixed_384_bytes(cx, buffer, "plaintext"))
8568
}
8669

87-
///
8870
/// Convert a JsObject with x/y Buffers into a PublicKey
89-
///
9071
pub fn js_object_to_public_key<'a, T: Context<'a>>(
9172
cx: &mut T,
9273
object: Handle<JsObject>,
@@ -101,9 +82,7 @@ pub fn js_object_to_public_key<'a, T: Context<'a>>(
10182
.unwrap()
10283
}
10384

104-
///
10585
/// Convert a Recrypt PublicKey struct into a JsObject with x/y properties which are Buffers
106-
///
10786
pub fn public_key_to_js_object<'a, T: Context<'a>>(
10887
cx: &mut T,
10988
public_key: &PublicKey,
@@ -118,9 +97,7 @@ pub fn public_key_to_js_object<'a, T: Context<'a>>(
11897
Ok(public_key_obj)
11998
}
12099

121-
///
122100
/// Convert a JsObject which represents a TransformKey into an internal recrypt TransformKey
123-
///
124101
pub fn js_object_to_transform_key<'a, T: Context<'a>>(
125102
cx: &mut T,
126103
object: Handle<JsObject>,
@@ -179,9 +156,7 @@ pub fn js_object_to_transform_key<'a, T: Context<'a>>(
179156
)
180157
}
181158

182-
///
183159
/// Convert a Recrypt TransformKey into a JsObject with expected properties and bytes converted to Buffers
184-
///
185160
pub fn transform_key_to_js_object<'a, T: Context<'a>>(
186161
cx: &mut T,
187162
transform_key: TransformKey,
@@ -206,11 +181,7 @@ pub fn transform_key_to_js_object<'a, T: Context<'a>>(
206181
Ok(transform_key_obj)
207182
}
208183

209-
///
210-
/// Convert an array of transform blocks into a non-empty vector of internal recrypt TransformBlock structs. Marked as dead code because usage
211-
/// of this function in the wrapped macro in `api256.rs` can't be parsed by Rust
212-
///
213-
#[allow(dead_code)]
184+
/// Convert an array of transform blocks into a non-empty vector of internal recrypt TransformBlock structs.
214185
pub fn js_object_to_transform_blocks<'a, T: Context<'a>>(
215186
cx: &mut T,
216187
js_array: Handle<JsArray>,
@@ -263,11 +234,7 @@ pub fn js_object_to_transform_blocks<'a, T: Context<'a>>(
263234
NonEmptyVec::try_from(&blocks).unwrap()
264235
}
265236

266-
///
267-
/// Iterate through the provided internal TransformBlocks and convert each block to an external array of transform block objects. Marked as dead code because usage
268-
/// of this function in the wrapped macro in `api256.rs` can't be parsed by Rust
269-
///
270-
#[allow(dead_code)]
237+
/// Iterate through the provided internal TransformBlocks and convert each block to an external array of transform block objects.
271238
pub fn transform_blocks_to_js_object<'a, T: Context<'a>>(
272239
cx: &mut T,
273240
transform_blocks: Vec<TransformBlock>,
@@ -303,11 +270,7 @@ pub fn transform_blocks_to_js_object<'a, T: Context<'a>>(
303270
Ok(blocks_array)
304271
}
305272

306-
///
307-
/// Convert a JsObject with various encrypted value keys into a EncryptedOnce or TransformedValue value. Marked as dead code because usage
308-
/// of this function in the wrapped macro in `api256.rs` can't be parsed by Rust
309-
///
310-
#[allow(dead_code)]
273+
/// Convert a JsObject with various encrypted value keys into a EncryptedOnce or TransformedValue value.
311274
pub fn js_object_to_encrypted_value<'a, T: Context<'a>>(
312275
cx: &mut T,
313276
object: Handle<JsObject>,
@@ -380,11 +343,7 @@ pub fn js_object_to_encrypted_value<'a, T: Context<'a>>(
380343
encrypted_value
381344
}
382345

383-
///
384-
/// Convert a Recrypt EncryptedValue into a JsObbject with expeted properties and bytes converted to Buffers. Marked as dead code because usage
385-
/// of this function in the wrapped macro in `api256.rs` can't be parsed by Rust
386-
///
387-
#[allow(dead_code)]
346+
/// Convert a Recrypt EncryptedValue into a JsObbject with expeted properties and bytes converted to Buffers.
388347
pub fn encrypted_value_to_js_object<'a, T: Context<'a>>(
389348
cx: &mut T,
390349
encrypted_value: EncryptedValue,

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131
"node-pre-gyp": "^0.14.0"
3232
},
3333
"devDependencies": {
34-
"@types/node": "^12.12.20",
34+
"@types/node": "^12.12.27",
3535
"benchmark": "^2.1.4",
36-
"jest": "^24.9.0",
37-
"jest-extended": "^0.11.2",
36+
"jest": "^25.1.0",
37+
"jest-extended": "^0.11.5",
3838
"neon-cli": "^0.3.3",
3939
"shelljs": "^0.8.3"
4040
},

test/recrypt-node.test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,4 +466,30 @@ describe("Recrypt-Node", () => {
466466
expect(transformKeyBytes).toHaveLength(672);
467467
});
468468
});
469+
470+
describe("addPrivateKeys", () => {
471+
it("should add together the provided keys", () => {
472+
//prettier-ignore
473+
const key1 = Buffer.from([1, 2, 0, 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, 1, 1, 0]);
474+
//prettier-ignore
475+
const key2 = Buffer.from([1, 1, 1, 104, 32, 121, 170, 221, 21, 229, 188, 159, 140, 164, 44, 173, 30, 151, 210, 60, 34, 10, 160, 186, 168, 36, 102, 174, 64, 0, 0, 1]);
476+
expect(recrypt.addPrivateKeys(key1, key2)).toEqual(
477+
//prettier-ignore
478+
Buffer.from([2, 3, 2, 69, 148, 131, 156, 115, 19, 56, 151, 204, 201, 94, 138, 31, 232, 254, 219, 251, 63, 158, 178, 214, 155, 152, 238, 175, 244, 1, 1, 1])
479+
);
480+
});
481+
});
482+
483+
describe("subtractPrivateKeys", () => {
484+
it("should subtract the provided keys", () => {
485+
//prettier-ignore
486+
const key1 = Buffer.from([1, 2, 0, 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, 1, 1, 0]);
487+
//prettier-ignore
488+
const key2 = Buffer.from([1, 1, 1, 104, 32, 121, 170, 221, 21, 229, 188, 159, 140, 164, 44, 173, 30, 151, 210, 60, 34, 10, 160, 186, 168, 36, 102, 174, 64, 0, 0, 1]);
489+
expect(recrypt.subtractPrivateKeys(key1, key2)).toEqual(
490+
//prettier-ignore
491+
Buffer.from([0, 0, 255, 117, 83, 144, 70, 184, 231, 109, 30, 141, 176, 22, 48, 197, 171, 207, 55, 130, 251, 137, 113, 97, 75, 80, 33, 83, 116, 1, 0, 255])
492+
);
493+
});
494+
});
469495
});

0 commit comments

Comments
 (0)