Skip to content

Commit e7d2dfb

Browse files
savely-krasovskykigawas
authored andcommitted
New default KDF (#83)
* New default KDF: HKDF-HMAC-SHA256 instead of just SHA256 * Updated README.md, few fixes * Update README.md * Fix hkdf * Update crypt.test.ts
1 parent 5c837b2 commit e7d2dfb

File tree

8 files changed

+50
-16
lines changed

8 files changed

+50
-16
lines changed

.circleci/config.yml

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@ defaults: &defaults
55
docker:
66
- image: circleci/node:12
77

8-
98
jobs:
109
test:
1110
<<: *defaults
1211
steps:
1312
- checkout
1413
- restore_cache:
1514
keys:
16-
- v1-dependencies-{{ checksum "package-lock.json" }}
17-
- v1-dependencies-
15+
- v1-dependencies-{{ checksum "package-lock.json" }}
16+
- v1-dependencies-
1817
- run:
1918
name: Install dependencies
2019
command: npm install
@@ -24,7 +23,7 @@ jobs:
2423
key: v1-dependencies-{{ checksum "package-lock.json" }}
2524
- run:
2625
name: Run tests and build js files
27-
command: npm test && npm run build && npm pack --dry-run
26+
command: npm test -- --bail --ci && npm run build && npm pack --dry-run
2827
- run:
2928
name: Upload coverage
3029
command: npx codecov

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# eciesjs
22

3-
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/ba01a8bb2d3344f29f98157ccbd14519)](https://app.codacy.com/app/ecies/js)
3+
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/47784cde956642b1b9e8e33cb8551674)](https://app.codacy.com/app/ecies/js)
44
[![License](https://img.shields.io/github/license/ecies/js.svg)](https://github.com/ecies/js)
55
[![Npm Package](https://img.shields.io/npm/v/eciesjs.svg)](https://www.npmjs.com/package/eciesjs)
66
[![Circle CI](https://img.shields.io/circleci/project/ecies/js/master.svg)](https://circleci.com/gh/ecies/js)
@@ -57,6 +57,7 @@ Returns: **Buffer**
5757
static fromHex(hex: string): PrivateKey;
5858
constructor(secret?: Buffer);
5959
toHex(): string;
60+
encapsulateKEM(pub: PublicKey): Buffer;
6061
ecdh(pub: PublicKey): Buffer;
6162
equals(other: PrivateKey): boolean;
6263
```
@@ -76,6 +77,7 @@ readonly publicKey: PublicKey;
7677
static fromHex(hex: string): PublicKey;
7778
constructor(buffer: Buffer);
7879
toHex(compressed?: boolean): string;
80+
decapsulateKEM(priv: PrivateKey): Buffer;
7981
equals(other: PublicKey): boolean;
8082
```
8183

package-lock.json

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
},
4242
"dependencies": {
4343
"@types/secp256k1": "^3.5.0",
44+
"futoin-hkdf": "^1.2.0",
4445
"secp256k1": "^3.6.0"
4546
}
4647
}

src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { aesDecrypt, aesEncrypt, decodeHex, getValidSecret, remove0x, sha256 } f
44
export function encrypt(receiverPubhex: string, msg: Buffer): Buffer {
55
const disposableKey = new PrivateKey();
66
const receiverPubkey = PublicKey.fromHex(receiverPubhex);
7-
const aesKey = disposableKey.ecdh(receiverPubkey);
7+
const aesKey = disposableKey.encapsulateKEM(receiverPubkey);
88
const encrypted = aesEncrypt(aesKey, msg);
99
return Buffer.concat([disposableKey.publicKey.uncompressed, encrypted]);
1010
}
@@ -13,7 +13,7 @@ export function decrypt(receiverPrvhex: string, msg: Buffer): Buffer {
1313
const receiverPrvkey = PrivateKey.fromHex(receiverPrvhex);
1414
const senderPubkey = new PublicKey(msg.slice(0, 65));
1515
const encrypted = msg.slice(65);
16-
const aesKey = receiverPrvkey.ecdh(senderPubkey);
16+
const aesKey = senderPubkey.decapsulateKEM(receiverPrvkey);
1717
return aesDecrypt(aesKey, encrypted);
1818
}
1919

src/keys/PrivateKey.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import hkdf from "futoin-hkdf";
12
import secp256k1 from "secp256k1";
23

34
import { decodeHex, getValidSecret } from "../utils";
@@ -24,8 +25,17 @@ export default class PrivateKey {
2425
return `0x${this.secret.toString("hex")}`;
2526
}
2627

27-
public ecdh(pub: PublicKey) {
28-
return secp256k1.ecdh(pub.compressed, this.secret);
28+
public encapsulateKEM(pub: PublicKey): Buffer {
29+
return hkdf(Buffer.concat([
30+
this.publicKey.uncompressed,
31+
this.multiply(pub),
32+
]), 32, {
33+
hash: "SHA-256",
34+
});
35+
}
36+
37+
public multiply(pub: PublicKey): Buffer {
38+
return secp256k1.ecdhUnsafe(pub.compressed, this.secret, false);
2939
}
3040

3141
public equals(other: PrivateKey): boolean {

src/keys/PublicKey.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import hkdf from "futoin-hkdf";
12
import secp256k1 from "secp256k1";
23

34
import { decodeHex } from "../utils";
5+
import PrivateKey from "./PrivateKey";
46

57
export default class PublicKey {
68

@@ -31,6 +33,15 @@ export default class PublicKey {
3133
}
3234
}
3335

36+
public decapsulateKEM(priv: PrivateKey): Buffer {
37+
return hkdf(Buffer.concat([
38+
this.uncompressed,
39+
priv.multiply(this),
40+
]), 32, {
41+
hash: "SHA-256",
42+
});
43+
}
44+
3445
public equals(other: PublicKey): boolean {
3546
return this.uncompressed.equals(other.uncompressed);
3647
}

src/tests/crypt.test.ts

+13-7
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,21 @@ describe("test keys", () => {
101101
expect(ethPub.equals(ethPrv.publicKey)).to.be.equal(true);
102102
});
103103

104-
it("tests ecdh", () => {
105-
const one = Buffer.from(new Uint8Array(32));
106-
one[31] = 1;
104+
it("tests multiply and hkdf", () => {
107105
const two = Buffer.from(new Uint8Array(32));
108106
two[31] = 2;
109-
110-
const k1 = new PrivateKey(one);
111-
const k2 = new PrivateKey(two);
112-
expect(k1.ecdh(k2.publicKey).equals(k2.ecdh(k1.publicKey))).to.be.equal(true);
107+
const three = Buffer.from(new Uint8Array(32));
108+
three[31] = 3;
109+
110+
const k1 = new PrivateKey(two);
111+
const k2 = new PrivateKey(three);
112+
expect(k1.multiply(k2.publicKey).equals(k2.multiply(k1.publicKey))).to.be.equal(true);
113+
114+
const derived = k1.encapsulateKEM(k2.publicKey);
115+
const knownDerived = Buffer.from(decodeHex(
116+
"6f982d63e8590c9d9b5b4c1959ff80315d772edd8f60287c9361d548d5200f82",
117+
));
118+
expect(derived.equals(knownDerived)).to.be.equal(true);
113119
});
114120

115121
});

0 commit comments

Comments
 (0)