mirror of
https://github.com/fluencelabs/js-libp2p-noise
synced 2025-04-25 14:12:30 +00:00
Move remaining functions from XX
This commit is contained in:
parent
0290df8685
commit
7b9118e15b
@ -8,6 +8,39 @@ import {getHkdf} from "../utils";
|
|||||||
export class AbstractHandshake {
|
export class AbstractHandshake {
|
||||||
protected minNonce = 0;
|
protected minNonce = 0;
|
||||||
|
|
||||||
|
public encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes): bytes {
|
||||||
|
const e = this.encrypt(cs.k, cs.n, ad, plaintext);
|
||||||
|
this.setNonce(cs, this.incrementNonce(cs.n));
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public decryptWithAd(cs: CipherState, ad: bytes, ciphertext: bytes): bytes {
|
||||||
|
const plaintext = this.decrypt(cs.k, cs.n, ad, ciphertext);
|
||||||
|
this.setNonce(cs, this.incrementNonce(cs.n));
|
||||||
|
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Cipher state related
|
||||||
|
protected hasKey(cs: CipherState): boolean {
|
||||||
|
return !this.isEmptyKey(cs.k);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setNonce(cs: CipherState, nonce: uint32): void {
|
||||||
|
cs.n = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createEmptyKey(): bytes32 {
|
||||||
|
return Buffer.alloc(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected isEmptyKey(k: bytes32): boolean {
|
||||||
|
const emptyKey = this.createEmptyKey();
|
||||||
|
return emptyKey.equals(k);
|
||||||
|
}
|
||||||
|
|
||||||
protected incrementNonce(n: uint32): uint32 {
|
protected incrementNonce(n: uint32): uint32 {
|
||||||
return n + 1;
|
return n + 1;
|
||||||
}
|
}
|
||||||
@ -31,6 +64,41 @@ export class AbstractHandshake {
|
|||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected encryptAndHash(ss: SymmetricState, plaintext: bytes): bytes {
|
||||||
|
let ciphertext;
|
||||||
|
if (this.hasKey(ss.cs)) {
|
||||||
|
ciphertext = this.encryptWithAd(ss.cs, ss.h, plaintext);
|
||||||
|
} else {
|
||||||
|
ciphertext = plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mixHash(ss, ciphertext);
|
||||||
|
return ciphertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected decrypt(k: bytes32, n: uint32, ad: bytes, ciphertext: bytes): bytes {
|
||||||
|
const nonce = this.nonceToBytes(n);
|
||||||
|
const ctx = new AEAD();
|
||||||
|
|
||||||
|
ctx.init(k, nonce);
|
||||||
|
ctx.aad(ad);
|
||||||
|
ctx.decrypt(ciphertext);
|
||||||
|
|
||||||
|
// Decryption is done on the sent reference
|
||||||
|
return ciphertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected decryptAndHash(ss: SymmetricState, ciphertext: bytes): bytes {
|
||||||
|
let plaintext;
|
||||||
|
if (this.hasKey(ss.cs)) {
|
||||||
|
plaintext = this.decryptWithAd(ss.cs, ss.h, ciphertext);
|
||||||
|
} else {
|
||||||
|
plaintext = ciphertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mixHash(ss, ciphertext);
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
protected dh(privateKey: bytes32, publicKey: bytes32): bytes32 {
|
protected dh(privateKey: bytes32, publicKey: bytes32): bytes32 {
|
||||||
const derived = x25519.derive(publicKey, privateKey);
|
const derived = x25519.derive(publicKey, privateKey);
|
||||||
@ -57,4 +125,35 @@ export class AbstractHandshake {
|
|||||||
const n = this.minNonce;
|
const n = this.minNonce;
|
||||||
return { k, n };
|
return { k, n };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Symmetric state related
|
||||||
|
|
||||||
|
protected initializeSymmetric(protocolName: string): SymmetricState {
|
||||||
|
const protocolNameBytes: bytes = Buffer.from(protocolName, 'utf-8');
|
||||||
|
const h = this.hashProtocolName(protocolNameBytes);
|
||||||
|
|
||||||
|
const ck = h;
|
||||||
|
const key = this.createEmptyKey();
|
||||||
|
const cs: CipherState = this.initializeKey(key);
|
||||||
|
|
||||||
|
return { cs, ck, h };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected hashProtocolName(protocolName: bytes): bytes32 {
|
||||||
|
if (protocolName.length <= 32) {
|
||||||
|
const h = Buffer.alloc(32);
|
||||||
|
protocolName.copy(h);
|
||||||
|
return h;
|
||||||
|
} else {
|
||||||
|
return this.getHash(protocolName, Buffer.alloc(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected split (ss: SymmetricState) {
|
||||||
|
const [ tempk1, tempk2 ] = getHkdf(ss.ck, Buffer.alloc(0));
|
||||||
|
const cs1 = this.initializeKey(tempk1);
|
||||||
|
const cs2 = this.initializeKey(tempk2);
|
||||||
|
|
||||||
|
return { cs1, cs2 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,6 @@ import {AbstractHandshake} from "./abstract-handshake";
|
|||||||
|
|
||||||
|
|
||||||
export class XXHandshake extends AbstractHandshake {
|
export class XXHandshake extends AbstractHandshake {
|
||||||
private createEmptyKey(): bytes32 {
|
|
||||||
return Buffer.alloc(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
private initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState {
|
private initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): HandshakeState {
|
||||||
const name = "Noise_XX_25519_ChaChaPoly_SHA256";
|
const name = "Noise_XX_25519_ChaChaPoly_SHA256";
|
||||||
const ss = this.initializeSymmetric(name);
|
const ss = this.initializeSymmetric(name);
|
||||||
@ -32,101 +28,6 @@ export class XXHandshake extends AbstractHandshake {
|
|||||||
return { ss, s, rs, psk, re };
|
return { ss, s, rs, psk, re };
|
||||||
}
|
}
|
||||||
|
|
||||||
private decrypt(k: bytes32, n: uint32, ad: bytes, ciphertext: bytes): bytes {
|
|
||||||
const nonce = this.nonceToBytes(n);
|
|
||||||
const ctx = new AEAD();
|
|
||||||
|
|
||||||
ctx.init(k, nonce);
|
|
||||||
ctx.aad(ad);
|
|
||||||
ctx.decrypt(ciphertext);
|
|
||||||
|
|
||||||
// Decryption is done on the sent reference
|
|
||||||
return ciphertext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private isEmptyKey(k: bytes32): boolean {
|
|
||||||
const emptyKey = this.createEmptyKey();
|
|
||||||
return emptyKey.equals(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cipher state related
|
|
||||||
private hasKey(cs: CipherState): boolean {
|
|
||||||
return !this.isEmptyKey(cs.k);
|
|
||||||
}
|
|
||||||
|
|
||||||
private setNonce(cs: CipherState, nonce: uint32): void {
|
|
||||||
cs.n = nonce;
|
|
||||||
}
|
|
||||||
|
|
||||||
public encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes): bytes {
|
|
||||||
const e = this.encrypt(cs.k, cs.n, ad, plaintext);
|
|
||||||
this.setNonce(cs, this.incrementNonce(cs.n));
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public decryptWithAd(cs: CipherState, ad: bytes, ciphertext: bytes): bytes {
|
|
||||||
const plaintext = this.decrypt(cs.k, cs.n, ad, ciphertext);
|
|
||||||
this.setNonce(cs, this.incrementNonce(cs.n));
|
|
||||||
|
|
||||||
return plaintext;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symmetric state related
|
|
||||||
|
|
||||||
private initializeSymmetric(protocolName: string): SymmetricState {
|
|
||||||
const protocolNameBytes: bytes = Buffer.from(protocolName, 'utf-8');
|
|
||||||
const h = this.hashProtocolName(protocolNameBytes);
|
|
||||||
|
|
||||||
const ck = h;
|
|
||||||
const key = this.createEmptyKey();
|
|
||||||
const cs: CipherState = this.initializeKey(key);
|
|
||||||
|
|
||||||
return { cs, ck, h };
|
|
||||||
}
|
|
||||||
|
|
||||||
private hashProtocolName(protocolName: bytes): bytes32 {
|
|
||||||
if (protocolName.length <= 32) {
|
|
||||||
const h = Buffer.alloc(32);
|
|
||||||
protocolName.copy(h);
|
|
||||||
return h;
|
|
||||||
} else {
|
|
||||||
return this.getHash(protocolName, Buffer.alloc(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private encryptAndHash(ss: SymmetricState, plaintext: bytes): bytes {
|
|
||||||
let ciphertext;
|
|
||||||
if (this.hasKey(ss.cs)) {
|
|
||||||
ciphertext = this.encryptWithAd(ss.cs, ss.h, plaintext);
|
|
||||||
} else {
|
|
||||||
ciphertext = plaintext;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.mixHash(ss, ciphertext);
|
|
||||||
return ciphertext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private decryptAndHash(ss: SymmetricState, ciphertext: bytes): bytes {
|
|
||||||
let plaintext;
|
|
||||||
if (this.hasKey(ss.cs)) {
|
|
||||||
plaintext = this.decryptWithAd(ss.cs, ss.h, ciphertext);
|
|
||||||
} else {
|
|
||||||
plaintext = ciphertext;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.mixHash(ss, ciphertext);
|
|
||||||
return plaintext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private split (ss: SymmetricState) {
|
|
||||||
const [ tempk1, tempk2 ] = getHkdf(ss.ck, Buffer.alloc(0));
|
|
||||||
const cs1 = this.initializeKey(tempk1);
|
|
||||||
const cs2 = this.initializeKey(tempk2);
|
|
||||||
|
|
||||||
return { cs1, cs2 };
|
|
||||||
}
|
|
||||||
|
|
||||||
private writeMessageA(hs: HandshakeState, payload: bytes): MessageBuffer {
|
private writeMessageA(hs: HandshakeState, payload: bytes): MessageBuffer {
|
||||||
const ns = Buffer.alloc(0);
|
const ns = Buffer.alloc(0);
|
||||||
hs.e = generateKeypair();
|
hs.e = generateKeypair();
|
||||||
|
@ -4,7 +4,7 @@ import { Buffer } from 'buffer';
|
|||||||
import { XXHandshake } from "../../src/handshakes/xx";
|
import { XXHandshake } from "../../src/handshakes/xx";
|
||||||
import { KeyPair } from "../../src/@types/libp2p";
|
import { KeyPair } from "../../src/@types/libp2p";
|
||||||
import { generateEd25519Keys } from "../utils";
|
import { generateEd25519Keys } from "../utils";
|
||||||
import {createHandshakePayload, generateKeypair, getHandshakePayload} from "../../src/utils";
|
import {createHandshakePayload, generateKeypair, getHandshakePayload, getHkdf} from "../../src/utils";
|
||||||
|
|
||||||
describe("Index", () => {
|
describe("Index", () => {
|
||||||
const prologue = Buffer.from("/noise", "utf-8");
|
const prologue = Buffer.from("/noise", "utf-8");
|
||||||
@ -29,7 +29,7 @@ describe("Index", () => {
|
|||||||
const ck = Buffer.alloc(32);
|
const ck = Buffer.alloc(32);
|
||||||
ckBytes.copy(ck);
|
ckBytes.copy(ck);
|
||||||
|
|
||||||
const [k1, k2, k3] = xx.getHkdf(ck, ikm);
|
const [k1, k2, k3] = getHkdf(ck, ikm);
|
||||||
expect(k1.toString('hex')).to.equal('cc5659adff12714982f806e2477a8d5ddd071def4c29bb38777b7e37046f6914');
|
expect(k1.toString('hex')).to.equal('cc5659adff12714982f806e2477a8d5ddd071def4c29bb38777b7e37046f6914');
|
||||||
expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa');
|
expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa');
|
||||||
expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68');
|
expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user