Skip to content

Commit

Permalink
feat(common): Stable Signature Generation from JS Objects
Browse files Browse the repository at this point in the history
Signed-off-by: suyukuoacn <su-yu.kuo@accenture.com>
  • Loading branch information
suyukuoacn authored and petermetz committed Aug 18, 2020
1 parent caf60b3 commit 22b5f5c
Show file tree
Hide file tree
Showing 8 changed files with 500 additions and 6 deletions.
139 changes: 139 additions & 0 deletions packages/cactus-common/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions packages/cactus-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,10 @@
],
"scripts": {
"tsc": "tsc --project ./tsconfig.json",

"webpack": "npm-run-all webpack:dev webpack:prod",

"webpack:dev": "npm-run-all webpack:dev:node webpack:dev:web",
"webpack:dev:web": "webpack --env=dev --target=web --config ../../webpack.config.js",
"webpack:dev:node": "webpack --env=dev --target=node --config ../../webpack.config.js",

"webpack:prod": "npm-run-all webpack:prod:node webpack:prod:web",
"webpack:prod:web": "webpack --env=prod --target=web --config ../../webpack.config.js",
"webpack:prod:node": "webpack --env=prod --target=node --config ../../webpack.config.js"
Expand Down Expand Up @@ -66,11 +63,16 @@
"homepage": "https://github.com/hyperledger/cactus#readme",
"dependencies": {
"joi": "14.3.1",
"json-stable-stringify": "1.0.1",
"loglevel": "1.6.7",
"loglevel-plugin-prefix": "0.8.4",
"secp256k1": "4.0.2",
"sha3": "2.1.3",
"typescript-optional": "2.0.1"
},
"devDependencies": {
"@types/joi": "14.3.4"
"@types/joi": "14.3.4",
"@types/json-stable-stringify": "1.0.32",
"@types/secp256k1": "4.0.1"
}
}
104 changes: 104 additions & 0 deletions packages/cactus-common/src/main/typescript/js-object-signer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Logger } from "./logging/logger";
import { LoggerProvider } from "./logging/logger-provider";
import { LogLevelDesc } from "loglevel";

import secp256k1 from "secp256k1";
import sha3 from "sha3";
import stringify from "json-stable-stringify";

export type SignatureFunction = (msg: any, pkey: any) => any;
export type VerifySignatureFunction = (
msg: any,
signature: any,
pubKey: Uint8Array
) => boolean;
export type HashFunction = (data: any) => string;

export interface IJsObjectSignerOptions {
privateKey: any;
signatureFunc?: SignatureFunction;
verifySignatureFunc?: VerifySignatureFunction;
hashFunc?: HashFunction;
logLevel?: LogLevelDesc;
}

export class JsObjectSigner {
private privateKey: any;
private signatureFunc: any;
private verifySignatureFunc: any;
private hashFunc: any;
private readonly logger: Logger;

constructor(public readonly options: IJsObjectSignerOptions) {
if (!options) {
throw new Error(`JsObjectSigner#ctor options falsy.`);
}
if (!options.privateKey) {
throw new Error(`JsObjectSigner#ctor options.privateKey falsy.`);
}

this.privateKey = options.privateKey;
this.signatureFunc = options.signatureFunc;
this.verifySignatureFunc = options.verifySignatureFunc;
this.hashFunc = options.hashFunc;

this.logger = LoggerProvider.getOrCreate({
label: "js-object-signer",
level: options.logLevel || "INFO",
});
}

/**
* Generate signature from formated message
* @param msg
* @returns Generated signature
*/
public sign(msg: any): any {
this.logger.debug("Message to sign: " + stringify(msg));

if (this.signatureFunc) {
return this.signatureFunc(msg, this.privateKey);
} else {
let hashMsg: any;
if (this.hashFunc) {
hashMsg = this.hashFunc(msg);
} else {
hashMsg = this.dataHash(msg);
}

const pkey = Buffer.from(this.privateKey, `hex`);
const signObj = secp256k1.ecdsaSign(Buffer.from(hashMsg, `hex`), pkey);
return signObj.signature;
}
}

/**
* Verify if a signature corresponds to given message and public key
* @param msg
* @param pubKey
* @param signature
* @returns {boolean}
*/
public verify(msg: any, signature: Uint8Array, pubKey: any): boolean {
if (this.verifySignatureFunc) {
return this.verifySignatureFunc(msg, signature, pubKey);
}
return secp256k1.ecdsaVerify(
signature,
Buffer.from(this.dataHash(msg), `hex`),
pubKey
);
}

/**
* Format message to be signed
* @param data
* @returns {string}
*/
private dataHash(data: any): string {
const hashObj = new sha3.SHA3Hash(256);
hashObj.update(stringify(data));
const hashMsg = hashObj.digest(`hex`);
return hashMsg;
}
}
9 changes: 9 additions & 0 deletions packages/cactus-common/src/main/typescript/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,12 @@ export { Logger, ILoggerOptions } from "./logging/logger";
export { LogLevelDesc } from "loglevel";
export { Objects } from "./objects";
export { Strings } from "./strings";
export {
JsObjectSigner,
IJsObjectSignerOptions,
SignatureFunction,
VerifySignatureFunction,
HashFunction,
} from "./js-object-signer";
export { ISignerKeyPair } from "./signer-key-pair";
export { Secp256k1Keys } from "./secp256k1-keys";
26 changes: 26 additions & 0 deletions packages/cactus-common/src/main/typescript/secp256k1-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import crypto from "crypto";
import secp256k1 from "secp256k1";

export interface ISignerKeyPair {
privateKey: any;
publicKey: any;
}

export class Secp256k1Keys {
/**
* Generate random private and public secp256k1 key in Buffer format
* @return Generated key pair
*/
static generateKeyPairsBuffer(): ISignerKeyPair {
let privKey: any;
// generate secp256K1 private key
do {
privKey = crypto.randomBytes(32);
} while (!secp256k1.privateKeyVerify(privKey));

// generate secp256K1 public key
const pubKey = secp256k1.publicKeyCreate(privKey);

return { privateKey: privKey, publicKey: pubKey };
}
}
4 changes: 4 additions & 0 deletions packages/cactus-common/src/main/typescript/signer-key-pair.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ISignerKeyPair {
privateKey: Uint8Array | Buffer | string;
publicKey: Uint8Array | Buffer | string;
}

0 comments on commit 22b5f5c

Please sign in to comment.