mirror of https://github.com/waku-org/js-noise.git
refactor: cipher specific endianness for nonce
This commit is contained in:
parent
938789d7cd
commit
550e26533f
|
@ -2,15 +2,18 @@ import { ChaCha20Poly1305 } from "@stablelib/chacha20poly1305";
|
||||||
|
|
||||||
import { bytes32 } from "./@types/basic.js";
|
import { bytes32 } from "./@types/basic.js";
|
||||||
import { Cipher } from "./crypto.js";
|
import { Cipher } from "./crypto.js";
|
||||||
|
import { Nonce } from "./nonce.js";
|
||||||
|
|
||||||
export class ChaChaPoly implements Cipher {
|
export class ChaChaPoly implements Cipher {
|
||||||
encrypt(k: bytes32, n: Uint8Array, ad: Uint8Array, plaintext: Uint8Array): Uint8Array {
|
encrypt(k: bytes32, nonce: Nonce, ad: Uint8Array, plaintext: Uint8Array): Uint8Array {
|
||||||
const ctx = new ChaCha20Poly1305(k);
|
const ctx = new ChaCha20Poly1305(k);
|
||||||
|
const n = nonce.getBytes(true);
|
||||||
return ctx.seal(n, plaintext, ad);
|
return ctx.seal(n, plaintext, ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt(k: bytes32, n: Uint8Array, ad: Uint8Array, ciphertext: Uint8Array): Uint8Array | null {
|
decrypt(k: bytes32, nonce: Nonce, ad: Uint8Array, ciphertext: Uint8Array): Uint8Array | null {
|
||||||
const ctx = new ChaCha20Poly1305(k);
|
const ctx = new ChaCha20Poly1305(k);
|
||||||
|
const n = nonce.getBytes(true);
|
||||||
return ctx.open(n, ciphertext, ad);
|
return ctx.open(n, ciphertext, ad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { concat as uint8ArrayConcat } from "uint8arrays/concat";
|
||||||
|
|
||||||
import type { bytes32 } from "./@types/basic.js";
|
import type { bytes32 } from "./@types/basic.js";
|
||||||
import type { KeyPair } from "./@types/keypair.js";
|
import type { KeyPair } from "./@types/keypair.js";
|
||||||
|
import { Nonce } from "./nonce.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HKDF key derivation function
|
* HKDF key derivation function
|
||||||
|
@ -63,7 +64,7 @@ export interface Cipher {
|
||||||
* @param plaintext data to encrypt
|
* @param plaintext data to encrypt
|
||||||
* @returns sealed ciphertext including authentication tag
|
* @returns sealed ciphertext including authentication tag
|
||||||
*/
|
*/
|
||||||
encrypt(k: bytes32, n: Uint8Array, ad: Uint8Array, plaintext: Uint8Array): Uint8Array;
|
encrypt(k: bytes32, n: Nonce, ad: Uint8Array, plaintext: Uint8Array): Uint8Array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate and decrypt data
|
* Authenticate and decrypt data
|
||||||
|
@ -73,7 +74,7 @@ export interface Cipher {
|
||||||
* @param ciphertext data to decrypt
|
* @param ciphertext data to decrypt
|
||||||
* @returns plaintext if decryption was successful, `null` otherwise
|
* @returns plaintext if decryption was successful, `null` otherwise
|
||||||
*/
|
*/
|
||||||
decrypt(k: bytes32, n: Uint8Array, ad: Uint8Array, ciphertext: Uint8Array): Uint8Array | null;
|
decrypt(k: bytes32, n: Nonce, ad: Uint8Array, ciphertext: Uint8Array): Uint8Array | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -134,7 +134,7 @@ describe("js-noise", () => {
|
||||||
plaintext = randomBytes(128, rng);
|
plaintext = randomBytes(128, rng);
|
||||||
|
|
||||||
// We perform encryption using the Cipher State key, NonceMax and ad (not using the cypher state directly so it does not trigger the max nonce error)
|
// We perform encryption using the Cipher State key, NonceMax and ad (not using the cypher state directly so it does not trigger the max nonce error)
|
||||||
ciphertext = cipherState.cipher.encrypt(cipherState.getKey(), cipherState.getNonce().getBytes(), ad, plaintext);
|
ciphertext = cipherState.cipher.encrypt(cipherState.getKey(), cipherState.getNonce(), ad, plaintext);
|
||||||
|
|
||||||
// At this point ciphertext is a proper encryption of the original plaintext obtained with nonce equal to NonceMax
|
// At this point ciphertext is a proper encryption of the original plaintext obtained with nonce equal to NonceMax
|
||||||
// We can now test if decryption fails with a NoiseNonceMaxError error. Any subsequent decryption call over the Cipher State should fail similarly and leave the nonce unchanged
|
// We can now test if decryption fails with a NoiseNonceMaxError error. Any subsequent decryption call over the Cipher State should fail similarly and leave the nonce unchanged
|
||||||
|
|
|
@ -116,7 +116,7 @@ export class CipherState {
|
||||||
|
|
||||||
if (this.hasKey()) {
|
if (this.hasKey()) {
|
||||||
// If an encryption key is set in the Cipher state, we proceed with encryption
|
// If an encryption key is set in the Cipher state, we proceed with encryption
|
||||||
ciphertext = this.cipher.encrypt(this.k, this.n.getBytes(), ad, plaintext);
|
ciphertext = this.cipher.encrypt(this.k, this.n, ad, plaintext);
|
||||||
this.n.increment();
|
this.n.increment();
|
||||||
this.n.assertValue();
|
this.n.assertValue();
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ export class CipherState {
|
||||||
this.n.assertValue();
|
this.n.assertValue();
|
||||||
|
|
||||||
if (this.hasKey()) {
|
if (this.hasKey()) {
|
||||||
const plaintext = this.cipher.decrypt(this.k, this.n.getBytes(), ad, ciphertext);
|
const plaintext = this.cipher.decrypt(this.k, this.n, ad, ciphertext);
|
||||||
if (!plaintext) {
|
if (!plaintext) {
|
||||||
throw new Error("decryptWithAd failed");
|
throw new Error("decryptWithAd failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,11 @@ export class Nonce {
|
||||||
|
|
||||||
increment(): void {
|
increment(): void {
|
||||||
this.n++;
|
this.n++;
|
||||||
// Even though we're treating the nonce as 8 bytes, RFC7539 specifies 12 bytes for a nonce.
|
|
||||||
this.view.setUint32(4, this.n, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getBytes(): Uint8Array {
|
getBytes(littleEndian: boolean): Uint8Array {
|
||||||
|
// Even though we're treating the nonce as 8 bytes, RFC7539 specifies 12 bytes for a nonce.
|
||||||
|
this.view.setUint32(4, this.n, littleEndian);
|
||||||
return this.bytes;
|
return this.bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue