UNPKG

did-sdk-js

Version:

js sdk for did and vc according to mcps did spec

287 lines (286 loc) 11.5 kB
"use strict"; // import { // aesCbcEncrypt, // aesCbcDecrypt, // aesCbcEncryptSync, // aesCbcDecryptSync, // } from './aes'; // import { derive } from './ecdh'; // import { getPublic, decompress, compress } from './ecdsa'; // import { // hmacSha256Sign, // hmacSha256Verify, // hmacSha256SignSync, // hmacSha256VerifySync, // } from './hmac'; // import { randomBytes } from './random'; // import { sha512, sha512Sync } from './sha2'; // // import { // LENGTH_0, // KEY_LENGTH, // IV_LENGTH, // MAC_LENGTH, // PREFIXED_KEY_LENGTH, // ERROR_BAD_MAC, // } from './constants'; // import { // PreEncryptOpts, // isValidPrivateKey, // Encrypted, // assert, // concatBuffers, // } from './helpers'; Object.defineProperty(exports, "__esModule", { value: true }); exports.decrypt = exports.encrypt = exports.Encrypted = exports.kdf = exports.aesCbcEncrypt = void 0; const crypto = require("crypto"); const eccrypto_js_1 = require("eccrypto-js"); const enc = require("enc-utils"); const secp256k1 = require('secp256k1'); let CryptoJS = require("crypto-js"); /* add by gangm: 基于"https://github.com.cnpmjs.org/sigp/ecies-parity.git"和https://hub.fastgit.org/pedrouid/eccrypto-js.git 库 ECIES几个标准:ANSI X9.63, IEEE 1363a 和 ISO/IEC 18033-2 这里选用: IEEE 1363a 为了多语言兼容,这里统一兼容java库org.bouncycastle.crypto中“ECIESWITHSHA256ANDAES-CBC”的实现 aes/cbc模式需要额外添加iv信息:https://github.com/bcgit/bc-java/issues/493 也为了方便后续扩展,加密结果返回原始数据(iv/pubkey/cipher/hmac),上层封装具体序列化方式(比如:publicKey(65) + iv(16) + cipher_text + hmac) */ function sha256(msg) { return crypto.createHash("sha256").update(msg).digest(); } // aes-cbc-256-256 function aesCbcEncrypt(plainText, secretKey, iv) { return eccrypto_js_1.aesCbcEncryptSync(iv, secretKey, plainText); // let key = CryptoJS.enc.Utf8.parse(secretKey.toString()); // let cipher = CryptoJS.AES.encrypt(plainText.toString(), key, { // iv: key, // mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 // } // ).ciphertext.toString() // // return Buffer.from(cipher, 'hex') } exports.aesCbcEncrypt = aesCbcEncrypt; function aesCbcDecrypt(cipherText, secretKey, iv) { return eccrypto_js_1.aesCbcDecryptSync(iv, secretKey, cipherText); // from base64 cipher str // let key = CryptoJS.enc.Utf8.parse(secretKey); // return CryptoJS.AES.decrypt(cipherText, secretKey, { // iv: iv, // mode: CryptoJS.mode.CBC, // padding: CryptoJS.pad.Pkcs7 // } // ).toString(CryptoJS.enc.Utf8); } function hmacSha256(key, msg) { return crypto.createHmac("sha256", key).update(msg).digest(); } // The KDF as implemented in Parity function kdf(secret, outputLength) { let ctr = 1; let written = 0; let result = Buffer.from(''); while (written < outputLength) { let ctrs = Buffer.from([ctr >> 24, ctr >> 16, ctr >> 8, ctr]); let hashResult = sha256(Buffer.concat([secret, ctrs])); result = Buffer.concat([result, hashResult]); written += 32; ctr += 1; } return result.slice(0, outputLength); } exports.kdf = kdf; // export function secp256k1Derive( // publicKey: Buffer, // privateKey: Buffer, // compressed?: boolean // ) { // let result = secp256k1.ecdhUnsafe(publicKey, privateKey, compressed); // // result.tri // return trimLeft(result, KEY_LENGTH); // } // // function derive(privateKeyA: Buffer, publicKeyB: Buffer): Buffer { // publicKeyB = secp256k1Decompress(publicKeyB) // return secp256k1Derive(privateKeyA, publicKeyB, false); // } // function getPublic(privateKey: Buffer) { // var compressed = secp256k1.publicKeyCreate(privateKey); // return secp256k1.publicKeyConvert(compressed, false); // } class Encrypted { constructor(iv, ephemPublicKey, ciphertext, mac) { this.iv = iv; this.ephemPublicKey = ephemPublicKey; this.ciphertext = ciphertext; this.mac = mac; } serialize() { return enc.concatBuffers(this.iv, this.ephemPublicKey, this.ciphertext, this.mac); } static deserialize(cipherData) { const slice0 = eccrypto_js_1.LENGTH_0; const slice_iv = eccrypto_js_1.IV_LENGTH; const slice_pubkey = slice_iv + eccrypto_js_1.PREFIXED_DECOMPRESSED_LENGTH; const slice_data = cipherData.length - eccrypto_js_1.MAC_LENGTH; const slice_mac = cipherData.length; return new Encrypted(cipherData.slice(slice0, slice_iv), cipherData.slice(slice_iv, slice_pubkey), cipherData.slice(slice_pubkey, slice_data), cipherData.slice(slice_data, slice_mac)); } } exports.Encrypted = Encrypted; function encrypt(publicKeyTo, msg, opts) { opts = opts || {}; let ephemPrivateKey = opts.ephemPrivateKey || crypto.randomBytes(32); let ephemPublicKey = eccrypto_js_1.getPublic(ephemPrivateKey); // getSharedKey publicKeyTo = eccrypto_js_1.decompress(publicKeyTo); let sharedPx = eccrypto_js_1.derive(ephemPrivateKey, publicKeyTo); let vz = Buffer.concat([ephemPublicKey, sharedPx]); // 参考java:bouncycastle库 let hash = kdf(vz, eccrypto_js_1.LENGTH_32 + eccrypto_js_1.MAC_LENGTH); // ke.length + km.length let iv = opts.iv || crypto.randomBytes(eccrypto_js_1.IV_LENGTH); let encryptionKey = hash.slice(0, eccrypto_js_1.LENGTH_32); let macKey = hash.slice(eccrypto_js_1.LENGTH_32); let ciphertext = aesCbcEncrypt(msg, encryptionKey, iv); let L2 = Buffer.alloc(8); // as described in Shroup's paper and P1363a;保持跟java bouncycastle库一致 L2.fill(0); let dataToMac = Buffer.concat([ciphertext, L2]); let HMAC = hmacSha256(macKey, dataToMac); return new Encrypted(iv, ephemPublicKey, ciphertext, HMAC); } exports.encrypt = encrypt; function decrypt(privateKey, encrypted) { let sharedPx = eccrypto_js_1.derive(privateKey, eccrypto_js_1.decompress(encrypted.ephemPublicKey)); let vz = Buffer.concat([encrypted.ephemPublicKey, sharedPx]); // 参考java:bouncycastle库 let hash = kdf(vz, eccrypto_js_1.LENGTH_32 + eccrypto_js_1.MAC_LENGTH); let encryptionKey = hash.slice(0, eccrypto_js_1.LENGTH_32); let macKey = hash.slice(eccrypto_js_1.LENGTH_32); let L2 = Buffer.alloc(8); // as described in Shroup's paper and P1363a;保持跟java bouncycastle库一致 L2.fill(0); let dataToMac = Buffer.concat([encrypted.ciphertext, L2]); let HMAC = hmacSha256(macKey, dataToMac); const verifyMac = eccrypto_js_1.equalConstTime(HMAC, encrypted.mac); eccrypto_js_1.assert(verifyMac, eccrypto_js_1.ERROR_BAD_MAC); return aesCbcDecrypt(encrypted.ciphertext, encryptionKey, encrypted.iv); } exports.decrypt = decrypt; // // function getSharedKey(privateKey: Buffer, publicKey: Buffer) { // publicKey = decompress(publicKey); // return derive(privateKey, publicKey); // } // // function getEncryptionKey(hash: Buffer) { // return Buffer.from(hash.slice(LENGTH_0, KEY_LENGTH)); // } // // function getMacKey(hash: Buffer) { // return Buffer.from(hash.slice(KEY_LENGTH)); // } // // async function getEciesKeys(privateKey: Buffer, publicKey: Buffer) { // const sharedKey = getSharedKey(privateKey, publicKey); // const hash = await sha512(sharedKey); // return { encryptionKey: getEncryptionKey(hash), macKey: getMacKey(hash) }; // } // // function getEciesKeysSync(privateKey: Buffer, publicKey: Buffer) { // const sharedKey = getSharedKey(privateKey, publicKey); // const hash = sha512Sync(sharedKey); // return { encryptionKey: getEncryptionKey(hash), macKey: getMacKey(hash) }; // } // // function getEphemKeyPair(opts?: Partial<PreEncryptOpts>) { // let ephemPrivateKey = opts?.ephemPrivateKey || randomBytes(KEY_LENGTH); // while (!isValidPrivateKey(ephemPrivateKey)) { // ephemPrivateKey = opts?.ephemPrivateKey || randomBytes(KEY_LENGTH); // } // const ephemPublicKey = getPublic(ephemPrivateKey); // return { ephemPrivateKey, ephemPublicKey }; // } // // export async function encrypt( // publicKeyTo: Buffer, // msg: Buffer, // opts?: Partial<PreEncryptOpts> // ): Promise<Encrypted> { // const { ephemPrivateKey, ephemPublicKey } = getEphemKeyPair(opts); // const { encryptionKey, macKey } = await getEciesKeys( // ephemPrivateKey, // publicKeyTo // ); // const iv = opts?.iv || randomBytes(IV_LENGTH); // const ciphertext = await aesCbcEncrypt(iv, encryptionKey, msg); // const dataToMac = concatBuffers(iv, ephemPublicKey, ciphertext); // const mac = await hmacSha256Sign(macKey, dataToMac); // return { iv, ephemPublicKey, ciphertext, mac: mac }; // } // // export async function decrypt( // privateKey: Buffer, // opts: Encrypted // ): Promise<Buffer> { // const { ephemPublicKey, iv, mac, ciphertext } = opts; // const { encryptionKey, macKey } = await getEciesKeys( // privateKey, // ephemPublicKey // ); // const dataToMac = concatBuffers(iv, ephemPublicKey, ciphertext); // const macTest = await hmacSha256Verify(macKey, dataToMac, mac); // assert(macTest, ERROR_BAD_MAC); // const msg = await aesCbcDecrypt(opts.iv, encryptionKey, opts.ciphertext); // return msg; // } // // export function encryptSync( // publicKeyTo: Buffer, // msg: Buffer, // opts?: Partial<PreEncryptOpts> // ): Encrypted { // const { ephemPrivateKey, ephemPublicKey } = getEphemKeyPair(opts); // const { encryptionKey, macKey } = getEciesKeysSync( // ephemPrivateKey, // publicKeyTo // ); // const iv = opts?.iv || randomBytes(IV_LENGTH); // const ciphertext = aesCbcEncryptSync(iv, encryptionKey, msg); // const dataToMac = concatBuffers(iv, ephemPublicKey, ciphertext); // const mac = hmacSha256SignSync(macKey, dataToMac); // return { iv, ephemPublicKey, ciphertext, mac: mac }; // } // // export async function decryptSync( // privateKey: Buffer, // opts: Encrypted // ): Promise<Buffer> { // const { ephemPublicKey, iv, mac, ciphertext } = opts; // const { encryptionKey, macKey } = getEciesKeysSync( // privateKey, // ephemPublicKey // ); // const dataToMac = concatBuffers(iv, ephemPublicKey, ciphertext); // const macTest = hmacSha256VerifySync(macKey, dataToMac, mac); // assert(macTest, ERROR_BAD_MAC); // const msg = aesCbcDecryptSync(opts.iv, encryptionKey, opts.ciphertext); // return msg; // } // // export function serialize(opts: Encrypted): Buffer { // const ephemPublicKey = compress(opts.ephemPublicKey); // return concatBuffers(opts.iv, ephemPublicKey, opts.mac, opts.ciphertext); // } // // export function deserialize(buf: Buffer): Encrypted { // const slice0 = LENGTH_0; // const slice1 = slice0 + IV_LENGTH; // const slice2 = slice1 + PREFIXED_KEY_LENGTH; // const slice3 = slice2 + MAC_LENGTH; // const slice4 = buf.length; // return { // iv: buf.slice(slice0, slice1), // ephemPublicKey: decompress(buf.slice(slice1, slice2)), // mac: buf.slice(slice2, slice3), // ciphertext: buf.slice(slice3, slice4), // }; // } //# sourceMappingURL=ecies.js.map