Create part of XX test and update code accordingly

This commit is contained in:
morrigan 2019-11-06 13:24:30 +01:00
parent 68cc670058
commit fe706fbd71
5 changed files with 172 additions and 18 deletions

View File

@ -16,6 +16,7 @@
"devDependencies": {
"@babel/cli": "^7.6.4",
"@babel/core": "^7.6.4",
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
"@babel/plugin-transform-runtime": "^7.6.2",
"@babel/preset-env": "^7.6.3",
"@babel/preset-typescript": "^7.6.0",
@ -37,13 +38,15 @@
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-transform-runtime"
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-object-rest-spread"
]
},
"dependencies": {
"bcrypto": "^4.2.3",
"bn.js": "^5.0.0",
"buffer": "^5.4.3",
"libp2p-crypto": "^0.17.1"
"libp2p-crypto": "^0.17.1",
"protobufjs": "~6.8.8"
}
}

9
payload.proto Normal file
View File

@ -0,0 +1,9 @@
syntax = "proto3";
package pb;
message NoiseHandshakePayload {
bytes libp2p_key = 1;
bytes noise_static_key_signature = 2;
bytes libp2p_data = 3;
bytes libp2p_data_signature = 4;
}

View File

@ -55,7 +55,7 @@ export class XXHandshake {
private async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise<HandshakeState> {
const name = "Noise_XX_25519_ChaChaPoly_SHA256";
const ss = await this.initializeSymmetric(name);
await this.mixHash(ss, prologue);
this.mixHash(ss, prologue);
const re = Buffer.alloc(32);
return { ss, s, rs, psk, re };
@ -64,7 +64,7 @@ export class XXHandshake {
private async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise<HandshakeState> {
const name = "Noise_XX_25519_ChaChaPoly_SHA256";
const ss = await this.initializeSymmetric(name);
await this.mixHash(ss, prologue);
this.mixHash(ss, prologue);
const re = Buffer.alloc(32);
return { ss, s, rs, psk, re };
@ -143,6 +143,7 @@ export class XXHandshake {
private async initializeSymmetric(protocolName: string) : Promise<SymmetricState> {
const protocolNameBytes: bytes = Buffer.from(protocolName, 'utf-8');
const h = await this.hashProtocolName(protocolNameBytes);
const ck = h;
const key = this.createEmptyKey();
const cs = this.initializeKey(key);
@ -158,11 +159,11 @@ export class XXHandshake {
private async hashProtocolName(protocolName: bytes) : Promise<bytes32> {
if (protocolName.length <= 32) {
const h = Buffer.alloc(32);
let h = Buffer.alloc(32);
protocolName.copy(h);
return h;
} else {
return await this.getHash(protocolName, Buffer.from([]));
return this.getHash(protocolName, Buffer.alloc(0));
}
}
@ -178,12 +179,12 @@ export class XXHandshake {
return [ k1, k2, k3 ];
}
private async mixHash(ss: SymmetricState, data: bytes) {
ss.h = await this.getHash(ss.h, data);
private mixHash(ss: SymmetricState, data: bytes) {
ss.h = this.getHash(ss.h, data);
}
private async getHash(a: bytes, b: bytes) : Promise<bytes32> {
return await crypto.hmac.create('sha256', Buffer.from([...a, ...b]))
private getHash(a: bytes, b: bytes) : bytes32 {
return SHA256.digest(Buffer.from([...a, ...b]));
}
private async encryptAndHash(ss: SymmetricState, plaintext: bytes) : Promise<bytes> {
@ -194,7 +195,7 @@ export class XXHandshake {
ciphertext = plaintext;
}
await this.mixHash(ss, ciphertext);
this.mixHash(ss, ciphertext);
return ciphertext;
}
@ -206,7 +207,7 @@ export class XXHandshake {
plaintext = ciphertext;
}
await this.mixHash(ss, ciphertext);
this.mixHash(ss, ciphertext);
return plaintext;
}
@ -222,7 +223,8 @@ export class XXHandshake {
let ns = Buffer.alloc(0);
hs.e = await this.generateKeypair();
const ne = hs.e.publicKey;
await this.mixHash(hs.ss, ne);
this.mixHash(hs.ss, ne);
const ciphertext = await this.encryptAndHash(hs.ss, payload);
return {ne, ns, ciphertext};
@ -231,7 +233,7 @@ export class XXHandshake {
private async writeMessageB(hs: HandshakeState, payload: bytes) : Promise<MessageBuffer> {
hs.e = await this.generateKeypair();
const ne = hs.e.publicKey;
await this.mixHash(hs.ss, ne);
this.mixHash(hs.ss, ne);
await this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re));
const spk = Buffer.from(hs.s.publicKey);
const ns = await this.encryptAndHash(hs.ss, spk);
@ -264,14 +266,14 @@ export class XXHandshake {
private async readMessageA(hs: HandshakeState, message: MessageBuffer) : Promise<bytes> {
// TODO: validate public key here
await this.mixHash(hs.ss, hs.re);
this.mixHash(hs.ss, hs.re);
return await this.decryptAndHash(hs.ss, message.ciphertext);
}
private async readMessageB(hs: HandshakeState, message: MessageBuffer) : Promise<bytes> {
// TODO: validate public key here
await this.mixHash(hs.ss, hs.re);
this.mixHash(hs.ss, hs.re);
if (!hs.e) {
throw new Error("Handshake state `e` param is missing.");
}
@ -302,7 +304,12 @@ export class XXHandshake {
}
public async generateKeypair() : Promise<KeyPair> {
return await crypto.keys.generateKeyPair('ed25519');
const Ed25519PrivateKey = await crypto.keys.generateKeyPair('ed25519');
return {
publicKey: Ed25519PrivateKey.public.bytes,
privateKey: Ed25519PrivateKey.bytes,
}
}
public async initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32) : Promise<NoiseSession> {

View File

@ -1,5 +1,7 @@
import { expect } from "chai";
import { expect, assert } from "chai";
import { Buffer } from 'buffer';
import * as crypto from 'libp2p-crypto';
import protobuf from 'protobufjs';
import { XXHandshake, KeyPair } from "../src/xx";
@ -28,4 +30,50 @@ describe("Index", () => {
expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa');
expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68');
})
async function generateKeypair() {
return await crypto.keys.generateKeyPair('ed25519');;
}
async function doHandshake() {
const xx = new XXHandshake();
const kpInit = await xx.generateKeypair();
const kpResp = await xx.generateKeypair();
const payloadString = Buffer.from("noise-libp2p-static-key:");
// initiator setup
const libp2pInitKeys = await generateKeypair();
const initSignedPayload = await libp2pInitKeys.sign(Buffer.concat([payloadString, kpInit.publicKey]));
// responder setup
const libp2pRespKeys = await generateKeypair();
const respSignedPayload = await libp2pRespKeys.sign(Buffer.concat([payloadString, kpResp.publicKey]));
// initiator: new XX noise session
const nsInit = await xx.initSession(true, prologue, kpInit, kpResp.publicKey);
// responder: new XX noise session
const nsResp = await xx.initSession(false, prologue, kpResp, kpInit.publicKey);
/* stage 0: initiator */
// initiator creates payload
const payloadProtoBuf = await protobuf.load("payload.proto");
const NoiseHandshakePayload = payloadProtoBuf.lookupType("pb.NoiseHandshakePayload");
const payloadInit = NoiseHandshakePayload.create({
libp2pKey: libp2pInitKeys.bytes.toString('hex'),
noiseStaticKeySignature: initSignedPayload,
});
const payloadInitEnc = NoiseHandshakePayload.encode(payloadInit).finish();
// initiator sends message
const message = Buffer.concat([Buffer.alloc(0), payloadInitEnc]);
const messageBuffer = await xx.sendMessage(nsInit, message);
expect(messageBuffer.ne.length).not.equal(0);
}
it("Test handshake", async () => {
await doHandshake();
})
});

View File

@ -718,6 +718,59 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
"@protobufjs/base64@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
"@protobufjs/codegen@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
"@protobufjs/eventemitter@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
"@protobufjs/fetch@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
dependencies:
"@protobufjs/aspromise" "^1.1.1"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/float@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
"@protobufjs/inquire@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
"@protobufjs/path@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
"@protobufjs/pool@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
"@protobufjs/utf8@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
"@types/chai@^4.2.4":
version "4.2.4"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.4.tgz#8936cffad3c96ec470a2dc26a38c3ba8b9b6f619"
@ -733,11 +786,21 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636"
integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==
"@types/long@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef"
integrity sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==
"@types/mocha@^5.2.7":
version "5.2.7"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea"
integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
"@types/node@^10.1.0":
version "10.17.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.3.tgz#65a8d9a6a0f6af55595a2d0020617959130d6495"
integrity sha512-QZ9CjUB3QoA3f2afw3utKlfRPhpmufB7jC2+oDhLWnXqoyx333fhKSQDLQu2EK7OE0a15X67eYiRAaJsHXrpMA==
"@types/node@^10.12.12":
version "10.17.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.2.tgz#41b5afbcde1a5a805302a4da3cf399499f1bbf64"
@ -2401,6 +2464,11 @@ log-symbols@2.2.0:
dependencies:
chalk "^2.0.1"
long@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
loose-envify@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@ -2982,6 +3050,25 @@ promise@~1.3.0:
dependencies:
is-promise "~1"
protobufjs@~6.8.8:
version "6.8.8"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c"
integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
"@protobufjs/codegen" "^2.0.4"
"@protobufjs/eventemitter" "^1.1.0"
"@protobufjs/fetch" "^1.1.0"
"@protobufjs/float" "^1.0.2"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/path" "^1.1.2"
"@protobufjs/pool" "^1.1.0"
"@protobufjs/utf8" "^1.1.0"
"@types/long" "^4.0.0"
"@types/node" "^10.1.0"
long "^4.0.0"
protocol-buffers-schema@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz#00434f608b4e8df54c59e070efeefc37fb4bb859"