diff --git a/src/xx.ts b/src/xx.ts index 261c692..ec869d8 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -4,54 +4,54 @@ import { AEAD, x25519, HKDF, SHA256 } from 'bcrypto'; import { BN } from 'bn.js'; export interface KeyPair { - publicKey: bytes32, - privateKey: bytes32, + publicKey: bytes32; + privateKey: bytes32; } interface MessageBuffer { - ne: bytes32, - ns: bytes, - ciphertext: bytes + ne: bytes32; + ns: bytes; + ciphertext: bytes; } type CipherState = { - k: bytes32, - n: uint32, + k: bytes32; + n: uint32; } type SymmetricState = { - cs: CipherState, - ck: bytes32, // chaining key - h: bytes32, // handshake hash + cs: CipherState; + ck: bytes32; // chaining key + h: bytes32; // handshake hash } type HandshakeState = { - ss: SymmetricState, - s: KeyPair, - e?: KeyPair, - rs: bytes32, - re: bytes32, - psk: bytes32, + ss: SymmetricState; + s: KeyPair; + e?: KeyPair; + rs: bytes32; + re: bytes32; + psk: bytes32; } type NoiseSession = { - hs: HandshakeState, - h?: bytes32, - cs1?: CipherState, - cs2?: CipherState, - mc: uint64, - i: boolean, + hs: HandshakeState; + h?: bytes32; + cs1?: CipherState; + cs2?: CipherState; + mc: uint64; + i: boolean; } export type Hkdf = [bytes, bytes, bytes]; const minNonce = 0; export class XXHandshake { - private createEmptyKey() : bytes32 { + private createEmptyKey(): bytes32 { return Buffer.alloc(32); } - private async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { + private async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): Promise { const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); this.mixHash(ss, prologue); @@ -60,7 +60,7 @@ export class XXHandshake { return { ss, s, rs, psk, re }; } - private async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { + private async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32): Promise { const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); this.mixHash(ss, prologue); @@ -69,25 +69,25 @@ export class XXHandshake { return { ss, s, rs, psk, re }; } - private incrementNonce(n: uint32) : uint32 { + private incrementNonce(n: uint32): uint32 { return n + 1; } - private dh(privateKey: bytes32, publicKey: bytes32) : bytes32 { + private dh(privateKey: bytes32, publicKey: bytes32): bytes32 { const derived = x25519.derive(publicKey, privateKey); const result = Buffer.alloc(32); derived.copy(result); return result; } - private nonceToBytes(n: uint32) : bytes { + private nonceToBytes(n: uint32): bytes { const nonce = Buffer.alloc(12); nonce.writeUInt32LE(n, 4); return nonce; } - private encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes) : bytes { + private encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes): bytes { const nonce = this.nonceToBytes(n); const ctx = new AEAD(); @@ -99,7 +99,7 @@ export class XXHandshake { return plaintext; } - private decrypt(k: bytes32, n: uint32, ad: bytes, ciphertext: bytes) : bytes { + private decrypt(k: bytes32, n: uint32, ad: bytes, ciphertext: bytes): bytes { const nonce = this.nonceToBytes(n); const ctx = new AEAD(); @@ -111,33 +111,33 @@ export class XXHandshake { return ciphertext; } - private isEmptyKey(k: bytes32) : boolean { + private isEmptyKey(k: bytes32): boolean { const emptyKey = this.createEmptyKey(); return emptyKey.equals(k); } // Cipher state related - private initializeKey(k: bytes32) : CipherState { + private initializeKey(k: bytes32): CipherState { const n = minNonce; return { k, n }; } - private hasKey(cs: CipherState) : boolean { + private hasKey(cs: CipherState): boolean { return !this.isEmptyKey(cs.k); } - private setNonce(cs: CipherState, nonce: uint32) : void { + private setNonce(cs: CipherState, nonce: uint32): void { cs.n = nonce; } - public encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes) : bytes { + 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 { + 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)); @@ -146,13 +146,13 @@ export class XXHandshake { // Symmetric state related - private async initializeSymmetric(protocolName: string) : Promise { + private async initializeSymmetric(protocolName: string): Promise { const protocolNameBytes: bytes = Buffer.from(protocolName, 'utf-8'); const h = await this.hashProtocolName(protocolNameBytes); const ck = h; const key = this.createEmptyKey(); - const cs:CipherState = this.initializeKey(key); + const cs: CipherState = this.initializeKey(key); return { cs, ck, h }; } @@ -163,9 +163,9 @@ export class XXHandshake { ss.ck = ck; } - private async hashProtocolName(protocolName: bytes) : Promise { + private async hashProtocolName(protocolName: bytes): Promise { if (protocolName.length <= 32) { - let h = Buffer.alloc(32); + const h = Buffer.alloc(32); protocolName.copy(h); return h; } else { @@ -173,7 +173,7 @@ export class XXHandshake { } } - public getHkdf(ck: bytes32, ikm: bytes) : Hkdf { + public getHkdf(ck: bytes32, ikm: bytes): Hkdf { const info = Buffer.alloc(0); const prk = HKDF.extract(SHA256, ikm, ck); const okm = HKDF.expand(SHA256, prk, info, 96); @@ -189,11 +189,11 @@ export class XXHandshake { ss.h = this.getHash(ss.h, data); } - private getHash(a: bytes, b: bytes) : bytes32 { + private getHash(a: bytes, b: bytes): bytes32 { return SHA256.digest(Buffer.from([...a, ...b])); } - private async encryptAndHash(ss: SymmetricState, plaintext: bytes) : Promise { + private async encryptAndHash(ss: SymmetricState, plaintext: bytes): Promise { let ciphertext; if (this.hasKey(ss.cs)) { ciphertext = this.encryptWithAd(ss.cs, ss.h, plaintext); @@ -205,7 +205,7 @@ export class XXHandshake { return ciphertext; } - private async decryptAndHash(ss: SymmetricState, ciphertext: bytes) : Promise { + private async decryptAndHash(ss: SymmetricState, ciphertext: bytes): Promise { let plaintext; if (this.hasKey(ss.cs)) { plaintext = this.decryptWithAd(ss.cs, ss.h, ciphertext); @@ -225,8 +225,8 @@ export class XXHandshake { return { cs1, cs2 }; } - private async writeMessageA(hs: HandshakeState, payload: bytes) : Promise { - let ns = Buffer.alloc(0); + private async writeMessageA(hs: HandshakeState, payload: bytes): Promise { + const ns = Buffer.alloc(0); hs.e = await this.generateKeypair(); const ne = hs.e.publicKey; @@ -236,7 +236,7 @@ export class XXHandshake { return {ne, ns, ciphertext}; } - private async writeMessageB(hs: HandshakeState, payload: bytes) : Promise { + private async writeMessageB(hs: HandshakeState, payload: bytes): Promise { hs.e = await this.generateKeypair(); const ne = hs.e.publicKey; this.mixHash(hs.ss, ne); @@ -263,7 +263,7 @@ export class XXHandshake { return { h: hs.ss.h, messageBuffer, cs1, cs2 }; } - private async writeMessageRegular(cs: CipherState, payload: bytes) : Promise { + private async writeMessageRegular(cs: CipherState, payload: bytes): Promise { const ciphertext = this.encryptWithAd(cs, Buffer.alloc(0), payload); const ne = this.createEmptyKey(); const ns = Buffer.alloc(0); @@ -271,7 +271,7 @@ export class XXHandshake { return { ne, ns, ciphertext }; } - private async readMessageA(hs: HandshakeState, message: MessageBuffer) : Promise { + private async readMessageA(hs: HandshakeState, message: MessageBuffer): Promise { if (x25519.publicKeyVerify(message.ne)) { hs.re = message.ne; } @@ -280,7 +280,7 @@ export class XXHandshake { return await this.decryptAndHash(hs.ss, message.ciphertext); } - private async readMessageB(hs: HandshakeState, message: MessageBuffer) : Promise { + private async readMessageB(hs: HandshakeState, message: MessageBuffer): Promise { if (x25519.publicKeyVerify(message.ne)) { hs.re = message.ne; } @@ -314,11 +314,11 @@ export class XXHandshake { return { h: hs.ss.h, plaintext, cs1, cs2 }; } - private readMessageRegular(cs: CipherState, message: MessageBuffer) : bytes { + private readMessageRegular(cs: CipherState, message: MessageBuffer): bytes { return this.decryptWithAd(cs, Buffer.alloc(0), message.ciphertext); } - public async generateKeypair() : Promise { + public async generateKeypair(): Promise { const privateKey = x25519.privateKeyGenerate(); const publicKey = x25519.publicKeyCreate(privateKey); @@ -328,7 +328,7 @@ export class XXHandshake { } } - public async initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32) : Promise { + public async initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32): Promise { const psk = this.createEmptyKey(); let hs; @@ -345,7 +345,7 @@ export class XXHandshake { }; } - public async sendMessage(session: NoiseSession, message: bytes) : Promise { + public async sendMessage(session: NoiseSession, message: bytes): Promise { let messageBuffer: MessageBuffer; if (session.mc.eqn(0)) { messageBuffer = await this.writeMessageA(session.hs, message); @@ -379,7 +379,7 @@ export class XXHandshake { return messageBuffer; } - public async recvMessage(session: NoiseSession, message: MessageBuffer) : Promise { + public async recvMessage(session: NoiseSession, message: MessageBuffer): Promise { let plaintext: bytes; if (session.mc.eqn(0)) { plaintext = await this.readMessageA(session.hs, message);