feat!: export crypto primitives (#1728)

* export crypto primitives

* export crypto

* update imports

* fix size limit

* rename crypto.js

* move Signature type

* fix path

* fix: size-limit (#1734)

* fix paths, revert change to config

---------

Co-authored-by: Danish Arora <35004822+danisharora099@users.noreply.github.com>
This commit is contained in:
Sasha 2023-11-28 01:02:12 +01:00 committed by GitHub
parent 7df21b7756
commit 7eb3375f50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 158 additions and 130 deletions

View File

@ -16,6 +16,10 @@
"./symmetric": {
"types": "./dist/symmetric.d.ts",
"import": "./dist/symmetric.js"
},
"./crypto": {
"types": "./dist/crypto/index.d.ts",
"import": "./dist/crypto/index.js"
}
},
"typesVersions": {

View File

@ -1,7 +1,7 @@
import * as secp from "@noble/secp256k1";
import { concat, hexToBytes } from "@waku/utils/bytes";
import { getSubtle, randomBytes, sha256 } from "./index.js";
import { getSubtle, randomBytes, sha256 } from "./utils.js";
/**
* HKDF as implemented in go-ethereum.
*/

View File

@ -1,76 +1,3 @@
import nodeCrypto from "crypto";
import * as secp from "@noble/secp256k1";
import { concat } from "@waku/utils/bytes";
import sha3 from "js-sha3";
import { Asymmetric, Symmetric } from "../constants.js";
declare const self: Record<string, any> | undefined;
const crypto: { node?: any; web?: any } = {
node: nodeCrypto,
web: typeof self === "object" && "crypto" in self ? self.crypto : undefined
};
export function getSubtle(): SubtleCrypto {
if (crypto.web) {
return crypto.web.subtle;
} else if (crypto.node) {
return crypto.node.webcrypto.subtle;
} else {
throw new Error(
"The environment doesn't have Crypto Subtle API (if in the browser, be sure to use to be in a secure context, ie, https)"
);
}
}
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);
}
/**
* Generate a new symmetric key to be used for symmetric encryption.
*/
export function generateSymmetricKey(): Uint8Array {
return randomBytes(Symmetric.keySize);
}
/**
* Return the public key for the given private key, to be used for asymmetric
* encryption.
*/
export const getPublicKey = secp.getPublicKey;
/**
* 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
);
}
export function keccak256(input: Uint8Array): Uint8Array {
return new Uint8Array(sha3.keccak256.arrayBuffer(input));
}
export * from "./utils.js";
export * as ecies from "./ecies.js";
export * as symmetric from "./symmetric.js";

View File

@ -1,6 +1,6 @@
import { Symmetric } from "../constants.js";
import { Symmetric } from "../misc.js";
import { getSubtle, randomBytes } from "./index.js";
import { getSubtle, randomBytes } from "./utils.js";
export async function encrypt(
iv: Uint8Array,

View File

@ -0,0 +1,76 @@
import nodeCrypto from "crypto";
import * as secp from "@noble/secp256k1";
import { concat } from "@waku/utils/bytes";
import sha3 from "js-sha3";
import { Asymmetric, Symmetric } from "../misc.js";
declare const self: Record<string, any> | undefined;
const crypto: { node?: any; web?: any } = {
node: nodeCrypto,
web: typeof self === "object" && "crypto" in self ? self.crypto : undefined
};
export function getSubtle(): SubtleCrypto {
if (crypto.web) {
return crypto.web.subtle;
} else if (crypto.node) {
return crypto.node.webcrypto.subtle;
} else {
throw new Error(
"The environment doesn't have Crypto Subtle API (if in the browser, be sure to use to be in a secure context, ie, https)"
);
}
}
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);
}
/**
* Generate a new symmetric key to be used for symmetric encryption.
*/
export function generateSymmetricKey(): Uint8Array {
return randomBytes(Symmetric.keySize);
}
/**
* Return the public key for the given private key, to be used for asymmetric
* encryption.
*/
export const getPublicKey = secp.getPublicKey;
/**
* 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
);
}
export function keccak256(input: Uint8Array): Uint8Array {
return new Uint8Array(sha3.keccak256.arrayBuffer(input));
}

View File

@ -1,33 +1,34 @@
import { DefaultPubsubTopic } from "@waku/core";
import { Decoder as DecoderV0 } from "@waku/core/lib/message/version_0";
import { IMetaSetter, PubsubTopic } from "@waku/interfaces";
import type {
EncoderOptions as BaseEncoderOptions,
IDecoder,
IEncoder,
IMessage,
IProtoMessage
IMetaSetter,
IProtoMessage,
PubsubTopic
} from "@waku/interfaces";
import { WakuMessage } from "@waku/proto";
import { Logger } from "@waku/utils";
import { generatePrivateKey } from "./crypto/utils.js";
import { DecodedMessage } from "./decoded_message.js";
import {
decryptAsymmetric,
encryptAsymmetric,
postCipher,
preCipher
} from "./waku_payload.js";
} from "./encryption.js";
import { OneMillion, Version } from "./misc.js";
import {
generatePrivateKey,
getPublicKey,
OneMillion,
Version
} from "./index.js";
export { generatePrivateKey, getPublicKey };
export type { Encoder, Decoder, DecodedMessage };
export {
decryptAsymmetric,
encryptAsymmetric,
postCipher,
preCipher,
generatePrivateKey
};
const log = new Logger("message-encryption:ecies");

View File

@ -9,9 +9,9 @@ import {
encryptSymmetric,
postCipher,
preCipher
} from "./waku_payload.js";
} from "./encryption.js";
describe("Waku Payload", function () {
describe("Waku Encryption", function () {
this.timeout(20000);
it("Asymmetric encrypt & decrypt", async function () {
await fc.assert(

View File

@ -1,12 +1,14 @@
import * as secp 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, sign } from "./crypto/index.js";
import * as symmetric from "./crypto/symmetric.js";
import { Signature } from "./index.js";
import {
ecies,
keccak256,
randomBytes,
sign,
symmetric
} from "./crypto/index.js";
import { Symmetric } from "./misc.js";
const FlagsLength = 1;
const FlagMask = 3; // 0011
@ -210,6 +212,11 @@ export async function preCipher(
return envelope;
}
type Signature = {
signature: Uint8Array;
publicKey: Uint8Array | undefined;
};
/**
* Decode a decrypted payload.
*

View File

@ -5,17 +5,9 @@ import {
} from "./crypto/index.js";
import { DecodedMessage } from "./decoded_message.js";
export const OneMillion = BigInt(1_000_000);
export { generatePrivateKey, generateSymmetricKey, getPublicKey };
export type { DecodedMessage };
export * as ecies from "./ecies.js";
export * as symmetric from "./symmetric.js";
export const Version = 1;
export type Signature = {
signature: Uint8Array;
publicKey: Uint8Array | undefined;
};
export * as crypto from "./crypto";

View File

@ -8,3 +8,7 @@ export const Symmetric = {
export const Asymmetric = {
keySize: 32
};
export const OneMillion = BigInt(1_000_000);
export const Version = 1;

View File

@ -12,18 +12,23 @@ import type {
import { WakuMessage } from "@waku/proto";
import { Logger } from "@waku/utils";
import { generateSymmetricKey } from "./crypto/utils.js";
import { DecodedMessage } from "./decoded_message.js";
import {
decryptSymmetric,
encryptSymmetric,
postCipher,
preCipher
} from "./waku_payload.js";
} from "./encryption.js";
import { OneMillion, Version } from "./misc.js";
import { generateSymmetricKey, OneMillion, Version } from "./index.js";
export { generateSymmetricKey };
export type { DecodedMessage, Encoder, Decoder };
export {
decryptSymmetric,
encryptSymmetric,
postCipher,
preCipher,
generateSymmetricKey
};
const log = new Logger("message-encryption:symmetric");

View File

@ -7,13 +7,15 @@ import {
import { IFilterSubscription, Protocols } from "@waku/interfaces";
import type { LightNode } from "@waku/interfaces";
import {
createDecoder as eciesDecoder,
createEncoder as eciesEncoder,
generatePrivateKey,
generateSymmetricKey,
getPublicKey
} from "@waku/message-encryption";
import {
createDecoder as eciesDecoder,
createEncoder as eciesEncoder
} from "@waku/message-encryption/ecies";
import {
generateSymmetricKey,
createDecoder as symDecoder,
createEncoder as symEncoder
} from "@waku/message-encryption/symmetric";

View File

@ -6,7 +6,13 @@ import {
} from "@waku/core";
import type { IFilterSubscription, LightNode } from "@waku/interfaces";
import { Protocols } from "@waku/interfaces";
import { ecies, symmetric } from "@waku/message-encryption";
import {
ecies,
generatePrivateKey,
generateSymmetricKey,
getPublicKey,
symmetric
} from "@waku/message-encryption";
import { utf8ToBytes } from "@waku/utils/bytes";
import { expect } from "chai";
@ -67,8 +73,8 @@ describe("Waku Filter V2: Subscribe", function () {
});
it("Subscribe and receive ecies encrypted messages via lightPush", async function () {
const privateKey = ecies.generatePrivateKey();
const publicKey = ecies.getPublicKey(privateKey);
const privateKey = generatePrivateKey();
const publicKey = getPublicKey(privateKey);
const encoder = ecies.createEncoder({
contentTopic: TestContentTopic,
publicKey
@ -89,7 +95,7 @@ describe("Waku Filter V2: Subscribe", function () {
});
it("Subscribe and receive symmetrically encrypted messages via lightPush", async function () {
const symKey = symmetric.generateSymmetricKey();
const symKey = generateSymmetricKey();
const encoder = symmetric.createEncoder({
contentTopic: TestContentTopic,
symKey

View File

@ -1,15 +1,17 @@
import { createDecoder, createEncoder, DecodedMessage } from "@waku/core";
import { RelayNode } from "@waku/interfaces";
import {
createDecoder as createEciesDecoder,
createEncoder as createEciesEncoder,
generatePrivateKey,
generateSymmetricKey,
getPublicKey
} from "@waku/message-encryption";
import {
createDecoder as createEciesDecoder,
createEncoder as createEciesEncoder
} from "@waku/message-encryption/ecies";
import {
createDecoder as createSymDecoder,
createEncoder as createSymEncoder,
generateSymmetricKey
createEncoder as createSymEncoder
} from "@waku/message-encryption/symmetric";
import { createRelayNode } from "@waku/sdk";
import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes";

View File

@ -7,15 +7,17 @@ import {
import type { IMessage, LightNode } from "@waku/interfaces";
import { Protocols } from "@waku/interfaces";
import {
createDecoder as createEciesDecoder,
createEncoder as createEciesEncoder,
generatePrivateKey,
generateSymmetricKey,
getPublicKey
} from "@waku/message-encryption";
import {
createDecoder as createEciesDecoder,
createEncoder as createEciesEncoder
} from "@waku/message-encryption/ecies";
import {
createDecoder as createSymDecoder,
createEncoder as createSymEncoder,
generateSymmetricKey
createEncoder as createSymEncoder
} from "@waku/message-encryption/symmetric";
import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes";
import { expect } from "chai";

View File

@ -7,10 +7,10 @@ import {
} from "@waku/core";
import type { LightNode, RelayNode, Waku } from "@waku/interfaces";
import { Protocols } from "@waku/interfaces";
import { generateSymmetricKey } from "@waku/message-encryption";
import {
createDecoder,
createEncoder,
generateSymmetricKey
createEncoder
} from "@waku/message-encryption/symmetric";
import {
createLightNode,