moar refactoring

This commit is contained in:
danisharora099 2023-08-17 14:58:25 +05:30
parent bf988e5871
commit 4e1843e71b
No known key found for this signature in database
GPG Key ID: FBD2BF500037F135
6 changed files with 92 additions and 93 deletions

View File

@ -1,27 +1,21 @@
import * as secp from "@noble/secp256k1";
import {
sign as nobleSign,
ProjectivePoint as Point,
Signature,
verify
} from "@noble/secp256k1";
import { concat } from "@waku/utils/bytes";
import sha3 from "js-sha3";
/**
* ECDSA Sign a message with the given private key.
*
* @param message The message to sign, usually a hash.
* @param privateKey The ECDSA private key to use to sign the message.
*
* @returns The signature and the recovery id concatenated.
*/
export async function sign(
message: Uint8Array,
privateKey: Uint8Array
): Promise<Uint8Array> {
const [signature, recoveryId] = await secp.sign(message, privateKey, {
recovered: true,
der: false
});
return concat(
[signature, new Uint8Array([recoveryId])],
signature.length + 1
);
const signature = nobleSign(message, privateKey);
return concat([
signature.toCompactRawBytes(),
new Uint8Array([signature.recovery || 0])
]);
}
export function keccak256(input: Uint8Array): Uint8Array {
@ -32,21 +26,18 @@ export function compressPublicKey(publicKey: Uint8Array): Uint8Array {
if (publicKey.length === 64) {
publicKey = concat([new Uint8Array([4]), publicKey], 65);
}
const point = secp.Point.fromHex(publicKey);
const point = Point.fromHex(publicKey);
return point.toRawBytes(true);
}
/**
* Verify an ECDSA signature.
*/
export function verifySignature(
signature: Uint8Array,
message: Uint8Array | string,
publicKey: Uint8Array
): boolean {
try {
const _signature = secp.Signature.fromCompact(signature.slice(0, 64));
return secp.verify(_signature, message, publicKey);
const _signature = Signature.fromCompact(signature.slice(0, 64));
return verify(_signature, message, publicKey);
} catch {
return false;
}

View File

@ -1,19 +1,18 @@
import * as secp from "@noble/secp256k1";
import { sign as nobleSign, ProjectivePoint as Point } from "@noble/secp256k1";
import type { NodeId } from "@waku/interfaces";
import { bytesToHex } from "@waku/utils/bytes";
import { keccak256 } from "./crypto.js";
export async function sign(
privKey: Uint8Array,
msg: Uint8Array
): Promise<Uint8Array> {
return secp.sign(keccak256(msg), privKey, {
der: false
});
return nobleSign(keccak256(msg), privKey).toCompactRawBytes();
}
export function nodeId(pubKey: Uint8Array): NodeId {
const publicKey = secp.Point.fromHex(pubKey);
const publicKey = Point.fromHex(pubKey);
const uncompressedPubkey = publicKey.toRawBytes(false);
return bytesToHex(keccak256(uncompressedPubkey.slice(1)));

View File

@ -1,7 +1,11 @@
import * as secp from "@noble/secp256k1";
import { concat, hexToBytes } from "@waku/utils/bytes";
import {
getPublicKey,
getSharedSecret,
etc as secpUtils
} from "@noble/secp256k1";
import { concat } from "@waku/utils/bytes";
import { getSubtle, randomBytes, sha256 } from "./index.js";
import { getSubtle } from "./index.js";
/**
* HKDF as implemented in go-ethereum.
*/
@ -15,7 +19,7 @@ function kdf(secret: Uint8Array, outputLength: number): Promise<Uint8Array> {
[counters, secret],
counters.length + secret.length
);
const willBeHashResult = sha256(countersSecret);
const willBeHashResult = secpUtils.hmacSha256Async(countersSecret);
willBeResult = willBeResult.then((result) =>
willBeHashResult.then((hashResult) => {
const _hashResult = new Uint8Array(hashResult);
@ -31,61 +35,59 @@ function kdf(secret: Uint8Array, outputLength: number): Promise<Uint8Array> {
return willBeResult;
}
function aesCtrEncrypt(
async function aesCtrEncrypt(
counter: Uint8Array,
key: ArrayBufferLike,
data: ArrayBufferLike
): Promise<Uint8Array> {
return getSubtle()
.importKey("raw", key, "AES-CTR", false, ["encrypt"])
.then((cryptoKey) =>
getSubtle().encrypt(
{ name: "AES-CTR", counter: counter, length: 128 },
cryptoKey,
data
)
)
.then((bytes) => new Uint8Array(bytes));
const cryptoKey = await getSubtle().importKey("raw", key, "AES-CTR", false, [
"encrypt"
]);
const bytes = await getSubtle().encrypt(
{ name: "AES-CTR", counter: counter, length: 128 },
cryptoKey,
data
);
return new Uint8Array(bytes);
}
function aesCtrDecrypt(
async function aesCtrDecrypt(
counter: Uint8Array,
key: ArrayBufferLike,
data: ArrayBufferLike
): Promise<Uint8Array> {
return getSubtle()
.importKey("raw", key, "AES-CTR", false, ["decrypt"])
.then((cryptoKey) =>
getSubtle().decrypt(
{ name: "AES-CTR", counter: counter, length: 128 },
cryptoKey,
data
)
)
.then((bytes) => new Uint8Array(bytes));
const cryptoKey = await getSubtle().importKey("raw", key, "AES-CTR", false, [
"decrypt"
]);
const bytes = await getSubtle().decrypt(
{ name: "AES-CTR", counter: counter, length: 128 },
cryptoKey,
data
);
return new Uint8Array(bytes);
}
function hmacSha256Sign(
async function hmacSha256Sign(
key: ArrayBufferLike,
msg: ArrayBufferLike
): PromiseLike<Uint8Array> {
): Promise<Uint8Array> {
const algorithm = { name: "HMAC", hash: { name: "SHA-256" } };
return getSubtle()
.importKey("raw", key, algorithm, false, ["sign"])
.then((cryptoKey) => getSubtle().sign(algorithm, cryptoKey, msg))
.then((bytes) => new Uint8Array(bytes));
const cryptoKey = await getSubtle().importKey("raw", key, algorithm, false, [
"sign"
]);
const bytes = await getSubtle().sign(algorithm, cryptoKey, msg);
return new Uint8Array(bytes);
}
function hmacSha256Verify(
async function hmacSha256Verify(
key: ArrayBufferLike,
msg: ArrayBufferLike,
sig: ArrayBufferLike
): Promise<boolean> {
const algorithm = { name: "HMAC", hash: { name: "SHA-256" } };
const _key = getSubtle().importKey("raw", key, algorithm, false, ["verify"]);
return _key.then((cryptoKey) =>
getSubtle().verify(algorithm, cryptoKey, sig, msg)
);
const cryptoKey = await _key;
return await getSubtle().verify(algorithm, cryptoKey, sig, msg);
}
/**
@ -108,9 +110,11 @@ function derive(privateKeyA: Uint8Array, publicKeyB: Uint8Array): Uint8Array {
} else if (publicKeyB[0] !== 4) {
throw new Error("Bad public key, a valid public key would begin with 4");
} else {
const px = secp.getSharedSecret(privateKeyA, publicKeyB, true);
const privateKeyAHex = secpUtils.bytesToHex(privateKeyA);
const publicKeyBHex = secpUtils.bytesToHex(publicKeyB);
const px = getSharedSecret(privateKeyAHex, publicKeyBHex, true);
// Remove the compression prefix
return new Uint8Array(hexToBytes(px).slice(1));
return new Uint8Array(px.slice(1));
}
}
@ -125,21 +129,21 @@ export async function encrypt(
publicKeyTo: Uint8Array,
msg: Uint8Array
): Promise<Uint8Array> {
const ephemPrivateKey = randomBytes(32);
const ephemPrivateKey = secpUtils.randomBytes(32);
const sharedPx = derive(ephemPrivateKey, publicKeyTo);
const hash = await kdf(sharedPx, 32);
const iv = randomBytes(16);
const iv = secpUtils.randomBytes(16);
const encryptionKey = hash.slice(0, 16);
const cipherText = await aesCtrEncrypt(iv, encryptionKey, msg);
const ivCipherText = concat([iv, cipherText], iv.length + cipherText.length);
const macKey = await sha256(hash.slice(16));
const macKey = await secpUtils.hmacSha256Async(hash.slice(16));
const hmac = await hmacSha256Sign(macKey, ivCipherText);
const ephemPublicKey = secp.getPublicKey(ephemPrivateKey, false);
const ephemPublicKey = getPublicKey(ephemPrivateKey, false);
return concat(
[ephemPublicKey, ivCipherText, hmac],
@ -181,9 +185,9 @@ export async function decrypt(
// check HMAC
const px = derive(privateKey, ephemPublicKey);
const hash = await kdf(px, 32);
const [encryptionKey, macKey] = await sha256(hash.slice(16)).then(
(macKey) => [hash.slice(0, 16), macKey]
);
const [encryptionKey, macKey] = await secpUtils
.hmacSha256Async(hash.slice(16))
.then((macKey) => [hash.slice(0, 16), macKey]);
if (!(await hmacSha256Verify(macKey, cipherAndIv, msgMac))) {
throw new Error("Incorrect MAC");

View File

@ -1,7 +1,10 @@
import nodeCrypto from "crypto";
import * as secp from "@noble/secp256k1";
import { concat } from "@waku/utils/bytes";
import {
getPublicKey,
sign as secpSign,
etc as secpUtils
} from "@noble/secp256k1";
import sha3 from "js-sha3";
import { Asymmetric, Symmetric } from "../constants.js";
@ -24,30 +27,28 @@ export function getSubtle(): SubtleCrypto {
}
}
export const randomBytes = secp.utils.randomBytes;
export const sha256 = secp.utils.sha256;
/**
* Generate a new private key to be used for asymmetric encryption.
*
* Use {@link getPublicKey} to get the corresponding Public Key.
*/
export function generatePrivateKey(): Uint8Array {
return randomBytes(Asymmetric.keySize);
return secpUtils.randomBytes(Asymmetric.keySize);
}
/**
* Generate a new symmetric key to be used for symmetric encryption.
*/
export function generateSymmetricKey(): Uint8Array {
return randomBytes(Symmetric.keySize);
return secpUtils.randomBytes(Symmetric.keySize);
}
/**
* Return the public key for the given private key, to be used for asymmetric
* encryption.
*/
export const getPublicKey = secp.getPublicKey;
export { getPublicKey };
/**
* ECDSA Sign a message with the given private key.
@ -61,14 +62,15 @@ export async function sign(
message: Uint8Array,
privateKey: Uint8Array
): Promise<Uint8Array> {
const [signature, recoveryId] = await secp.sign(message, privateKey, {
recovered: true,
der: false
});
return concat(
[signature, new Uint8Array([recoveryId])],
signature.length + 1
);
const signatureObj = secpSign(message, privateKey);
const signature = signatureObj.toCompactRawBytes();
const recoveryId = signatureObj.recovery;
if (recoveryId === undefined) {
throw new Error("Recovery ID is undefined");
}
return new Uint8Array([...signature, recoveryId]);
}
export function keccak256(input: Uint8Array): Uint8Array {

View File

@ -1,6 +1,8 @@
import { etc as secpUtils } from "@noble/secp256k1";
import { Symmetric } from "../constants.js";
import { getSubtle, randomBytes } from "./index.js";
import { getSubtle } from "./index.js";
export async function encrypt(
iv: Uint8Array,
@ -29,5 +31,5 @@ export async function decrypt(
}
export function generateIv(): Uint8Array {
return randomBytes(Symmetric.ivSize);
return secpUtils.randomBytes(Symmetric.ivSize);
}

View File

@ -1,9 +1,10 @@
import { sign, Signature } from "@noble/secp256k1";
import { etc as secpUtils } from "@noble/secp256k1";
import { concat, hexToBytes } from "@waku/utils/bytes";
import { Symmetric } from "./constants.js";
import * as ecies from "./crypto/ecies.js";
import { keccak256, randomBytes } from "./crypto/index.js";
import { keccak256 } from "./crypto/index.js";
import * as symmetric from "./crypto/symmetric.js";
import { Signature as WakuSignature } from "./index.js";
@ -190,7 +191,7 @@ export async function preCipher(
const remainder = rawSize % PaddingTarget;
const paddingSize = PaddingTarget - remainder;
const pad = randomBytes(paddingSize);
const pad = secpUtils.randomBytes(paddingSize);
if (!validateDataIntegrity(pad, paddingSize)) {
throw new Error("failed to generate random padding of size " + paddingSize);