Files
xiaozhi-user-uniappx/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/native_rsa.ets
T

177 lines
5.9 KiB
Plaintext

import cryptoFramework from '@ohos.security.cryptoFramework'
import util from '@ohos.util'
const UTF8_ENCODER = new util.TextEncoder('utf-8')
const UTF8_DECODER = util.TextDecoder.create('utf-8')
const BASE64_HELPER = new util.Base64Helper()
const PUBLIC_PEM_FORMATS: string[] = ['X509', 'x509', 'SPKI', 'spki', 'PKCS1', 'pkcs1']
const PRIVATE_PEM_FORMATS: string[] = ['PKCS8', 'pkcs8', 'PKCS1', 'pkcs1']
const RSA_GENERATOR_ALGS: string[] = ['RSA']
const RSA_CIPHER_ALGS: string[] = [
'RSA/ECB/PKCS1Padding',
'RSA/None/PKCS1Padding',
'RSA/None/OAEPWithSHA256AndMGF1Padding',
'RSA'
]
export class NativeRsaBundle {
public publicKey: string
public privateKey: string
constructor(publicKey: string = '', privateKey: string = '') {
this.publicKey = publicKey
this.privateKey = privateKey
}
}
export class NativeHarmonyRsaCore {
static createRsaBundle(keySize: number): NativeRsaBundle {
const generator = NativeHarmonyRsaCore.createKeyGenerator(keySize)
const keyPair = generator.generateKeyPairSync()
const publicKey = NativeHarmonyRsaCore.exportPublicPem(keyPair.pubKey)
const privateKey = NativeHarmonyRsaCore.exportPrivatePem(keyPair.priKey)
return new NativeRsaBundle(publicKey, privateKey)
}
static rsaEncrypt(publicKey: string, plainText: string, outputKind: string | null): string {
const keyPair = NativeHarmonyRsaCore.importPemKeyPair(publicKey, null)
const cipher = NativeHarmonyRsaCore.createCipher()
cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null)
const output = cipher.doFinalSync({ data: NativeHarmonyRsaCore.encodeUtf8(plainText) })
return NativeHarmonyRsaCore.encodeCipherOutput(output.data, outputKind)
}
static rsaDecrypt(privateKey: string, cipherText: string, outputKind: string | null): string {
const keyPair = NativeHarmonyRsaCore.importPemKeyPair(null, privateKey)
const cipher = NativeHarmonyRsaCore.createCipher()
cipher.initSync(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null)
const sourceBytes = NativeHarmonyRsaCore.decodeCipherInput(cipherText)
const output = cipher.doFinalSync({ data: sourceBytes })
return NativeHarmonyRsaCore.decodePlainOutput(output.data, outputKind)
}
private static createKeyGenerator(keySize: number): cryptoFramework.AsyKeyGenerator {
const candidates: string[] = [
'RSA' + keySize.toString(),
'RSA|' + keySize.toString(),
'RSA/' + keySize.toString(),
'RSA'
]
let lastError: Error | null = null
for (const algName of candidates) {
try {
return cryptoFramework.createAsyKeyGenerator(algName)
} catch (error) {
lastError = error as Error
}
}
throw lastError ?? new Error('create RSA key generator failed')
}
private static importPemKeyPair(publicKey: string | null, privateKey: string | null): cryptoFramework.KeyPair {
let lastError: Error | null = null
for (const algName of RSA_GENERATOR_ALGS) {
try {
const generator = cryptoFramework.createAsyKeyGenerator(algName)
return generator.convertPemKeySync(publicKey, privateKey)
} catch (error) {
lastError = error as Error
}
}
throw lastError ?? new Error('import RSA PEM failed')
}
private static createCipher(): cryptoFramework.Cipher {
let lastError: Error | null = null
for (const algName of RSA_CIPHER_ALGS) {
try {
return cryptoFramework.createCipher(algName)
} catch (error) {
lastError = error as Error
}
}
throw lastError ?? new Error('create RSA cipher failed')
}
private static exportPublicPem(publicKey: cryptoFramework.PubKey): string {
let lastError: Error | null = null
for (const formatName of PUBLIC_PEM_FORMATS) {
try {
return publicKey.getEncodedPem(formatName)
} catch (error) {
lastError = error as Error
}
}
throw lastError ?? new Error('export public PEM failed')
}
private static exportPrivatePem(privateKey: cryptoFramework.PriKey): string {
let lastError: Error | null = null
for (const formatName of PRIVATE_PEM_FORMATS) {
try {
return privateKey.getEncodedPem(formatName)
} catch (error) {
lastError = error as Error
}
}
throw lastError ?? new Error('export private PEM failed')
}
private static encodeUtf8(input: string): Uint8Array {
return UTF8_ENCODER.encodeInto(input)
}
private static decodeUtf8(input: Uint8Array): string {
return UTF8_DECODER.decode(input)
}
private static encodeCipherOutput(input: Uint8Array, outputKind: string | null): string {
if (outputKind === 'hex') {
return NativeHarmonyRsaCore.bytesToHex(input)
}
return BASE64_HELPER.encodeToStringSync(input)
}
private static decodePlainOutput(input: Uint8Array, outputKind: string | null): string {
if (outputKind === 'hex') {
return NativeHarmonyRsaCore.bytesToHex(input)
}
return NativeHarmonyRsaCore.decodeUtf8(input)
}
private static decodeCipherInput(cipherText: string): Uint8Array {
const normalized = cipherText.trim()
if (NativeHarmonyRsaCore.looksLikeHex(normalized)) {
return NativeHarmonyRsaCore.hexToBytes(normalized)
}
return BASE64_HELPER.decodeSync(normalized)
}
private static looksLikeHex(input: string): boolean {
return input.length > 0 && input.length % 2 == 0 && /^[0-9a-fA-F]+$/.test(input)
}
private static bytesToHex(input: Uint8Array): string {
let output = ''
for (let i = 0; i < input.length; i++) {
const item = input[i]
if (item < 16) {
output += '0'
}
output += item.toString(16)
}
return output
}
private static hexToBytes(input: string): Uint8Array {
const length = input.length / 2
const output = new Uint8Array(length)
for (let i = 0; i < length; i++) {
const offset = i * 2
output[i] = Number.parseInt(input.substring(offset, offset + 2), 16)
}
return output
}
}