Move remaining functions from XX

This commit is contained in:
Belma Gutlic 2019-12-25 11:11:07 +01:00
parent 0290df8685
commit 7b9118e15b
3 changed files with 101 additions and 101 deletions

View File

@ -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 };
}
} }

View File

@ -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();

View File

@ -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');