UNPKG

@lakutata/core

Version:

Lakutata Framework Core

141 lines (132 loc) 4.23 kB
import {Plugin} from '../base/Plugin' import NodeRSA, {FormatComponentsPrivate, FormatComponentsPublic} from 'node-rsa' import {CryptoException} from '../exceptions/CryptoException' import {JSON} from './JSON' import {Configurable, Inject} from '../decorators/DependencyInjection' declare module '../Core' { interface Application { Crypto: Crypto } } export class Crypto extends Plugin { @Inject('JSON') private readonly JSON: JSON /** * 密钥bits长度 * @type {number} * @private */ @Configurable() private readonly bits: number = 512 /** * 生成密钥对 * @param {"PKCS8" | "PKCS1"} format * @returns {{private: string, public: string}} */ public generateKeyPair(format: 'PKCS8' | 'PKCS1' = 'PKCS8'): { private: string; public: string } { const key = new NodeRSA({b: this.bits}) let publicKeyFormat: string = 'public-pem' let privateKeyFormat: string = 'private-pem' switch (format) { case 'PKCS8': { publicKeyFormat = `pkcs8-${publicKeyFormat}` privateKeyFormat = `pkcs8-${privateKeyFormat}` } break case 'PKCS1': { publicKeyFormat = `pkcs1-${publicKeyFormat}` privateKeyFormat = `pkcs1-${privateKeyFormat}` } break default: { publicKeyFormat = `pkcs8-${publicKeyFormat}` privateKeyFormat = `pkcs8-${privateKeyFormat}` } } return { private: key.exportKey(privateKeyFormat as FormatComponentsPrivate).toString(), public: key.exportKey(publicKeyFormat as FormatComponentsPublic).toString() } } /** * 数据签名 * @param data * @param {string} privateKey * @returns {string} */ public sign(data: any, privateKey: string): string { const key = new NodeRSA() key.importKey(privateKey) if (key.isEmpty()) throw new CryptoException('Cannot sign data with empty key') if (!key.isPrivate()) throw new CryptoException('Only allow private key for data signing') const bufferData: Buffer = Buffer.from(typeof data === 'string' ? data : this.JSON.stringify(data)) return key.sign(bufferData).toString('base64') } /** * 验证数据签名 * @param data * @param {string} sign * @param {string} secretKey * @returns {boolean} */ public verify(data: any, sign: string, secretKey: string): boolean { const key = new NodeRSA() key.importKey(secretKey) if (key.isEmpty()) throw new CryptoException('Cannot verify data sign with empty key') const bufferData: Buffer = Buffer.from(typeof data === 'string' ? data : this.JSON.stringify(data)) return key.verify(bufferData, Buffer.from(sign, 'base64')) } /** * 加密数据 * @param data * @param {string} secretKey * @returns {string} */ public encrypt(data: any, secretKey: string): string { const key = new NodeRSA() key.importKey(secretKey) if (key.isEmpty()) throw new CryptoException('Cannot encrypt data by empty key') const bufferData: Buffer = Buffer.from(typeof data === 'string' ? data : this.JSON.stringify(data)) if (key.isPublic(true)) { return key.encrypt(bufferData).toString('base64') } else { return key.encryptPrivate(bufferData).toString('base64') } } /** * 解密数据 * @param {string} encryptedData * @param {string} secretKey * @returns {any} */ public decrypt(encryptedData: string, secretKey: string): any { const key = new NodeRSA() key.importKey(secretKey) if (key.isEmpty()) throw new CryptoException('Cannot decrypt data by empty key') const bufferData: Buffer = Buffer.from(encryptedData, 'base64') const decryptedData: string = (() => { let decryptResult: string = '' let decryptException: CryptoException = new CryptoException('Unknown decrypt exception') try { if (key.isPrivate() && !decryptResult) decryptResult = key.decrypt(bufferData).toString() } catch (e) { decryptException = new CryptoException((e as Error).message) } try { if (key.isPublic() && !decryptResult) decryptResult = key.decryptPublic(bufferData).toString() } catch (e) { decryptException = new CryptoException((e as Error).message) } if (decryptResult) { return decryptResult } else { throw decryptException } })() try { return this.JSON.parse(decryptedData) } catch (e) { return decryptedData } } }