添加导入加密插件"laoqianjunzi-crypto"
This commit is contained in:
@@ -0,0 +1,771 @@
|
||||
import type { CryptoBlockMode, CryptoByteCipherOptions, CryptoCodecKind, CryptoDesOptions, CryptoDigestKind, CryptoMacKind, CryptoPaddingKind, CryptoRsaPair, CryptoTextCipherOptions, RsaOutputKind } from '../interface.uts'
|
||||
|
||||
const LIME_MODE_CBC = 1
|
||||
const LIME_MODE_CFB = 2
|
||||
const LIME_MODE_CTR = 3
|
||||
const LIME_MODE_CTR_GLADMAN = 4
|
||||
const LIME_MODE_ECB = 5
|
||||
const LIME_MODE_OFB = 6
|
||||
|
||||
const LIME_PAD_PKCS7 = 1
|
||||
const LIME_PAD_ANSI_X923 = 2
|
||||
const LIME_PAD_ISO_10126 = 3
|
||||
const LIME_PAD_ISO_97971 = 4
|
||||
const LIME_PAD_NONE = 5
|
||||
const LIME_PAD_ZERO = 6
|
||||
|
||||
const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
|
||||
export type CompatBridge = {
|
||||
encodeText : (codec : CryptoCodecKind, plainText : string) => string,
|
||||
decodeText : (codec : CryptoCodecKind, encodedText : string) => string,
|
||||
digestText : (kind : CryptoDigestKind, plainText : string) => string,
|
||||
signText : (kind : CryptoMacKind, secretText : string, plainText : string) => string,
|
||||
aesEncryptText : (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) => string,
|
||||
aesDecryptText : (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) => string,
|
||||
aesEncryptBytes : (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) => Uint8Array,
|
||||
aesDecryptBytes : (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) => Uint8Array,
|
||||
desEncryptText : (secretText : string, plainText : string, options : CryptoDesOptions | null) => string,
|
||||
desDecryptText : (secretText : string, cipherText : string, options : CryptoDesOptions | null) => string,
|
||||
createRsaPair : (keySize : number) => CryptoRsaPair,
|
||||
rsaEncryptText : (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) => string,
|
||||
rsaDecryptText : (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) => string,
|
||||
rc4EncryptText : (secretText : string, plainText : string) => string,
|
||||
rc4DecryptText : (secretText : string, cipherHexText : string) => string
|
||||
}
|
||||
|
||||
export type CompatEncSet = {
|
||||
Utf8 : CompatEncoder,
|
||||
Hex : CompatEncoder,
|
||||
Base64 : CompatEncoder,
|
||||
Latin1 : CompatEncoder,
|
||||
Utf16 : CompatEncoder,
|
||||
Base64url : CompatEncoder
|
||||
}
|
||||
|
||||
export type CompatModeSet = {
|
||||
CBC : number,
|
||||
CFB : number,
|
||||
CTR : number,
|
||||
CTRGladman : number,
|
||||
ECB : number,
|
||||
OFB : number
|
||||
}
|
||||
|
||||
export type CompatPadSet = {
|
||||
Pkcs7 : number,
|
||||
AnsiX923 : number,
|
||||
Iso10126 : number,
|
||||
Iso97971 : number,
|
||||
NoPadding : number,
|
||||
ZeroPadding : number
|
||||
}
|
||||
|
||||
export function createCompatBridge(
|
||||
encodeText : (codec : CryptoCodecKind, plainText : string) => string,
|
||||
decodeText : (codec : CryptoCodecKind, encodedText : string) => string,
|
||||
digestText : (kind : CryptoDigestKind, plainText : string) => string,
|
||||
signText : (kind : CryptoMacKind, secretText : string, plainText : string) => string,
|
||||
aesEncryptText : (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) => string,
|
||||
aesDecryptText : (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) => string,
|
||||
aesEncryptBytes : (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) => Uint8Array,
|
||||
aesDecryptBytes : (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) => Uint8Array,
|
||||
desEncryptText : (secretText : string, plainText : string, options : CryptoDesOptions | null) => string,
|
||||
desDecryptText : (secretText : string, cipherText : string, options : CryptoDesOptions | null) => string,
|
||||
createRsaPair : (keySize : number) => CryptoRsaPair,
|
||||
rsaEncryptText : (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) => string,
|
||||
rsaDecryptText : (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) => string,
|
||||
rc4EncryptText : (secretText : string, plainText : string) => string,
|
||||
rc4DecryptText : (secretText : string, cipherHexText : string) => string
|
||||
) : CompatBridge {
|
||||
return {
|
||||
encodeText,
|
||||
decodeText,
|
||||
digestText,
|
||||
signText,
|
||||
aesEncryptText,
|
||||
aesDecryptText,
|
||||
aesEncryptBytes,
|
||||
aesDecryptBytes,
|
||||
desEncryptText,
|
||||
desDecryptText,
|
||||
createRsaPair,
|
||||
rsaEncryptText,
|
||||
rsaDecryptText,
|
||||
rc4EncryptText,
|
||||
rc4DecryptText
|
||||
} as CompatBridge
|
||||
}
|
||||
|
||||
function cloneBytes(input : Uint8Array) : Uint8Array {
|
||||
const output = new Uint8Array(input.length)
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
output[index] = input[index]
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function bytesToWords(input : Uint8Array) : number[] {
|
||||
const output = [] as number[]
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
let word = 0
|
||||
let offset = 0
|
||||
while (offset < 4 && index + offset < input.length) {
|
||||
word |= input[index + offset] << (24 - offset * 8)
|
||||
offset += 1
|
||||
}
|
||||
output.push(word)
|
||||
index += 4
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function byteToHex(value : number) : string {
|
||||
let part = value.toString(16)
|
||||
if (part.length < 2) {
|
||||
part = '0' + part
|
||||
}
|
||||
return part
|
||||
}
|
||||
|
||||
function bytesToHex(input : Uint8Array) : string {
|
||||
let output = ''
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
output += byteToHex(input[index] & 0xff)
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function hexValueOfChar(ch : string) : number {
|
||||
const lower = ch.toLowerCase()
|
||||
const code = lower.charCodeAt(0)
|
||||
const actualCode = code == null ? 0 : code
|
||||
if (lower >= '0' && lower <= '9') {
|
||||
return actualCode - 48
|
||||
}
|
||||
return actualCode - 87
|
||||
}
|
||||
|
||||
function hexToBytes(hexText : string) : Uint8Array {
|
||||
const actualLength = hexText.length % 2 == 0 ? hexText.length : hexText.length - 1
|
||||
const output = new Uint8Array(actualLength / 2)
|
||||
let index = 0
|
||||
while (index < actualLength) {
|
||||
const high = hexValueOfChar(hexText.substring(index, index + 1))
|
||||
const low = hexValueOfChar(hexText.substring(index + 1, index + 2))
|
||||
const targetIndex = index / 2
|
||||
output[targetIndex] = ((high << 4) | low) & 0xff
|
||||
index += 2
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function base64IndexOf(ch : string) : number {
|
||||
return BASE64_ALPHABET.indexOf(ch)
|
||||
}
|
||||
|
||||
function toBase64UrlText(input : string) : string {
|
||||
let output = ''
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
const ch = input.substring(index, index + 1)
|
||||
if (ch == '+') {
|
||||
output += '-'
|
||||
} else if (ch == '/') {
|
||||
output += '_'
|
||||
} else if (ch != '=') {
|
||||
output += ch
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function fromBase64UrlText(input : string) : string {
|
||||
let output = ''
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
const ch = input.substring(index, index + 1)
|
||||
if (ch == '-') {
|
||||
output += '+'
|
||||
} else if (ch == '_') {
|
||||
output += '/'
|
||||
} else {
|
||||
output += ch
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
while (output.length % 4 != 0) {
|
||||
output += '='
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function bytesToBase64(input : Uint8Array, urlSafe : boolean) : string {
|
||||
let output = ''
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
const first = input[index] & 0xff
|
||||
const hasSecond = index + 1 < input.length
|
||||
const hasThird = index + 2 < input.length
|
||||
const second = hasSecond ? input[index + 1] & 0xff : 0
|
||||
const third = hasThird ? input[index + 2] & 0xff : 0
|
||||
const block = (first << 16) | (second << 8) | third
|
||||
output += BASE64_ALPHABET.substring((block >>> 18) & 0x3f, ((block >>> 18) & 0x3f) + 1)
|
||||
output += BASE64_ALPHABET.substring((block >>> 12) & 0x3f, ((block >>> 12) & 0x3f) + 1)
|
||||
if (hasSecond) {
|
||||
output += BASE64_ALPHABET.substring((block >>> 6) & 0x3f, ((block >>> 6) & 0x3f) + 1)
|
||||
} else {
|
||||
output += '='
|
||||
}
|
||||
if (hasThird) {
|
||||
output += BASE64_ALPHABET.substring(block & 0x3f, (block & 0x3f) + 1)
|
||||
} else {
|
||||
output += '='
|
||||
}
|
||||
index += 3
|
||||
}
|
||||
if (urlSafe) {
|
||||
return toBase64UrlText(output)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function normalizeBase64Text(input : string) : string {
|
||||
return fromBase64UrlText(input)
|
||||
}
|
||||
|
||||
function base64ToBytes(input : string, urlSafe : boolean) : Uint8Array {
|
||||
const source = urlSafe ? normalizeBase64Text(input) : input
|
||||
const output = [] as number[]
|
||||
let index = 0
|
||||
while (index < source.length) {
|
||||
const char1 = source.substring(index, index + 1)
|
||||
const char2 = source.substring(index + 1, index + 2)
|
||||
const char3 = source.substring(index + 2, index + 3)
|
||||
const char4 = source.substring(index + 3, index + 4)
|
||||
const value1 = base64IndexOf(char1)
|
||||
const value2 = base64IndexOf(char2)
|
||||
const value3 = char3 == '=' ? -1 : base64IndexOf(char3)
|
||||
const value4 = char4 == '=' ? -1 : base64IndexOf(char4)
|
||||
const block = (value1 << 18) | (value2 << 12) | ((value3 < 0 ? 0 : value3) << 6) | (value4 < 0 ? 0 : value4)
|
||||
output.push((block >>> 16) & 0xff)
|
||||
if (value3 >= 0) {
|
||||
output.push((block >>> 8) & 0xff)
|
||||
}
|
||||
if (value4 >= 0) {
|
||||
output.push(block & 0xff)
|
||||
}
|
||||
index += 4
|
||||
}
|
||||
return new Uint8Array(output)
|
||||
}
|
||||
|
||||
function latin1ToBytes(input : string) : Uint8Array {
|
||||
const output = new Uint8Array(input.length)
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
const code = input.charCodeAt(index)
|
||||
output[index] = (code == null ? 0 : code) & 0xff
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function bytesToLatin1(input : Uint8Array) : string {
|
||||
let output = ''
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
output += String.fromCharCode(input[index] & 0xff)
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function utf16ToBytes(input : string) : Uint8Array {
|
||||
const output = new Uint8Array(input.length * 2)
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
const code = input.charCodeAt(index)
|
||||
const actualCode = code == null ? 0 : code
|
||||
output[index * 2] = (actualCode >>> 8) & 0xff
|
||||
output[index * 2 + 1] = actualCode & 0xff
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function bytesToUtf16(input : Uint8Array) : string {
|
||||
let output = ''
|
||||
let index = 0
|
||||
while (index + 1 < input.length) {
|
||||
const code = ((input[index] & 0xff) << 8) | (input[index + 1] & 0xff)
|
||||
output += String.fromCharCode(code)
|
||||
index += 2
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function textToUtf8Bytes(input : string, bridge : CompatBridge) : Uint8Array {
|
||||
return hexToBytes(bridge.encodeText('hex', input))
|
||||
}
|
||||
|
||||
function utf8BytesToText(input : Uint8Array, bridge : CompatBridge) : string {
|
||||
return bridge.decodeText('hex', bytesToHex(input))
|
||||
}
|
||||
|
||||
function parseCodecBytes(kind : CryptoCodecKind, input : string, bridge : CompatBridge) : Uint8Array {
|
||||
if (kind == 'utf8') {
|
||||
return textToUtf8Bytes(input, bridge)
|
||||
}
|
||||
if (kind == 'hex') {
|
||||
return hexToBytes(input)
|
||||
}
|
||||
if (kind == 'base64') {
|
||||
return base64ToBytes(input, false)
|
||||
}
|
||||
if (kind == 'base64url') {
|
||||
return base64ToBytes(input, true)
|
||||
}
|
||||
if (kind == 'latin1') {
|
||||
return latin1ToBytes(input)
|
||||
}
|
||||
return utf16ToBytes(input)
|
||||
}
|
||||
|
||||
function stringifyCodecBytes(kind : CryptoCodecKind, input : Uint8Array, bridge : CompatBridge) : string {
|
||||
if (kind == 'utf8') {
|
||||
return utf8BytesToText(input, bridge)
|
||||
}
|
||||
if (kind == 'hex') {
|
||||
return bytesToHex(input)
|
||||
}
|
||||
if (kind == 'base64') {
|
||||
return bytesToBase64(input, false)
|
||||
}
|
||||
if (kind == 'base64url') {
|
||||
return bytesToBase64(input, true)
|
||||
}
|
||||
if (kind == 'latin1') {
|
||||
return bytesToLatin1(input)
|
||||
}
|
||||
return bytesToUtf16(input)
|
||||
}
|
||||
|
||||
function normalizeKeyLength(keySize : number | null) : number | null {
|
||||
if (keySize == null) {
|
||||
return null
|
||||
}
|
||||
if (keySize == 128) {
|
||||
return 16
|
||||
}
|
||||
if (keySize == 192) {
|
||||
return 24
|
||||
}
|
||||
if (keySize == 256) {
|
||||
return 32
|
||||
}
|
||||
if (keySize == 16 || keySize == 24 || keySize == 32) {
|
||||
return keySize
|
||||
}
|
||||
return 16
|
||||
}
|
||||
|
||||
function toLimeMode(mode : number | null) : CryptoBlockMode {
|
||||
if (mode == LIME_MODE_CFB) {
|
||||
return 'CFB'
|
||||
}
|
||||
if (mode == LIME_MODE_CTR) {
|
||||
return 'CTR'
|
||||
}
|
||||
if (mode == LIME_MODE_CTR_GLADMAN) {
|
||||
return 'CTRGladman'
|
||||
}
|
||||
if (mode == LIME_MODE_ECB) {
|
||||
return 'ECB'
|
||||
}
|
||||
if (mode == LIME_MODE_OFB) {
|
||||
return 'OFB'
|
||||
}
|
||||
return 'CBC'
|
||||
}
|
||||
|
||||
function toLimePadding(padding : number | null) : CryptoPaddingKind {
|
||||
if (padding == LIME_PAD_ANSI_X923) {
|
||||
return 'ANSI_X923'
|
||||
}
|
||||
if (padding == LIME_PAD_ISO_10126) {
|
||||
return 'ISO_10126'
|
||||
}
|
||||
if (padding == LIME_PAD_ISO_97971) {
|
||||
return 'ISO_97971'
|
||||
}
|
||||
if (padding == LIME_PAD_NONE) {
|
||||
return 'NONE'
|
||||
}
|
||||
if (padding == LIME_PAD_ZERO) {
|
||||
return 'ZERO'
|
||||
}
|
||||
return 'PKCS7'
|
||||
}
|
||||
|
||||
function readConfigNumber(cfg : UTSJSONObject | null, key : string) : number | null {
|
||||
if (cfg == null) {
|
||||
return null
|
||||
}
|
||||
return cfg.getNumber(key)
|
||||
}
|
||||
|
||||
function readConfigWordArray(cfg : UTSJSONObject | null, key : string) : CompatWordArray | null {
|
||||
if (cfg == null) {
|
||||
return null
|
||||
}
|
||||
const raw = cfg.get(key) as object | null
|
||||
if (raw != null && raw instanceof CompatWordArray) {
|
||||
return raw as CompatWordArray
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function buildLimeTextOptions(cfg : UTSJSONObject | null, bridge : CompatBridge) : CryptoTextCipherOptions {
|
||||
const iv = readConfigWordArray(cfg, 'iv')
|
||||
return {
|
||||
mode: toLimeMode(readConfigNumber(cfg, 'mode')),
|
||||
padding: toLimePadding(readConfigNumber(cfg, 'padding')),
|
||||
ivText: iv == null ? null : utf8BytesToText(iv.toUint8Array(), bridge),
|
||||
keyLength: null
|
||||
} as CryptoTextCipherOptions
|
||||
}
|
||||
|
||||
function buildLimeDesOptions(cfg : UTSJSONObject | null, bridge : CompatBridge) : CryptoDesOptions {
|
||||
const iv = readConfigWordArray(cfg, 'iv')
|
||||
return {
|
||||
mode: toLimeMode(readConfigNumber(cfg, 'mode')),
|
||||
padding: toLimePadding(readConfigNumber(cfg, 'padding')),
|
||||
ivText: iv == null ? null : utf8BytesToText(iv.toUint8Array(), bridge)
|
||||
} as CryptoDesOptions
|
||||
}
|
||||
|
||||
function buildXTextOptions(mode : string, iv : string | null, keySize : number | null) : CryptoTextCipherOptions {
|
||||
return {
|
||||
mode: mode == 'CBC' ? 'CBC' : 'ECB',
|
||||
padding: 'PKCS7',
|
||||
ivText: iv,
|
||||
keyLength: normalizeKeyLength(keySize)
|
||||
} as CryptoTextCipherOptions
|
||||
}
|
||||
|
||||
function buildXByteOptions(mode : string, iv : Uint8Array | null, keySize : number | null) : CryptoByteCipherOptions {
|
||||
return {
|
||||
mode: mode == 'CBC' ? 'CBC' : 'ECB',
|
||||
padding: 'PKCS7',
|
||||
ivBytes: iv,
|
||||
keyLength: normalizeKeyLength(keySize)
|
||||
} as CryptoByteCipherOptions
|
||||
}
|
||||
|
||||
function buildXDesOptions(mode : string, iv : string | null) : CryptoDesOptions {
|
||||
return {
|
||||
mode: mode == 'CBC' ? 'CBC' : 'ECB',
|
||||
padding: 'PKCS7',
|
||||
ivText: iv
|
||||
} as CryptoDesOptions
|
||||
}
|
||||
|
||||
function keyToText(key : string | CompatWordArray, bridge : CompatBridge) : string {
|
||||
if (typeof key == 'string') {
|
||||
return key
|
||||
}
|
||||
if (key instanceof CompatWordArray) {
|
||||
return utf8BytesToText(key.toUint8Array(), bridge)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export class CompatWordArray {
|
||||
words : number[]
|
||||
sigBytes : number
|
||||
private rawBytes : Uint8Array
|
||||
|
||||
constructor(rawBytes : Uint8Array) {
|
||||
this.rawBytes = cloneBytes(rawBytes)
|
||||
this.words = bytesToWords(this.rawBytes)
|
||||
this.sigBytes = this.rawBytes.length
|
||||
}
|
||||
|
||||
toString(encoder : CompatEncoder | null = null) : string {
|
||||
if (encoder == null) {
|
||||
return bytesToHex(this.rawBytes)
|
||||
}
|
||||
return encoder.stringify(this)
|
||||
}
|
||||
|
||||
toUint8Array() : Uint8Array {
|
||||
return cloneBytes(this.rawBytes)
|
||||
}
|
||||
}
|
||||
|
||||
export class CompatCipherResult {
|
||||
ciphertext : CompatWordArray
|
||||
private serialized : string
|
||||
|
||||
constructor(serialized : string, cipherBytes : Uint8Array) {
|
||||
this.serialized = serialized
|
||||
this.ciphertext = new CompatWordArray(cipherBytes)
|
||||
}
|
||||
|
||||
toString(encoder : CompatEncoder | null = null) : string {
|
||||
if (encoder == null) {
|
||||
return this.serialized
|
||||
}
|
||||
return this.ciphertext.toString(encoder)
|
||||
}
|
||||
}
|
||||
|
||||
export class CompatEncoder {
|
||||
private kind : CryptoCodecKind
|
||||
private bridge : CompatBridge
|
||||
|
||||
constructor(kind : CryptoCodecKind, bridge : CompatBridge) {
|
||||
this.kind = kind
|
||||
this.bridge = bridge
|
||||
}
|
||||
|
||||
parse(input : string) : CompatWordArray {
|
||||
return new CompatWordArray(parseCodecBytes(this.kind, input, this.bridge))
|
||||
}
|
||||
|
||||
stringify(wordArray : CompatWordArray) : string {
|
||||
return stringifyCodecBytes(this.kind, wordArray.toUint8Array(), this.bridge)
|
||||
}
|
||||
}
|
||||
|
||||
export class CompatRsaAdapter {
|
||||
private bridge : CompatBridge
|
||||
private publicKey : string = ''
|
||||
private privateKey : string = ''
|
||||
|
||||
constructor(bridge : CompatBridge) {
|
||||
this.bridge = bridge
|
||||
}
|
||||
|
||||
generateKeyPair() : CryptoRsaPair {
|
||||
const pair = this.bridge.createRsaPair(2048)
|
||||
this.publicKey = pair.publicKey
|
||||
this.privateKey = pair.privateKey
|
||||
return pair
|
||||
}
|
||||
|
||||
setPublicKey(publicKey : string) : void {
|
||||
this.publicKey = publicKey
|
||||
}
|
||||
|
||||
setPrivateKey(privateKey : string) : void {
|
||||
this.privateKey = privateKey
|
||||
}
|
||||
|
||||
encrypt(data : string) : string {
|
||||
return this.bridge.rsaEncryptText(this.publicKey, data, 'base64')
|
||||
}
|
||||
|
||||
decrypt(encryptedData : string) : string {
|
||||
return this.bridge.rsaDecryptText(this.privateKey, encryptedData, 'base64')
|
||||
}
|
||||
|
||||
getPublicKey() : string {
|
||||
return this.publicKey
|
||||
}
|
||||
|
||||
getPrivateKey() : string {
|
||||
return this.privateKey
|
||||
}
|
||||
}
|
||||
|
||||
export class CompatSymmetricAdapter {
|
||||
private bridge : CompatBridge
|
||||
private algorithm : string
|
||||
|
||||
constructor(bridge : CompatBridge, algorithm : string) {
|
||||
this.bridge = bridge
|
||||
this.algorithm = algorithm
|
||||
}
|
||||
|
||||
encrypt(message : string, key : string | CompatWordArray, cfg : UTSJSONObject | null = null) : CompatCipherResult {
|
||||
const keyText = keyToText(key, this.bridge)
|
||||
if (this.algorithm == 'DES') {
|
||||
const cipherText = this.bridge.desEncryptText(keyText, message, buildLimeDesOptions(cfg, this.bridge))
|
||||
return new CompatCipherResult(cipherText, parseCodecBytes('base64', cipherText, this.bridge))
|
||||
}
|
||||
const cipherText = this.bridge.aesEncryptText(keyText, message, buildLimeTextOptions(cfg, this.bridge))
|
||||
return new CompatCipherResult(cipherText, parseCodecBytes('base64', cipherText, this.bridge))
|
||||
}
|
||||
|
||||
decrypt(ciphertext : string, password : string | CompatWordArray, cfg : UTSJSONObject | null = null) : CompatWordArray {
|
||||
const keyText = keyToText(password, this.bridge)
|
||||
if (this.algorithm == 'DES') {
|
||||
return new CompatWordArray(textToUtf8Bytes(this.bridge.desDecryptText(keyText, ciphertext, buildLimeDesOptions(cfg, this.bridge)), this.bridge))
|
||||
}
|
||||
return new CompatWordArray(textToUtf8Bytes(this.bridge.aesDecryptText(keyText, ciphertext, buildLimeTextOptions(cfg, this.bridge)), this.bridge))
|
||||
}
|
||||
}
|
||||
|
||||
export class CompatCrypto {
|
||||
enc : CompatEncSet
|
||||
mode : CompatModeSet
|
||||
pad : CompatPadSet
|
||||
AES : CompatSymmetricAdapter
|
||||
DES : CompatSymmetricAdapter
|
||||
RSA : CompatRsaAdapter
|
||||
private bridge : CompatBridge
|
||||
|
||||
constructor(bridge : CompatBridge) {
|
||||
this.bridge = bridge
|
||||
this.enc = {
|
||||
Utf8: new CompatEncoder('utf8', bridge),
|
||||
Hex: new CompatEncoder('hex', bridge),
|
||||
Base64: new CompatEncoder('base64', bridge),
|
||||
Latin1: new CompatEncoder('latin1', bridge),
|
||||
Utf16: new CompatEncoder('utf16', bridge),
|
||||
Base64url: new CompatEncoder('base64url', bridge)
|
||||
} as CompatEncSet
|
||||
this.mode = {
|
||||
CBC: LIME_MODE_CBC,
|
||||
CFB: LIME_MODE_CFB,
|
||||
CTR: LIME_MODE_CTR,
|
||||
CTRGladman: LIME_MODE_CTR_GLADMAN,
|
||||
ECB: LIME_MODE_ECB,
|
||||
OFB: LIME_MODE_OFB
|
||||
} as CompatModeSet
|
||||
this.pad = {
|
||||
Pkcs7: LIME_PAD_PKCS7,
|
||||
AnsiX923: LIME_PAD_ANSI_X923,
|
||||
Iso10126: LIME_PAD_ISO_10126,
|
||||
Iso97971: LIME_PAD_ISO_97971,
|
||||
NoPadding: LIME_PAD_NONE,
|
||||
ZeroPadding: LIME_PAD_ZERO
|
||||
} as CompatPadSet
|
||||
this.AES = new CompatSymmetricAdapter(bridge, 'AES')
|
||||
this.DES = new CompatSymmetricAdapter(bridge, 'DES')
|
||||
this.RSA = new CompatRsaAdapter(bridge)
|
||||
}
|
||||
|
||||
MD5(message : string) : CompatWordArray {
|
||||
return new CompatWordArray(hexToBytes(this.bridge.digestText('md5', message)))
|
||||
}
|
||||
|
||||
SHA1(message : string) : CompatWordArray {
|
||||
return new CompatWordArray(hexToBytes(this.bridge.digestText('sha1', message)))
|
||||
}
|
||||
|
||||
SHA256(message : string) : CompatWordArray {
|
||||
return new CompatWordArray(hexToBytes(this.bridge.digestText('sha256', message)))
|
||||
}
|
||||
|
||||
SHA512(message : string) : CompatWordArray {
|
||||
return new CompatWordArray(hexToBytes(this.bridge.digestText('sha512', message)))
|
||||
}
|
||||
|
||||
HmacSHA256(message : string, secretKey : string | CompatWordArray) : CompatWordArray {
|
||||
return new CompatWordArray(hexToBytes(this.bridge.signText('sha256', typeof secretKey == 'string' ? secretKey : keyToText(secretKey, this.bridge), message)))
|
||||
}
|
||||
|
||||
HmacSHA1(message : string, secretKey : string | CompatWordArray) : CompatWordArray {
|
||||
return new CompatWordArray(hexToBytes(this.bridge.signText('sha1', typeof secretKey == 'string' ? secretKey : keyToText(secretKey, this.bridge), message)))
|
||||
}
|
||||
|
||||
HmacSHA512(message : string, secretKey : string | CompatWordArray) : CompatWordArray {
|
||||
return new CompatWordArray(hexToBytes(this.bridge.signText('sha512', typeof secretKey == 'string' ? secretKey : keyToText(secretKey, this.bridge), message)))
|
||||
}
|
||||
|
||||
onError(_callback : (err : IUniError) => void) : void {
|
||||
}
|
||||
}
|
||||
|
||||
export function createCompatCrypto(bridge : CompatBridge) : CompatCrypto {
|
||||
return new CompatCrypto(bridge)
|
||||
}
|
||||
|
||||
export function base64EncodeCompat(bridge : CompatBridge, input : string) : string {
|
||||
return bridge.encodeText('base64', input)
|
||||
}
|
||||
|
||||
export function base64DecodeCompat(bridge : CompatBridge, input : string) : string {
|
||||
return bridge.decodeText('base64', input)
|
||||
}
|
||||
|
||||
export function md5Compat(bridge : CompatBridge, input : string) : string {
|
||||
return bridge.digestText('md5', input)
|
||||
}
|
||||
|
||||
export function sha1Compat(bridge : CompatBridge, input : string) : string {
|
||||
return bridge.digestText('sha1', input)
|
||||
}
|
||||
|
||||
export function sha256Compat(bridge : CompatBridge, input : string) : string {
|
||||
return bridge.digestText('sha256', input)
|
||||
}
|
||||
|
||||
export function sha512Compat(bridge : CompatBridge, input : string) : string {
|
||||
return bridge.digestText('sha512', input)
|
||||
}
|
||||
|
||||
export function hmacSha1Compat(bridge : CompatBridge, key : string, data : string) : string {
|
||||
return bridge.signText('sha1', key, data)
|
||||
}
|
||||
|
||||
export function hmacSha256Compat(bridge : CompatBridge, key : string, data : string) : string {
|
||||
return bridge.signText('sha256', key, data)
|
||||
}
|
||||
|
||||
export function hmacSha512Compat(bridge : CompatBridge, key : string, data : string) : string {
|
||||
return bridge.signText('sha512', key, data)
|
||||
}
|
||||
|
||||
export function aesEncryptCompat(bridge : CompatBridge, key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
|
||||
return bridge.aesEncryptText(key, data, buildXTextOptions(mode, iv, keySize))
|
||||
}
|
||||
|
||||
export function aesDecryptCompat(bridge : CompatBridge, key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
|
||||
return bridge.aesDecryptText(key, data, buildXTextOptions(mode, iv, keySize))
|
||||
}
|
||||
|
||||
export function aesEncryptBytesCompat(bridge : CompatBridge, key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
|
||||
return bridge.aesEncryptBytes(key, data, buildXByteOptions(mode, iv, keySize))
|
||||
}
|
||||
|
||||
export function aesDecryptBytesCompat(bridge : CompatBridge, key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
|
||||
return bridge.aesDecryptBytes(key, data, buildXByteOptions(mode, iv, keySize))
|
||||
}
|
||||
|
||||
export function desEncryptCompat(bridge : CompatBridge, key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
|
||||
return bridge.desEncryptText(key, data, buildXDesOptions(mode, iv))
|
||||
}
|
||||
|
||||
export function desDecryptCompat(bridge : CompatBridge, key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
|
||||
return bridge.desDecryptText(key, data, buildXDesOptions(mode, iv))
|
||||
}
|
||||
|
||||
export function generateRsaKeyPairCompat(bridge : CompatBridge, keySize : number = 2048) : CryptoRsaPair {
|
||||
return bridge.createRsaPair(keySize)
|
||||
}
|
||||
|
||||
export function rsaEncryptCompat(bridge : CompatBridge, publicKey : string, data : string) : string {
|
||||
return bridge.rsaEncryptText(publicKey, data, 'base64')
|
||||
}
|
||||
|
||||
export function rsaDecryptCompat(bridge : CompatBridge, privateKey : string, data : string) : string {
|
||||
return bridge.rsaDecryptText(privateKey, data, 'base64')
|
||||
}
|
||||
|
||||
export function rc4EncryptCompat(bridge : CompatBridge, key : string, data : string) : string {
|
||||
return bridge.rc4EncryptText(key, data)
|
||||
}
|
||||
|
||||
export function rc4DecryptCompat(bridge : CompatBridge, key : string, data : string) : string {
|
||||
return bridge.rc4DecryptText(key, data)
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { CryptoBlockMode, CryptoByteCipherOptions, CryptoDesOptions, CryptoPaddingKind, CryptoRuntimeSnapshot, CryptoTextCipherOptions, CryptoTripleDesOptions, RsaOutputKind } from "../interface.uts"
|
||||
|
||||
export function createDefaultTextCipherOptions() : CryptoTextCipherOptions {
|
||||
return {
|
||||
mode: "CBC",
|
||||
padding: "PKCS7",
|
||||
ivText: "0123456789abcdef",
|
||||
keyLength: 16
|
||||
} as CryptoTextCipherOptions
|
||||
}
|
||||
|
||||
export function createDefaultByteCipherOptions() : CryptoByteCipherOptions {
|
||||
return {
|
||||
mode: "CBC",
|
||||
padding: "PKCS7",
|
||||
ivBytes: new Uint8Array([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102]),
|
||||
keyLength: 16
|
||||
} as CryptoByteCipherOptions
|
||||
}
|
||||
|
||||
export function createDefaultTripleDesOptions() : CryptoTripleDesOptions {
|
||||
return {
|
||||
mode: "CBC",
|
||||
ivText: "12345678"
|
||||
} as CryptoTripleDesOptions
|
||||
}
|
||||
|
||||
export function createDefaultDesOptions() : CryptoDesOptions {
|
||||
return {
|
||||
mode: "CBC",
|
||||
padding: "PKCS7",
|
||||
ivText: "12345678"
|
||||
} as CryptoDesOptions
|
||||
}
|
||||
|
||||
export function normalizeTextCipherOptions(options : CryptoTextCipherOptions | null) : CryptoTextCipherOptions {
|
||||
if (options == null) {
|
||||
return createDefaultTextCipherOptions()
|
||||
}
|
||||
return {
|
||||
mode: options.mode,
|
||||
padding: options.padding,
|
||||
ivText: options.ivText,
|
||||
keyLength: options.keyLength
|
||||
} as CryptoTextCipherOptions
|
||||
}
|
||||
|
||||
export function normalizeByteCipherOptions(options : CryptoByteCipherOptions | null) : CryptoByteCipherOptions {
|
||||
if (options == null) {
|
||||
return createDefaultByteCipherOptions()
|
||||
}
|
||||
return {
|
||||
mode: options.mode,
|
||||
padding: options.padding,
|
||||
ivBytes: options.ivBytes,
|
||||
keyLength: options.keyLength
|
||||
} as CryptoByteCipherOptions
|
||||
}
|
||||
|
||||
export function normalizeTripleDesOptions(options : CryptoTripleDesOptions | null) : CryptoTripleDesOptions {
|
||||
if (options == null) {
|
||||
return createDefaultTripleDesOptions()
|
||||
}
|
||||
return {
|
||||
mode: options.mode,
|
||||
ivText: options.ivText
|
||||
} as CryptoTripleDesOptions
|
||||
}
|
||||
|
||||
export function normalizeDesOptions(options : CryptoDesOptions | null) : CryptoDesOptions {
|
||||
if (options == null) {
|
||||
return createDefaultDesOptions()
|
||||
}
|
||||
return {
|
||||
mode: options.mode,
|
||||
padding: options.padding,
|
||||
ivText: options.ivText
|
||||
} as CryptoDesOptions
|
||||
}
|
||||
|
||||
export function buildRuntimeSnapshot(platformName : string, engineName : string, supportsAdvancedModes : boolean, usesNativeBridge : boolean) : CryptoRuntimeSnapshot {
|
||||
return {
|
||||
platformName: platformName,
|
||||
engineName: engineName,
|
||||
supportsAdvancedModes: supportsAdvancedModes,
|
||||
usesNativeBridge: usesNativeBridge
|
||||
} as CryptoRuntimeSnapshot
|
||||
}
|
||||
|
||||
export function resolveHexOutput(outputKind : RsaOutputKind | null) : boolean {
|
||||
return outputKind == "hex"
|
||||
}
|
||||
|
||||
export function createAsciiBlock(text : string, size : number) : Uint8Array {
|
||||
const output = new Uint8Array(size)
|
||||
let index = 0
|
||||
while (index < size) {
|
||||
if (index < text.length) {
|
||||
output[index] = text.charCodeAt(index) & 0xff
|
||||
} else {
|
||||
output[index] = 0
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
// @ts-nocheck
|
||||
import CryptoES from '../deps/node_modules/crypto-es/lib/index.js'
|
||||
import JSEncrypt from '../deps/node_modules/jsencrypt/lib/index.js'
|
||||
|
||||
function ensureSupportedCodec(codec: string): void {
|
||||
const value = codec.toLowerCase()
|
||||
if (value == 'utf8' || value == 'hex' || value == 'base64' || value == 'base64url' || value == 'latin1' || value == 'utf16') {
|
||||
return
|
||||
}
|
||||
throw new Error('不支持的编码类型')
|
||||
}
|
||||
|
||||
function ensureDigestKind(kind: string): string {
|
||||
const value = kind.toLowerCase()
|
||||
if (value == 'md5' || value == 'sha1' || value == 'sha256' || value == 'sha512') {
|
||||
return value
|
||||
}
|
||||
throw new Error('不支持的摘要算法')
|
||||
}
|
||||
|
||||
function ensureMacKind(kind: string): string {
|
||||
const value = kind.toLowerCase()
|
||||
if (value == 'sha1' || value == 'sha256' || value == 'sha512') {
|
||||
return value
|
||||
}
|
||||
throw new Error('不支持的HMAC算法')
|
||||
}
|
||||
|
||||
function ensureAesMode(mode: string): any {
|
||||
const value = mode.toUpperCase()
|
||||
if (value == 'CBC') {
|
||||
return CryptoES.mode.CBC
|
||||
}
|
||||
if (value == 'CFB') {
|
||||
return CryptoES.mode.CFB
|
||||
}
|
||||
if (value == 'CTR') {
|
||||
return CryptoES.mode.CTR
|
||||
}
|
||||
if (value == 'CTRGLADMAN') {
|
||||
return CryptoES.mode.CTRGladman
|
||||
}
|
||||
if (value == 'ECB') {
|
||||
return CryptoES.mode.ECB
|
||||
}
|
||||
if (value == 'OFB') {
|
||||
return CryptoES.mode.OFB
|
||||
}
|
||||
throw new Error('不支持的AES模式')
|
||||
}
|
||||
|
||||
function ensureAesPadding(padding: string): any {
|
||||
const value = padding.toUpperCase()
|
||||
if (value == 'PKCS7') {
|
||||
return CryptoES.pad.Pkcs7
|
||||
}
|
||||
if (value == 'ANSI_X923') {
|
||||
return CryptoES.pad.AnsiX923
|
||||
}
|
||||
if (value == 'ISO_10126') {
|
||||
return CryptoES.pad.Iso10126
|
||||
}
|
||||
if (value == 'ISO_97971') {
|
||||
return CryptoES.pad.Iso97971
|
||||
}
|
||||
if (value == 'NONE') {
|
||||
return CryptoES.pad.NoPadding
|
||||
}
|
||||
if (value == 'ZERO') {
|
||||
return CryptoES.pad.ZeroPadding
|
||||
}
|
||||
throw new Error('不支持的AES填充')
|
||||
}
|
||||
|
||||
function ensureTripleDesMode(mode: string): any {
|
||||
const value = mode.toUpperCase()
|
||||
if (value == 'CBC') {
|
||||
return CryptoES.mode.CBC
|
||||
}
|
||||
if (value == 'ECB') {
|
||||
return CryptoES.mode.ECB
|
||||
}
|
||||
throw new Error('不支持的3DES模式')
|
||||
}
|
||||
|
||||
function ensureDesMode(mode: string): any {
|
||||
const value = mode.toUpperCase()
|
||||
if (value == 'CBC') {
|
||||
return CryptoES.mode.CBC
|
||||
}
|
||||
if (value == 'CFB') {
|
||||
return CryptoES.mode.CFB
|
||||
}
|
||||
if (value == 'CTR') {
|
||||
return CryptoES.mode.CTR
|
||||
}
|
||||
if (value == 'CTRGLADMAN') {
|
||||
return CryptoES.mode.CTRGladman
|
||||
}
|
||||
if (value == 'ECB') {
|
||||
return CryptoES.mode.ECB
|
||||
}
|
||||
if (value == 'OFB') {
|
||||
return CryptoES.mode.OFB
|
||||
}
|
||||
throw new Error('不支持的DES模式')
|
||||
}
|
||||
|
||||
function inferKeyLength(sourceLength: number, hint: number | null): number {
|
||||
if (hint != null) {
|
||||
if (hint == 16 || hint == 24 || hint == 32) {
|
||||
return hint
|
||||
}
|
||||
if (hint == 128) {
|
||||
return 16
|
||||
}
|
||||
if (hint == 192) {
|
||||
return 24
|
||||
}
|
||||
if (hint == 256) {
|
||||
return 32
|
||||
}
|
||||
throw new Error('AES密钥长度无效')
|
||||
}
|
||||
if (sourceLength <= 16) {
|
||||
return 16
|
||||
}
|
||||
if (sourceLength <= 24) {
|
||||
return 24
|
||||
}
|
||||
return 32
|
||||
}
|
||||
|
||||
function clampBytes(source: Uint8Array, targetLength: number): Uint8Array {
|
||||
const output = new Uint8Array(targetLength)
|
||||
const actualLength = source.length < targetLength ? source.length : targetLength
|
||||
let index = 0
|
||||
while (index < actualLength) {
|
||||
output[index] = source[index]
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function textToUtf8Bytes(input: string): Uint8Array {
|
||||
const wordArray = CryptoES.enc.Utf8.parse(input)
|
||||
return wordArrayToBytes(wordArray)
|
||||
}
|
||||
|
||||
function utf8BytesToText(input: Uint8Array): string {
|
||||
return bytesToWordArray(input).toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
|
||||
function bytesToWordArray(input: Uint8Array): any {
|
||||
const words: number[] = []
|
||||
let index = 0
|
||||
while (index < input.length) {
|
||||
let word = 0
|
||||
let offset = 0
|
||||
while (offset < 4 && index + offset < input.length) {
|
||||
word |= input[index + offset] << (24 - offset * 8)
|
||||
offset += 1
|
||||
}
|
||||
words.push(word)
|
||||
index += 4
|
||||
}
|
||||
return CryptoES.lib.WordArray.create(words, input.length)
|
||||
}
|
||||
|
||||
function wordArrayToBytes(wordArray: any): Uint8Array {
|
||||
const sigBytes = wordArray.sigBytes
|
||||
const output = new Uint8Array(sigBytes)
|
||||
const words = wordArray.words
|
||||
let index = 0
|
||||
while (index < sigBytes) {
|
||||
const wordIndex = Math.floor(index / 4)
|
||||
const byteOffset = index % 4
|
||||
output[index] = (words[wordIndex] >>> (24 - byteOffset * 8)) & 0xff
|
||||
index += 1
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function fitKeyText(secretText: string, keyLength: number | null): any {
|
||||
const rawBytes = textToUtf8Bytes(secretText)
|
||||
const actualLength = inferKeyLength(rawBytes.length, keyLength)
|
||||
return bytesToWordArray(clampBytes(rawBytes, actualLength))
|
||||
}
|
||||
|
||||
function fitFixedTextKey(secretText: string, targetLength: number): any {
|
||||
return bytesToWordArray(clampBytes(textToUtf8Bytes(secretText), targetLength))
|
||||
}
|
||||
|
||||
function fitKeyBytes(secretBytes: Uint8Array, keyLength: number | null): any {
|
||||
const actualLength = inferKeyLength(secretBytes.length, keyLength)
|
||||
return bytesToWordArray(clampBytes(secretBytes, actualLength))
|
||||
}
|
||||
|
||||
function fitIvText(ivText: string | null, size: number): any {
|
||||
const source = ivText == null ? new Uint8Array(size) : clampBytes(textToUtf8Bytes(ivText), size)
|
||||
return bytesToWordArray(source)
|
||||
}
|
||||
|
||||
function fitIvBytes(ivBytes: Uint8Array | null, size: number): any {
|
||||
const source = ivBytes == null ? new Uint8Array(size) : clampBytes(ivBytes, size)
|
||||
return bytesToWordArray(source)
|
||||
}
|
||||
|
||||
function wrapCipherBytes(cipherBytes: Uint8Array): any {
|
||||
return CryptoES.lib.CipherParams.create({
|
||||
ciphertext: bytesToWordArray(cipherBytes)
|
||||
})
|
||||
}
|
||||
|
||||
function toBase64Url(base64Text: string): string {
|
||||
return base64Text.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '')
|
||||
}
|
||||
|
||||
function fromBase64Url(base64UrlText: string): string {
|
||||
let output = base64UrlText.replace(/-/g, '+').replace(/_/g, '/')
|
||||
while (output.length % 4 != 0) {
|
||||
output += '='
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function base64ToHex(base64Text: string): string {
|
||||
return CryptoES.enc.Base64.parse(base64Text).toString(CryptoES.enc.Hex)
|
||||
}
|
||||
|
||||
function hexToBase64(hexText: string): string {
|
||||
return CryptoES.enc.Hex.parse(hexText).toString(CryptoES.enc.Base64)
|
||||
}
|
||||
|
||||
export function encodeTextPortable(codec: string, plainText: string): string {
|
||||
ensureSupportedCodec(codec)
|
||||
const value = codec.toLowerCase()
|
||||
if (value == 'utf8') {
|
||||
return plainText
|
||||
}
|
||||
const word = CryptoES.enc.Utf8.parse(plainText)
|
||||
if (value == 'hex') {
|
||||
return CryptoES.enc.Hex.stringify(word)
|
||||
}
|
||||
if (value == 'base64') {
|
||||
return CryptoES.enc.Base64.stringify(word)
|
||||
}
|
||||
if (value == 'base64url') {
|
||||
return toBase64Url(CryptoES.enc.Base64.stringify(word))
|
||||
}
|
||||
if (value == 'latin1') {
|
||||
return CryptoES.enc.Latin1.stringify(word)
|
||||
}
|
||||
return CryptoES.enc.Utf16.stringify(word)
|
||||
}
|
||||
|
||||
export function decodeTextPortable(codec: string, encodedText: string): string {
|
||||
ensureSupportedCodec(codec)
|
||||
const value = codec.toLowerCase()
|
||||
if (value == 'utf8') {
|
||||
return encodedText
|
||||
}
|
||||
if (value == 'hex') {
|
||||
return CryptoES.enc.Hex.parse(encodedText).toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
if (value == 'base64') {
|
||||
return CryptoES.enc.Base64.parse(encodedText).toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
if (value == 'base64url') {
|
||||
return CryptoES.enc.Base64.parse(fromBase64Url(encodedText)).toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
if (value == 'latin1') {
|
||||
return CryptoES.enc.Latin1.parse(encodedText).toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
return CryptoES.enc.Utf16.parse(encodedText).toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
|
||||
export function digestTextPortable(kind: string, plainText: string): string {
|
||||
const value = ensureDigestKind(kind)
|
||||
if (value == 'md5') {
|
||||
return CryptoES.MD5(plainText).toString()
|
||||
}
|
||||
if (value == 'sha1') {
|
||||
return CryptoES.SHA1(plainText).toString()
|
||||
}
|
||||
if (value == 'sha256') {
|
||||
return CryptoES.SHA256(plainText).toString()
|
||||
}
|
||||
return CryptoES.SHA512(plainText).toString()
|
||||
}
|
||||
|
||||
export function signTextPortable(kind: string, secretText: string, plainText: string): string {
|
||||
const value = ensureMacKind(kind)
|
||||
if (value == 'sha1') {
|
||||
return CryptoES.HmacSHA1(plainText, secretText).toString()
|
||||
}
|
||||
if (value == 'sha256') {
|
||||
return CryptoES.HmacSHA256(plainText, secretText).toString()
|
||||
}
|
||||
return CryptoES.HmacSHA512(plainText, secretText).toString()
|
||||
}
|
||||
|
||||
export function aesEncryptTextPortable(secretText: string, plainText: string, mode: string, padding: string, ivText: string | null, keyLength: number | null): string {
|
||||
const encrypted = CryptoES.AES.encrypt(plainText, fitKeyText(secretText, keyLength), {
|
||||
iv: fitIvText(ivText, 16),
|
||||
mode: ensureAesMode(mode),
|
||||
padding: ensureAesPadding(padding)
|
||||
})
|
||||
return encrypted.toString()
|
||||
}
|
||||
|
||||
export function aesDecryptTextPortable(secretText: string, cipherText: string, mode: string, padding: string, ivText: string | null, keyLength: number | null): string {
|
||||
const decrypted = CryptoES.AES.decrypt(cipherText, fitKeyText(secretText, keyLength), {
|
||||
iv: fitIvText(ivText, 16),
|
||||
mode: ensureAesMode(mode),
|
||||
padding: ensureAesPadding(padding)
|
||||
})
|
||||
return decrypted.toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
|
||||
export function aesEncryptBytesPortable(secretBytes: Uint8Array, plainBytes: Uint8Array, mode: string, padding: string, ivBytes: Uint8Array | null, keyLength: number | null): Uint8Array {
|
||||
const encrypted = CryptoES.AES.encrypt(bytesToWordArray(plainBytes), fitKeyBytes(secretBytes, keyLength), {
|
||||
iv: fitIvBytes(ivBytes, 16),
|
||||
mode: ensureAesMode(mode),
|
||||
padding: ensureAesPadding(padding)
|
||||
})
|
||||
return wordArrayToBytes(encrypted.ciphertext)
|
||||
}
|
||||
|
||||
export function aesDecryptBytesPortable(secretBytes: Uint8Array, cipherBytes: Uint8Array, mode: string, padding: string, ivBytes: Uint8Array | null, keyLength: number | null): Uint8Array {
|
||||
const decrypted = CryptoES.AES.decrypt(wrapCipherBytes(cipherBytes), fitKeyBytes(secretBytes, keyLength), {
|
||||
iv: fitIvBytes(ivBytes, 16),
|
||||
mode: ensureAesMode(mode),
|
||||
padding: ensureAesPadding(padding)
|
||||
})
|
||||
return wordArrayToBytes(decrypted)
|
||||
}
|
||||
|
||||
export function tripleDesEncryptTextPortable(secretText: string, plainText: string, mode: string, ivText: string | null): string {
|
||||
const encrypted = CryptoES.TripleDES.encrypt(plainText, fitKeyText(secretText, 24), {
|
||||
iv: fitIvText(ivText, 8),
|
||||
mode: ensureTripleDesMode(mode),
|
||||
padding: CryptoES.pad.Pkcs7
|
||||
})
|
||||
return encrypted.toString()
|
||||
}
|
||||
|
||||
export function tripleDesDecryptTextPortable(secretText: string, cipherText: string, mode: string, ivText: string | null): string {
|
||||
const decrypted = CryptoES.TripleDES.decrypt(cipherText, fitKeyText(secretText, 24), {
|
||||
iv: fitIvText(ivText, 8),
|
||||
mode: ensureTripleDesMode(mode),
|
||||
padding: CryptoES.pad.Pkcs7
|
||||
})
|
||||
return decrypted.toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
|
||||
export function desEncryptTextPortable(secretText: string, plainText: string, mode: string, padding: string, ivText: string | null): string {
|
||||
const encrypted = CryptoES.DES.encrypt(plainText, fitFixedTextKey(secretText, 8), {
|
||||
iv: fitIvText(ivText, 8),
|
||||
mode: ensureDesMode(mode),
|
||||
padding: ensureAesPadding(padding)
|
||||
})
|
||||
return encrypted.toString()
|
||||
}
|
||||
|
||||
export function desDecryptTextPortable(secretText: string, cipherText: string, mode: string, padding: string, ivText: string | null): string {
|
||||
const decrypted = CryptoES.DES.decrypt(cipherText, fitFixedTextKey(secretText, 8), {
|
||||
iv: fitIvText(ivText, 8),
|
||||
mode: ensureDesMode(mode),
|
||||
padding: ensureAesPadding(padding)
|
||||
})
|
||||
return decrypted.toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
|
||||
export function rc4EncryptTextPortable(secretText: string, plainText: string): string {
|
||||
const encrypted = CryptoES.RC4.encrypt(plainText, CryptoES.enc.Utf8.parse(secretText))
|
||||
return encrypted.ciphertext.toString(CryptoES.enc.Hex)
|
||||
}
|
||||
|
||||
export function rc4DecryptTextPortable(secretText: string, cipherHexText: string): string {
|
||||
const decrypted = CryptoES.RC4.decrypt(wrapCipherBytes(wordArrayToBytes(CryptoES.enc.Hex.parse(cipherHexText))), CryptoES.enc.Utf8.parse(secretText))
|
||||
return decrypted.toString(CryptoES.enc.Utf8)
|
||||
}
|
||||
|
||||
export function createRsaPairPortable(keySize: number): { publicKey: string, privateKey: string } {
|
||||
const engine = new JSEncrypt({ default_key_size: keySize.toString() })
|
||||
engine.getKey()
|
||||
return {
|
||||
publicKey: engine.getPublicKey(),
|
||||
privateKey: engine.getPrivateKey()
|
||||
}
|
||||
}
|
||||
|
||||
export function rsaEncryptTextPortable(publicKey: string, plainText: string, outputKind: string | null): string {
|
||||
const engine = new JSEncrypt()
|
||||
engine.setPublicKey(publicKey)
|
||||
const encrypted = engine.encrypt(plainText)
|
||||
if (encrypted == null || encrypted == false) {
|
||||
throw new Error('RSA加密失败')
|
||||
}
|
||||
return outputKind == 'hex' ? base64ToHex(encrypted as string) : encrypted as string
|
||||
}
|
||||
|
||||
export function rsaDecryptTextPortable(privateKey: string, cipherText: string, outputKind: string | null): string {
|
||||
const engine = new JSEncrypt()
|
||||
engine.setPrivateKey(privateKey)
|
||||
const source = outputKind == 'hex' ? hexToBase64(cipherText) : cipherText
|
||||
const decrypted = engine.decrypt(source)
|
||||
if (decrypted == null || decrypted == false) {
|
||||
throw new Error('RSA解密失败')
|
||||
}
|
||||
return decrypted as string
|
||||
}
|
||||
|
||||
export function bytesToHexPortable(input: Uint8Array): string {
|
||||
return bytesToWordArray(input).toString(CryptoES.enc.Hex)
|
||||
}
|
||||
|
||||
export function utf8ToBytesPortable(input: string): Uint8Array {
|
||||
return textToUtf8Bytes(input)
|
||||
}
|
||||
|
||||
export function bytesToUtf8Portable(input: Uint8Array): string {
|
||||
return utf8BytesToText(input)
|
||||
}
|
||||
Reference in New Issue
Block a user