import * as crypto from 'crypto' ; import * as xml2js from 'xml2js' ; import { ApiConfig } from '@tnwx/accesstoken' ; export class CryptoKit { static xmlParser = new xml2js . Builder ( { rootName : 'xml' , cdata : true , headless : true , renderOpts : { pretty : true , indent : ' ' } } ) ; aesModel : string ; token : string ; appId : string ; encodingAesKey : Buffer ; iv : Buffer ; msgSignature : string ; timestamp : string ; nonce : string ; constructor ( config , msgSignature , timestamp , nonce ) { this . aesModel = 'aes-256-cbc' ; this . token = config . getToken ; this . appId = config . getAppId ; this . encodingAesKey = Buffer . from ( config . getEncodingAesKey + '=' , 'base64' ) ; this . iv = this . encodingAesKey . slice ( 0 , 16 ) ; this . msgSignature = msgSignature ; this . timestamp = timestamp ; this . nonce = nonce ; } getMsgSignature ( encryptedMsg ) { let tempStr = [ this . token , this . timestamp , this . nonce , encryptedMsg ] . sort ( ) . join ( '' ) ; const hashCode = crypto . createHash ( 'sha1' ) ; let tempSignature = hashCode . update ( tempStr , 'utf8' ) . digest ( 'hex' ) ; return tempSignature ; } decrypt ( echostr ) { let deCipheriv = crypto . createDecipheriv ( this . aesModel , this . encodingAesKey , this . iv ) ; deCipheriv . setAutoPadding ( false ) ; let decipheredBuff = Buffer . concat ( [ deCipheriv . update ( echostr , 'base64' ) , deCipheriv . final ( ) ] ) ; decipheredBuff = this . PKCS7Decoder ( decipheredBuff ) ; let len_netOrder_corpid = decipheredBuff . slice ( 16 ) ; let msg_len = len_netOrder_corpid . slice ( 0 , 4 ) . readUInt32BE ( 0 ) ; let result = len_netOrder_corpid . slice ( 4 , msg_len + 4 ) . toString ( ) ; return result ; } param encryptMsg decryptMsg ( encryptMsg ) { let tempSignature = this . getMsgSignature ( encryptMsg ) ; if ( this . msgSignature !== tempSignature ) { throw new Error ( 'msgSignature is not invalid' ) ; } let deCipheriv = crypto . createDecipheriv ( this . aesModel , this . encodingAesKey , this . iv ) ; deCipheriv . setAutoPadding ( false ) ; let deEncryptedMsg = Buffer . concat ( [ deCipheriv . update ( encryptMsg , 'base64' ) , deCipheriv . final ( ) ] ) . toString ( 'utf8' ) ; let pad = deEncryptedMsg . charCodeAt ( deEncryptedMsg . length - 1 ) ; deEncryptedMsg = deEncryptedMsg . slice ( 20 , - pad ) . replace ( /<\/xml>.*/ , '</xml>' ) ; return this . parseXmlToObj ( deEncryptedMsg ) ; } param xmlMsg encryptMsg ( xmlMsg ) { let random = crypto . randomBytes ( 8 ) . toString ( 'hex' ) ; let text = Buffer . from ( xmlMsg ) ; let buf = Buffer . alloc ( 4 ) ; buf . writeUInt32BE ( text . length , 0 ) ; let pack = this . KCS7Encoder ( 20 + text . length + this . appId . length ) ; let content = random + buf . toString ( 'binary' ) + text . toString ( 'binary' ) + this . appId + pack ; let cipheriv = crypto . createCipheriv ( this . aesModel , this . encodingAesKey , this . iv ) ; cipheriv . setAutoPadding ( false ) ; let encryptedMsg = Buffer . concat ( [ cipheriv . update ( content , 'binary' ) , cipheriv . final ( ) ] ) . toString ( 'base64' ) ; let msgSignature = this . getMsgSignature ( encryptedMsg ) ; return CryptoKit . xmlParser . buildObject ( { Encrypt : encryptedMsg , MsgSignature : msgSignature , TimeStamp : this . timestamp , Nonce : this . nonce } ) ; } KCS7Encoder ( textLength ) { let blockSize = 32 ; let amountToPad = blockSize - ( textLength % blockSize ) ; if ( amountToPad === 0 ) { amountToPad = blockSize ; } let pad = String . fromCharCode ( amountToPad ) , s = [ ] ; for ( let i = 0 ; i < amountToPad ; i ++ ) s . push ( pad ) ; return s . join ( '' ) ; } PKCS7Decoder ( buff ) { var pad = buff [ buff . length - 1 ] ; if ( pad < 1 || pad > 32 ) { pad = 0 ; } return buff . slice ( 0 , buff . length - pad ) ; } parseXmlToObj ( xml ) { if ( ! xml || typeof xml != 'string' ) return { } ; let re = { } ; xml = xml . replace ( /^<xml>|<\/xml>$/g , '' ) ; let ms = xml . match ( /<([a-z0-9]+)>([\s\S]*?)<\/\1>/gi ) ; if ( ms && ms . length > 0 ) { ms . forEach ( t => { let ms = t . match ( /<([a-z0-9]+)>([\s\S]*?)<\/\1>/i ) || [ ] ; let tagName = ms [ 1 ] ; let cdata = ms [ 2 ] || '' ; cdata = cdata . replace ( /^\s*<\!\[CDATA\[\s*|\s*\]\]>\s*$/g , '' ) ; re [ tagName ] = cdata ; } ) ; } return re ; } }