@lakutata/core
Version:
Lakutata Framework Core
141 lines (132 loc) • 4.23 kB
text/typescript
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 {
('JSON')
private readonly JSON: JSON
/**
* 密钥bits长度
* @type {number}
* @private
*/
()
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
}
}
}