91 lines
2.0 KiB
TypeScript
91 lines
2.0 KiB
TypeScript
import { IEncryptor } from './interface';
|
|
|
|
/**
|
|
* AES-GCM加密器
|
|
*/
|
|
export class AESEncryptor implements IEncryptor {
|
|
private key: CryptoKey | null = null;
|
|
|
|
constructor(keyString: string) {
|
|
this.importKey(keyString);
|
|
}
|
|
|
|
/**
|
|
* 导入密钥
|
|
*/
|
|
private async importKey(keyString: string): Promise<void> {
|
|
const encoder = new TextEncoder();
|
|
const keyData = encoder.encode(keyString.padEnd(32, '0').substring(0, 32));
|
|
|
|
this.key = await crypto.subtle.importKey(
|
|
'raw',
|
|
keyData,
|
|
{
|
|
name: 'AES-GCM',
|
|
length: 256,
|
|
},
|
|
false,
|
|
['encrypt', 'decrypt']
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 加密数据
|
|
*/
|
|
async encrypt(plaintext: Uint8Array): Promise<Uint8Array> {
|
|
if (!this.key) {
|
|
throw new Error('密钥未设置');
|
|
}
|
|
|
|
// 生成随机IV
|
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
|
|
const encrypted = await crypto.subtle.encrypt(
|
|
{
|
|
name: 'AES-GCM',
|
|
iv: iv,
|
|
},
|
|
this.key,
|
|
plaintext
|
|
);
|
|
|
|
// 将IV和密文拼接在一起
|
|
const result = new Uint8Array(iv.length + encrypted.byteLength);
|
|
result.set(iv, 0);
|
|
result.set(new Uint8Array(encrypted), iv.length);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 解密数据
|
|
*/
|
|
async decrypt(ciphertext: Uint8Array): Promise<Uint8Array> {
|
|
if (!this.key) {
|
|
throw new Error('密钥未设置');
|
|
}
|
|
|
|
// 提取IV
|
|
const iv = ciphertext.slice(0, 12);
|
|
const data = ciphertext.slice(12);
|
|
|
|
const decrypted = await crypto.subtle.decrypt(
|
|
{
|
|
name: 'AES-GCM',
|
|
iv: iv,
|
|
},
|
|
this.key,
|
|
data
|
|
);
|
|
|
|
return new Uint8Array(decrypted);
|
|
}
|
|
|
|
/**
|
|
* 返回算法名称
|
|
*/
|
|
name(): string {
|
|
return 'AES-GCM-256';
|
|
}
|
|
}
|