//解密 import {EnctyptObject} from "./Encrypt"; import crypto from "crypto"; import axios from "axios"; import https from "https"; const toArrayBuffer = require('to-arraybuffer'); export enum CipherType{ AES256CBC = 'aes-256-cbc', AES256CTR = 'aes-256-ctr', } /*** * @breif 解密对象 */ class Decrypt{ /*** * @breif 初始化列表 * @param keu 密钥 * @param theirDigest 摘要 * @param ciphertext 明文 */ constructor(ciphertext: ArrayBuffer,key: Uint8Array,theirDigest: ArrayBuffer,cryptType:CipherType) { this.plaintext = new ArrayBuffer(ciphertext.byteLength - 16 - 32); this.key = key; this.digest = theirDigest; /*** * @breif 密钥切割 */ this.aeskey = key.slice(0, 32); this.mackey = key.slice(32, 64); /*** * @breif 获取IV值 * @param ciphertext 去掉IV和Mac的密文 * @param ivAndCiphertext 带iv的密文 */ this.iv = new Uint8Array(ciphertext.slice(0, 16)); this.ciphertext = ciphertext.slice(16, ciphertext.byteLength - 32); this.ivAndCiphertext = ciphertext.slice(0, ciphertext.byteLength - 32); /*** * @breif 获取mac * @param errorInfo 初始化错误信息 * @param decryptError 是否发生错误 */ this.mac = ciphertext.slice(ciphertext.byteLength - 32, ciphertext.byteLength); this.errorInfo = ""; this.decryptError = false; /*** * @function verifyMac Mac验证 * @param ivAndCiphertext 需要进行验证的IV 信息 * @param mackey mac密钥 * @param mac mac摘要(密文最后的32位信息) */ this.verifyMac(this.ivAndCiphertext, this.mackey, this.mac, 32); /*** * @function verifyDigest Digest验证 * @param ciphertext 密文 * @param theirDigest 对方传过来的摘要 */ this.verifyDigest(ciphertext, theirDigest); /*** * @breif 解密过程 * @param aeskey AES密钥 * @param ciphertext 密文 * @param iv 信息 * @param cryptType 解密类型 */ this.plaintext = this.decryptAes(this.aeskey, this.ciphertext, this.iv, cryptType); //console.log("最终明文",this.plaintext); } /*** * @breif model */ public errorInfo: string; //错误信息 public decryptError: boolean; //是否加密成功 public iv: Uint8Array; //iv值 public key: Uint8Array; //传处的key; public mac: ArrayBuffer; //mac public mackey: Uint8Array; //Mac密钥 public aeskey: Uint8Array; //aes密钥 public digest: ArrayBuffer; //摘要 public ivAndCiphertext: ArrayBuffer; //IV密文 public ciphertext: ArrayBuffer; //密文 public plaintext: ArrayBuffer; //明文 /*** * 验证过程 */ /*** * @breif 验证mac * @param ivAndCiphtext iv+密文 * @param macKey mac密钥 * @param macSize Mac大小 */ private verifyMac(ivAndCiphtext: ArrayBuffer,macKey:ArrayBuffer,mac: ArrayBuffer, macSize: number){ /*** * @breif 注意:只是这里macSize必须是32的 */ if (macSize !== 32){ throw new Error('verify mac out error!'); } /*** * @breif 创建Hmac密钥并传入需要验证的密文并获取摘要 * @return calculated_mac mac摘要 */ let calculated_mac = crypto.createHmac("sha256",Buffer.from(macKey)) .update(Buffer.from(ivAndCiphtext)) .digest(); if (mac.byteLength != macSize || calculated_mac.byteLength < 32){ throw new Error('Bad Mac length!'); } /** * @breif 将摘要转换成用来验证的格式 * */ var calculatedUint8Array = new Uint8Array(calculated_mac); /** * @breif 将对端传过来的mac摘要转换成用来验证的格式 * */ var macUint8Array = new Uint8Array(mac); /** * @breif 初始化一个返回值 若验证失败则返回值不等于0 * */ var result = 0; /*** * @breif 异或验证 */ for (var i = 0 ; i < mac.byteLength; i++ ){ result = result | (calculatedUint8Array[i] ^ macUint8Array[i]); } if (result !== 0 ){ //console.log("mac验证失败"); this.decryptError = false; this.errorInfo = "verify Mac error!"; throw new Error('Bad Mac'); return null; } } /*** * @breif 验证摘要 * @param ciphertext 密文 * @param theirDigest 用来验证的摘要 */ private verifyDigest(ciphertext: ArrayBuffer,theirDigest: ArrayBuffer) { /*** * @breif 注意:摘要不能为空 */ if (!theirDigest) { throw new Error('verify digest out error!'); } /*** * @breif 用来验证摘要判断密文是否完整 */ let outDigest = toArrayBuffer( crypto.createHash('sha256').update(Buffer.from(ciphertext)).digest() ); /*** * @breif 获取当前传输过来的密文生成的摘要 */ const currentDigest = new Uint8Array(outDigest); /*** * @breif 获取socket传输过来的摘要 */ const verifyTheirDigest = new Uint8Array(theirDigest); //console.log("currentDigest:",currentDigest); //console.log("verifyTheirDigest",verifyTheirDigest); let result = 0; /*** * @breif 进行异或判断 */ for (let i = 0; i < verifyTheirDigest.byteLength; i += 1) { result |= currentDigest[i] ^ verifyTheirDigest[i]; } if (result !== 0) { //console.log("摘要验证失败"); this.errorInfo = "varify digest error!"; this.decryptError = false; return null; } } /*** * @breif 解密过程 */ /*** * @breif 解密AES * @param aesKey AES密钥 * @param ivAndCiphertext iv+密文 * @param cipherType 加密类型 */ private decryptAes(aesKey: ArrayBuffer,ciphertext: ArrayBuffer,iv:ArrayBuffer,cipherType:CipherType): ArrayBuffer{ /*** * @breif 通过iv+key创建密钥 */ // console.log("开始进行AES解密:",cipherType,"aeskey",new Uint8Array(aesKey).slice(0,32),"iv",new Uint8Array(iv).slice(0,16)); let decipher = crypto.createDecipheriv( 'aes-256-cbc', Buffer.from(new Uint8Array(aesKey).slice(0,32)), Buffer.from(new Uint8Array(iv).slice(0,16)) ); //console.log("解密ciphertext:",ciphertext); const decrypted = Buffer.concat([ decipher.update(Buffer.from(ciphertext)), decipher.final(), ]); this.errorInfo = ""; this.decryptError = true; return decrypted; } } /*** * @breif 解密返回参数 */ export interface DecryptResult { plaintext?: ArrayBuffer; //明文对象 error?: Error; } /*** * @breif 方便使用的解密接口函数 * @param enctyptObject 加密对象 * @param cipytType 加密类型 */ export function decryptSdkInBuffer(enctyptObject: EnctyptObject,cipytType: CipherType = CipherType.AES256CBC): DecryptResult { /*** * @breif 注意:这个key是由 aeskey 和 mackey 组合而成的 */ if (enctyptObject.key.byteLength !== 64) { throw new Error('aeskey error'); } //console.log("key的长度正确"); /*** * @breif 注意:保证密文存在 */ if (enctyptObject.ciphertext.byteLength <= 16 + 32) { throw new Error('cipherText error'); } //console.log("秘文存在"); /*** * @breif 创建解密对象 */ let decryptObject = new Decrypt(enctyptObject.ciphertext,new Uint8Array(enctyptObject.key),enctyptObject.digest,cipytType); if (decryptObject.decryptError == false || decryptObject.errorInfo.length != 0){ throw new Error(decryptObject.errorInfo); } return {plaintext:decryptObject.plaintext}; } /*** * @breif 通过URL获取解密接口数据 * @param keyStr 16进制 * @param digestStr 16进制 */ export async function decryptSdkInPath(path: string, keyStr: string,digestStr: string,cipytType: CipherType = CipherType.AES256CBC): Promise{ const fromHexString = hexString => new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); let key = fromHexString(keyStr); let digest = fromHexString(digestStr); if (path.length == 0){ throw new Error("error:path is not!"); } /*** * @breif 注意:这个key是由 aeskey 和 mackey 组合而成的 */ //console.log("key.byteLength = " + key.byteLength); if (key.byteLength !== 64) { throw new Error('aeskey error'); } let cipyttext; //console.log("开始获取下载图像",path); await axios.get(path,{ responseType: "arraybuffer", httpsAgent: new https.Agent({ rejectUnauthorized: false }) }).then((Response)=>{ return cipyttext = Response.data; //console.log("从阿里云下载的秘闻",cipyttext); }); if (cipyttext != undefined){ /*** * @breif 创建解密对象 */ let decryptObject = new Decrypt(cipyttext, key, digest, cipytType); if (decryptObject.decryptError == false || decryptObject.errorInfo.length != 0) { throw new Error(decryptObject.errorInfo); } return {plaintext: decryptObject.plaintext}; }else { return { error: Error("参数错误"), plaintext: undefined, }; } }