鸿蒙系统开发【加解密算法库框架】安全
加解密算法库框架
介绍
本示例使用@ohos.security.cryptoFramework相关接口实现了对文本文件的加解密、签名验签操作。
实现场景如下:
1)软件需要加密存储本地文本文件,需要调用加解密算法库框架选择密钥文本文件,对本地文本文件进行加密,其中密钥文本文件可由加解密算法库生成。
2)软件需要解密存储本地文本文件,需要调用加解密算法库框架选择密钥文本文件,对本地文本文件进行解密,其中密钥文本文件可由加解密算法库生成。
3)软件需要对存储本地文本文件签名,调用加解密算法库框架选择密钥文本文件,对本地文本文件进行完整性签名,其中密钥文本文件可由加解密算法库生成。
4)软件需要验证存储本地文本文件的签名完整性,需要调用加解密算法库框架选择密钥文本文件与签名文件,对文件进行验签,其中密钥文本文件可由加解密算法库生成。
效果预览

使用说明
1.点击主页面tab栏的加密,在加密界面点击打开文件,通过文件选择器选择文本文件,选择完毕自动返回加密界面, 其内容显示在文件内容文本框中, 点击选择密钥,选择密钥文件,如果没有密钥文件,可以通过在加密界面点击随机生成AES密钥,生成并通过文件选择器保存密钥文件。 选择完文本文件和密钥文件后,点击加密按钮,完成加密,并通过文件选择器保存密文文件。 下方加密内容文本框中显示加密后的消息内容。
2.点击主页面tab栏的解密,在解密界面点击打开文件,通过文件选择器选择文本文件,选择完毕自动返回解密界面, 其内容显示在文件内容文本框中, 点击选择密钥,选择和加密相同的密钥文件。 选择完文本文件和密钥文件后,点击解密按钮,完成解密,并通过文件选择器保存明文文件。 下方解密内容文本框中显示解密后的消息内容。
3.点击主页面tab栏的签名,在签名界面点击打开文件,通过文件选择器选择文本文件,选择完毕自动返回签名界面, 其内容显示在文件内容文本框中, 点击选择密钥,选择密钥文件,如果没有密钥文件,可以通过在签名界面点击随机生成RSA密钥,生成并通过文件选择器保存密钥文件,注意RSA密钥生成耗时较长。 选择完文本文件和密钥文件后,点击签名按钮,完成完整性签名,并通过文件选择器保存签名文件。
4.点击主页面tab栏的验签,在验签界面点击打开文件,通过文件选择器选择文本文件,选择完毕自动返回验签界面, 其内容显示在文件内容文本框中, 点击选择密钥,选择和签名一致的密钥文件。点击选择签名文件,通过文件选择器选择签名时保存的签名文件, 选择完文本文件、密钥文件和签名文件后,点击验签按钮,完成验签。
具体实现
- 进行对文本文件进行加解密、签名验签的功能接口封装在CryptoOperation中,源码参考:[CryptoOperation.ts]
/** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import Logger from '../util/Logger';const TAG: string = '[Crypto_Framework]';
const BASE_16: number = 16;
const SLICE_NUMBER: number = -2;// 字节流以16进制字符串输出
function uint8ArrayToShowStr(uint8Array: Uint8Array): string {let ret: string = Array.prototype.map.call(uint8Array, (x) => ('00' + x.toString(BASE_16)).slice(SLICE_NUMBER)).join('');return ret;
}// 16进制字符串转字节流
function fromHexString(hexString: string): Uint8Array {let ret: Uint8Array = new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, BASE_16)));return ret;
}// 字节流转字符串
function arrayBufferToString(buffer: ArrayBuffer): string {let ret: string = String.fromCharCode.apply(null, new Uint8Array(buffer));return ret;
}// 可理解的字符串转成字节流
function stringToUint8Array(str: string): Uint8Array {let arr = [];for (let i = 0, j = str.length; i < j; ++i) {arr.push(str.charCodeAt(i));}let ret: Uint8Array = new Uint8Array(arr);return ret;
}function genGcmParamsSpec(): cryptoFramework.GcmParamsSpec {let arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 12 byteslet dataIv = new Uint8Array(arr);let ivBlob = { data: dataIv };arr = [0, 0, 0, 0, 0, 0, 0, 0]; // 8 byteslet dataAad = new Uint8Array(arr);let aadBlob = { data: dataAad };arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 16 byteslet dataTag = new Uint8Array(arr);let tagBlob = { data: dataTag }; // GCM的authTag在加密时从doFinal结果中获取,在解密时填入init函数的params参数中let gcmParamsSpec = { iv: ivBlob, aad: aadBlob, authTag: tagBlob, algName: 'GcmParamsSpec' };return gcmParamsSpec;
}export class CryptoOperation {async generateAesKey(): Promise<string> {let symKeyGenerator;let encodedKey;// 创建对称密钥生成器try {symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');} catch (error) {Logger.error(TAG, 'create generator failed');return null;}// 通过密钥生成器随机生成对称密钥try {let symKey = await symKeyGenerator.generateSymKey();// 获取对称密钥的二进制数据,输出长度为256bit的字节流encodedKey = symKey.getEncoded();let data: Uint8Array = encodedKey.data;Logger.info('success, key bytes: ' + data);Logger.info('success, key hex:' + uint8ArrayToShowStr(data));// 将二进制数据转为16进制string。return uint8ArrayToShowStr(data);} catch (error) {Logger.error(TAG, 'create symKey failed');return null;}}async convertAesKey(aesKeyBlobString: string): Promise<cryptoFramework.SymKey> {let symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES256');Logger.info(TAG, 'success, read key string' + aesKeyBlobString);Logger.info(TAG, 'success, blob key ' + fromHexString(aesKeyBlobString));let symKeyBlob = { data: fromHexString(aesKeyBlobString) };try {let key = await symKeyGenerator.convertKey(symKeyBlob);let aesKey: cryptoFramework.SymKey = key;return aesKey;} catch (error) {Logger.error(TAG, `convert aes key failed, ${error.code}, ${error.message}`);return null;}}async aesGcmEncrypt(globalKey, textString: string): Promise<string> {let cipherAlgName = 'AES256|GCM|PKCS7';let cipher;let cipherText: string;let globalGcmParams = genGcmParamsSpec();let aesEncryptJsonStr = null;try {cipher = cryptoFramework.createCipher(cipherAlgName);Logger.info(TAG, `cipher algName: ${cipher.algName}`);} catch (error) {Logger.error(TAG, `createCipher failed, ${error.code}, ${error.message}`);return aesEncryptJsonStr;}let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE;try {await cipher.init(mode, globalKey, globalGcmParams);} catch (error) {Logger.error(TAG, `init cipher failed, ${error.code}, ${error.message}`);return aesEncryptJsonStr;}let plainText = { data: stringToUint8Array(textString) };Logger.info(TAG, `plain text: ${plainText.data}`);try {let cipherTextBlob = await cipher.update(plainText);let tmpArr: Uint8Array = cipherTextBlob.data;cipherText = uint8ArrayToShowStr(tmpArr);Logger.info(TAG, `cipher text: ${cipherText}`);} catch (error) {Logger.error(TAG, `update cipher failed, ${error.code}, ${error.message}`);return aesEncryptJsonStr;}try {let authTag = await cipher.doFinal(null);let tmoTagArr: Uint8Array = authTag.data;let aesEncryptJson = ({ aesGcmTag: uint8ArrayToShowStr(tmoTagArr), encryptedText: cipherText });aesEncryptJsonStr = JSON.stringify(aesEncryptJson);Logger.info(TAG, `success, authTag blob ${authTag.data}`);Logger.info(TAG, `success, authTag blob.length = ${authTag.data.length}`);return aesEncryptJsonStr;} catch (error) {Logger.error(TAG, `doFinal cipher failed, ${error.code}, ${error.message}`);return aesEncryptJsonStr;}}async aesGcmDecrypt(globalKey, aesEncryptJsonStr: string): Promise<string> {let cipherAlgName = 'AES256|GCM|PKCS7';let decode;let plainTextBlob;let plainText: string;let aesEncryptJson;try {aesEncryptJson = JSON.parse(aesEncryptJsonStr);} catch (error) {Logger.error(TAG, `trans from json string failed, ${error.code}, ${error.message}`);return null;}let authTagStr: string = aesEncryptJson.aesGcmTag;let textString: string = aesEncryptJson.encryptedText;let globalGcmParams = genGcmParamsSpec();globalGcmParams.authTag = { data: fromHexString(authTagStr) };Logger.info(TAG, 'success, decrypt authTag string' + authTagStr);Logger.info(TAG, 'success, decrypt authTag blob' + globalGcmParams.authTag.data);Logger.info(TAG, 'success, decrypt authTag blob.length = ' + globalGcmParams.authTag.data.length);try {decode = cryptoFramework.createCipher(cipherAlgName);} catch (error) {Logger.error(TAG, `createCipher failed, ${error.code}, ${error.message}`);return null;}let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;try {await decode.init(mode, globalKey, globalGcmParams);} catch (error) {Logger.error(TAG, `init decode failed, ${error.code}, ${error.message}`);return null;}let cipherText = { data: fromHexString(textString) };Logger.info(TAG, `success, cipher text: ${cipherText.data}`);try {plainTextBlob = await decode.update(cipherText);let tmpArr: Uint8Array = plainTextBlob.data;plainText = arrayBufferToString(tmpArr);Logger.info(TAG, `success, plain text: ${plainText}`);} catch (error) {Logger.error(TAG, `update decode failed, ${error.code}, ${error.message}`);return null;}try {let finalOut = await decode.doFinal(null);} catch (error) {Logger.error(TAG, `doFinal decode failed, ${error.code}, ${error.message}`);return null;}return plainText;}async aesConvertAndEncrypt(aesKeyBlobString: string, textString: string): Promise<string> {let aesEncryptJsonStr = '';try {let key = await this.convertAesKey(aesKeyBlobString);try {aesEncryptJsonStr = await this.aesGcmEncrypt(key, textString);} catch (error) {Logger.error(TAG, `encrypt error, ${error.code}, ${error.message}`);}} catch (error) {Logger.error(TAG, `convert key error, ${error.code}, ${error.message}`);return null;}return aesEncryptJsonStr;}async aesConvertAndDecrypt(aesKeyBlobString: string, textString: string): Promise<string> {let plainText = '';try {let key = await this.convertAesKey(aesKeyBlobString);try {plainText = await this.aesGcmDecrypt(key, textString);} catch (error) {Logger.error(TAG, `encrypt error, ${error.code}, ${error.message}`);}} catch (error) {Logger.error(TAG, `convert key error, ${error.code}, ${error.message}`);return null;}return plainText;}async generateRsaKey(): Promise<string> {// 创建非对称密钥生成器let rsaKeyGenerator;let jsonStr;// 创建对称密钥生成器try {rsaKeyGenerator = cryptoFramework.createAsyKeyGenerator('RSA3072');} catch (error) {Logger.error(TAG, 'create generator failed');return null;}// 通过密钥生成器随机生成非对称密钥try {// 通过密钥生成器随机生成非对称密钥let keyPair = await rsaKeyGenerator.generateKeyPair();// 获取非对称密钥的二进制数据let encodedPriKey = keyPair.priKey.getEncoded();let priKeyData: Uint8Array = encodedPriKey.data;let encodedPubKey = keyPair.pubKey.getEncoded();let pubKeyData: Uint8Array = encodedPubKey.data;let rsaKeyJson = ({ priKey: uint8ArrayToShowStr(priKeyData), pubKey: uint8ArrayToShowStr(pubKeyData) });jsonStr = JSON.stringify(rsaKeyJson);Logger.info(TAG, 'success, key string: ' + jsonStr.length);return jsonStr;} catch (error) {Logger.error(TAG, 'create symKey failed');return null;}}async convertRsaKey(rsaJsonString: string): Promise<cryptoFramework.KeyPair> {let rsaKeyGenerator = cryptoFramework.createAsyKeyGenerator('RSA3072');Logger.info(TAG, 'success, read key string' + rsaJsonString.length);let jsonRsaKeyBlob;try {jsonRsaKeyBlob = JSON.parse(rsaJsonString);} catch (error) {Logger.error(TAG, `trans from json string failed, ${error.code}, ${error.message}`);return null;}let priKeyStr: string = jsonRsaKeyBlob.priKey;let pubKeyStr: string = jsonRsaKeyBlob.pubKey;Logger.info(TAG, 'success, read rsa pri str ' + priKeyStr.length);Logger.info(TAG, 'success, read rsa pub str ' + pubKeyStr.length);let priKeyBlob = fromHexString(priKeyStr);let pubKeyBlob = fromHexString(pubKeyStr);Logger.info(TAG, 'success, read rsa pri blob key ' + priKeyBlob.length);Logger.info(TAG, 'success, read rsa pub blob key ' + pubKeyBlob.length);try {let key: cryptoFramework.KeyPair = await rsaKeyGenerator.convertKey({ data: pubKeyBlob }, { data: priKeyBlob });return key;Logger.info(TAG, 'success, read and convert key');} catch (error) {Logger.error(TAG, `convert rsa key failed, ${error.code}, ${error.message}`);return null;}}async rsaSign(globalKey, textString: string): Promise<string> {let signer = cryptoFramework.createSign('RSA3072|PKCS1|SHA256');let keyPair = globalKey;try {await signer.init(keyPair.priKey);let signBlob = stringToUint8Array(textString);try {let signedBlob = await signer.sign({ data: signBlob });let tmpArr: Uint8Array = signedBlob.data;Logger.info(TAG, 'success,RSA sign output is' + signedBlob.data.length);let rsaSignedBlobString = uint8ArrayToShowStr(tmpArr);Logger.info(TAG, 'success,RSA sign string is' + rsaSignedBlobString);return rsaSignedBlobString;} catch (error1) {Logger.error(TAG, `sign text failed, ${error1.code}, ${error1.message}`);return null;}} catch (error) {Logger.error(TAG, `sign init failed, ${error.code}, ${error.message}`);return null;}}async rsaVerify(globalKey, textString: string, rsaSignedText: string): Promise<Boolean> {let verifyer = cryptoFramework.createVerify('RSA3072|PKCS1|SHA256');let keyPair = globalKey;let signBlob = stringToUint8Array(textString);let signedBlob = fromHexString(rsaSignedText);Logger.info('success,RSA sign input is ' + signBlob);Logger.info('success,RSA signed file length ' + signedBlob.length);try {await verifyer.init(keyPair.pubKey);try {let result: Boolean = await verifyer.verify({ data: signBlob }, { data: signedBlob });if (result === false) {// flag = false;Logger.error(TAG, 'RSA Verify result = fail');} else {Logger.info(TAG, 'success, RSA Verify result = success');}return result;} catch (error) {Logger.error(TAG, `verify dofinal failed, ${error.code}, ${error.message}`);}} catch (err) {Logger.error(TAG, `verify init failed, ${err.code}, ${err.message}`);}return null;}async rsaConvertAndSign(rsaJsonString: string, textString: string): Promise<string> {let rsaSignString;try {let key = await this.convertRsaKey(rsaJsonString);try {rsaSignString = await this.rsaSign(key, textString);} catch (error) {Logger.error(TAG, `sign error, ${error.code}, ${error.message}`);return null;}} catch (error) {Logger.error(TAG, `convert rsa key error, ${error.code}, ${error.message}`);return null;}return rsaSignString;}async rsaConvertAndVerify(rsaJsonString: string, textString: string, rsaSignedText: string): Promise<Boolean> {let rsaVerifyRes;try {let key = await this.convertRsaKey(rsaJsonString);try {rsaVerifyRes = await this.rsaVerify(key, textString, rsaSignedText);} catch (error) {Logger.error(TAG, `sign error, ${error.code}, ${error.message}`);return null;}} catch (error) {Logger.error(TAG, `convert rsa key error, ${error.code}, ${error.message}`);return null;}return rsaVerifyRes;}
}
- 对文本文件加密:在[Encrypt.ets](文件中依次点击打开文件、选择密钥,通过filePicker选择明文文本文件和密钥文件,点击加密按钮,调用加密函数实现对文本内容进行加密,并将密文文件通过filePicker保存。 需要生成密钥文本文件时,可以点击随机生成AES密钥,通过调用cryptoFramework.symKeyGenerator生成用于加密的AES密钥,并通过filePicker保存密钥文本文件。 对消息加密的过程中采用cryptoFramework.Cipher完成加密操作。
/** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import { promptAction } from '@kit.ArkUI';
import Logger from '../util/Logger';
import { picker } from '@kit.CoreFileKit';
import { CryptoOperation } from '../cryptoframework/CryptoOperation';
import TextFileManager from '../textfilemanager/TextFileManager';const TAG: string = '[Crypto_Framework]';@Component
export struct Encrypt {@State keyFileName: string = '';@State keyFileUri: string = '';@State textFileUri: string = '';@State textFileName: string = '';@State keyString: string = '';@State cipherText: string = '';@State plainText: string = '';@State message: string = '';@State createKeyUri: string = '';@State encryptedFileUri: string = '';private CryptoOperation: CryptoOperation = new CryptoOperation();build() {Stack({ alignContent: Alignment.Center }) {Column() {GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {List() {ListItem() {Row() {Text($r('app.string.open_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.textFileName === '' ? $r('app.string.please_choose') : this.textFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('52vp').padding({ top: 4, left: 12, right: 12 })}.onClick(() => {this.selectTextFileAndRead();})ListItem() {Row() {Text($r('app.string.select_key_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.keyFileName === '' ? $r('app.string.please_choose') : this.keyFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('48vp').padding({ left: 12, right: 12 })}.onClick(() => {this.selectAesKeyFileAndRead();})}.width('100%').height('100%').borderRadius(16)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Column() {Row() {Text($r('app.string.text_context')).fontSize(16).textAlign(TextAlign.Start).fontWeight(500).lineHeight(22)}.padding({ left: 12, right: 12 }).width('100%').height('48vp')Row() {Text() {Span(this.plainText).fontSize(16).fontWeight(400).fontColor('#182431')}.textAlign(TextAlign.Start)}.padding({ left: 12, right: 12, bottom: 4 }).width('100%').height('52vp')}.borderRadius(16).width('100%').height('100').backgroundColor(0xFFFFFF)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Column() {Row() {Text($r('app.string.encrypted_context')).fontSize(16).textAlign(TextAlign.Start).fontWeight(500).lineHeight(22)}.padding({ left: 12, right: 12 }).width('100%').height('48vp')Row() {Text() {Span(this.cipherText).fontSize(16).fontWeight(400).fontColor('#182431')}.textAlign(TextAlign.Start)}.padding({ left: 12, right: 12, bottom: 4 }).width('100%').height('80vp')}.borderRadius(16).width('100%').height('100').backgroundColor(0xFFFFFF)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })Column() {GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Column() {Button() {Text($r('app.string.generate_aes_key_randomly')).fontSize(16).fontWeight(500).lineHeight(22).fontColor('#FFFFFF')}.id('encryptAesGenKey').borderRadius(20).type(ButtonType.Capsule).width('100%').height('40vp').margin({ bottom: 16 }).backgroundColor('#007DFF').onClick(() => {this.genAesKey();});Button() {Text($r('app.string.encrypt')).fontSize(16).fontWeight(500).lineHeight(22).fontColor('#FFFFFF')}.borderRadius(20).id('encryptionBtn').type(ButtonType.Capsule).margin({ left: 24, right: 24 }).width('100%').height('40vp').backgroundColor('#007DFF').onClick(() => {if (this.textFileUri === '' || this.keyFileUri === '') {promptAction.showToast({message: $r('app.string.null_message')});} else {this.encryptFunc();}});}}}.margin({ left: 24, right: 24 })}.width('100%').height('296vp').justifyContent(FlexAlign.End)}.width('100%').height('100%')}}async selectAesKeyFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})this.keyFileUri = uri;await TextFileManager.readTextFile(this.keyFileUri);this.keyFileName = TextFileManager.getName();this.keyString = TextFileManager.getString();}async selectTextFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})this.textFileUri = uri;await TextFileManager.readTextFile(this.textFileUri);this.textFileName = TextFileManager.getName();this.plainText = TextFileManager.getString();}async createTextFileAndWrite() {let documentSaveOptions = new picker.DocumentSaveOptions();documentSaveOptions.newFileNames = ['cipherText.txt'];let documentPicker = new picker.DocumentViewPicker();let documentSaveResult = await documentPicker.save(documentSaveOptions);this.encryptedFileUri = documentSaveResult[0];await TextFileManager.writeTextFile(this.encryptedFileUri, this.cipherText);}async createKeyFileAndWrite() {let documentSaveOptions = new picker.DocumentSaveOptions();documentSaveOptions.newFileNames = ['aesKey.txt'];let documentPicker = new picker.DocumentViewPicker();let documentSaveResult = await documentPicker.save(documentSaveOptions);this.createKeyUri = documentSaveResult[0];await TextFileManager.writeTextFile(this.createKeyUri, this.keyString);}async encryptFunc() {if (this.plainText === '' || this.keyFileUri === '') {promptAction.showToast({message: $r('app.string.null_message')});return;}try {this.cipherText = await this.CryptoOperation.aesConvertAndEncrypt(this.keyString, this.plainText);} catch (error) {Logger.error(TAG, `encrypt failed, ${error}`);promptAction.showToast({message: $r('app.string.encrypt_fail')});}if (this.cipherText === '' || this.cipherText === undefined || this.cipherText === null) {promptAction.showToast({message: $r('app.string.encrypt_fail')});return;} else {try {await this.createTextFileAndWrite();} catch (error) {Logger.error(TAG, `encrypt failed, ${error}`);}}if (this.encryptedFileUri === '' || typeof (this.encryptedFileUri) == 'undefined') {promptAction.showToast({message: $r('app.string.encrypt_fail')});} else {promptAction.showToast({message: $r('app.string.encrypt_success')});}}async genAesKey() {try {this.keyString = await this.CryptoOperation.generateAesKey();} catch (error) {Logger.error(TAG, `gen aes key failed, ${error}`);}if (this.keyString === '' || typeof (this.keyString) == 'undefined') {promptAction.showToast({message: $r('app.string.gen_key_fail')});return;} else {try {await this.createKeyFileAndWrite();} catch (error) {Logger.error(TAG, `write aes key failed, ${error}`);}}if (this.createKeyUri === '' || typeof (this.createKeyUri) == 'undefined') {promptAction.showToast({message: $r('app.string.gen_key_fail')});} else {promptAction.showToast({message: $r('app.string.gen_key_success')});}}
}
- 对文本文件解密:在[Decrypt.ets] 文件中依次点击打开文件、选择密钥,通过filePicker选择密文文本文件和密钥文件,点击解密按钮,调用解密函数实现对文本内容进行解密,并将明文文件通过filePicker保存。 对消息解密的过程中采用cryptoFramework.Cipher完成解密操作。
/** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import { promptAction } from '@kit.ArkUI';
import Logger from '../util/Logger';
import { picker } from '@kit.CoreFileKit';
import { CryptoOperation } from '../cryptoframework/CryptoOperation';
import TextFileManager from '../textfilemanager/TextFileManager';const TAG: string = '[Crypto_Framework]';@Component
export struct Decrypt {@State keyFileName: string = '';@State keyFileUri: string = '';@State textFileUri: string = '';@State textFileName: string = '';@State keyString: string = '';@State cipherText: string = '';@State plainText: string = '';@State message: string = '';@State decryptedFileUri: string = '';private CryptoOperation: CryptoOperation = new CryptoOperation();build() {Stack({ alignContent: Alignment.Center }) {Column() {GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {List() {ListItem() {Row() {Text($r('app.string.open_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.textFileName === '' ? $r('app.string.please_choose') : this.textFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('52vp').padding({ top: 4, left: 12, right: 12 })}.onClick(() => {this.selectTextFileAndRead();})ListItem() {Row() {Text($r('app.string.select_key_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.keyFileName === '' ? $r('app.string.please_choose') : this.keyFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('48vp').padding({ left: 12, right: 12 })}.onClick(() => {this.selectAesKeyFileAndRead();})}.width('100%').height('100%').borderRadius(16)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Column() {Row() {Text($r('app.string.text_context')).fontSize(16).textAlign(TextAlign.Start).fontWeight(500).lineHeight(22)}.padding({ left: 12, right: 12 }).width('100%').height('48vp')Row() {Text() {Span(this.cipherText).fontSize(16).fontWeight(400).fontColor('#182431')}.textAlign(TextAlign.Start)}.padding({ left: 12, right: 12, bottom: 4 }).width('100%').height('52vp')}.borderRadius(16).width('100%').height('100').backgroundColor(0xFFFFFF)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Column() {Row() {Text($r('app.string.decrypted_context')).fontSize(16).textAlign(TextAlign.Start).fontWeight(500).lineHeight(22)}.padding({ left: 12, right: 12 }).width('100%').height('48vp')Row() {Text() {Span(this.plainText).fontSize(16).fontWeight(400).fontColor('#182431')}.textAlign(TextAlign.Start)}.padding({ left: 12, right: 12, bottom: 4 }).width('100%').height('52vp')}.borderRadius(16).width('100%').height('100').backgroundColor(0xFFFFFF)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })Column() {GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Column() {Button() {Text($r('app.string.decrypt')).fontSize(16).fontWeight(500).lineHeight(22).fontColor('#FFFFFF')}.borderRadius(20).id('decryptionBtn').type(ButtonType.Capsule).margin({ left: 24, right: 24 }).width('100%').height('40vp').backgroundColor('#007DFF').onClick(() => {if (this.textFileUri === '' || this.keyFileUri === '') {promptAction.showToast({message: $r('app.string.null_message')});} else {this.decryptFunc();}});}}}.margin({ left: 24, right: 24 })}.width('100%').height('296vp').justifyContent(FlexAlign.End)}.width('100%').height('100%')}}async selectAesKeyFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})this.keyFileUri = uri;await TextFileManager.readTextFile(this.keyFileUri);this.keyFileName = TextFileManager.getName();this.keyString = TextFileManager.getString();}async selectTextFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})this.textFileUri = uri;await TextFileManager.readTextFile(this.textFileUri);this.textFileName = TextFileManager.getName();this.cipherText = TextFileManager.getString();}async createTextFileAndWrite() {let documentSaveOptions = new picker.DocumentSaveOptions();documentSaveOptions.newFileNames = ['plainText.txt'];let documentPicker = new picker.DocumentViewPicker();let documentSaveResult = await documentPicker.save(documentSaveOptions);this.decryptedFileUri = documentSaveResult[0];await TextFileManager.writeTextFile(this.decryptedFileUri, this.plainText);}async decryptFunc() {if (this.cipherText === '' || this.keyFileUri === '') {promptAction.showToast({message: $r('app.string.null_message')});return;}try {this.plainText = await this.CryptoOperation.aesConvertAndDecrypt(this.keyString, this.cipherText);} catch (error) {Logger.error(TAG, `decrypt failed, ${error}`);promptAction.showToast({message: $r('app.string.decrypt_fail')});return;}if (this.plainText === '' || this.plainText === null || this.plainText === undefined) {promptAction.showToast({message: $r('app.string.decrypt_fail')});return;} else {try {await this.createTextFileAndWrite();} catch (error) {Logger.error(TAG, `decrypt failed, ${error}`);}}if (this.decryptedFileUri === '' || typeof (this.decryptedFileUri) == 'undefined') {promptAction.showToast({message: $r('app.string.decrypt_fail')});} else {promptAction.showToast({message: $r('app.string.decrypt_success')});}}
}
- 对文本文件签名:在[Sign.ets] 文件中依次点击打开文件、选择密钥,通过filePicker选择待签名文本文件和密钥文件,点击签名按钮,调用签名函数实现对文本内容进行加密,并将签名文件通过filePicker保存。 需要生成密钥文本文件时,可以点击随机生成RSA密钥,通过调用cryptoFramework.asyKeyGenerator生成用于签名的RSA密钥,并通过filePicker保存密钥文本文件。 对消息签名的过程中采用cryptoFramework.Sign完成加密操作。
/** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import { promptAction } from '@kit.ArkUI';
import Logger from '../util/Logger';
import { picker } from '@kit.CoreFileKit';
import { CryptoOperation } from '../cryptoframework/CryptoOperation';
import TextFileManager from '../textfilemanager/TextFileManager';const TAG: string = '[Crypto_Framework]';@Component
export struct Sign {@State keyFileName: string = '';@State keyFileUri: string = '';@State textFileUri: string = '';@State textFileName: string = '';@State keyString: string = '';@State cipherText: string = '';@State plainText: string = '';@State message: string = '';@State signFileUri: string = '';@State createKeyUri: string = '';private CryptoOperation: CryptoOperation = new CryptoOperation();build() {Stack({ alignContent: Alignment.Center }) {Column() {GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {List() {ListItem() {Row() {Text($r('app.string.open_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.textFileName === '' ? $r('app.string.please_choose') : this.textFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('52vp').padding({ top: 4, left: 12, right: 12 })}.onClick(() => {this.selectTextFileAndRead();})ListItem() {Row() {Text($r('app.string.select_key_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.keyFileName === '' ? $r('app.string.please_choose') : this.keyFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('48vp').padding({ left: 12, right: 12 })}.onClick(() => {this.selectRsaKeyFileAndRead();})}.width('100%').height('100%').borderRadius(16)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Column() {Row() {Text($r('app.string.text_context')).fontSize(16).textAlign(TextAlign.Start).fontWeight(500).lineHeight(22)}.padding({ left: 12, right: 12 }).width('100%').height('48vp')Row() {Text() {Span(this.plainText).fontSize(16).fontWeight(400).fontColor('#182431')}.textAlign(TextAlign.Start)}.padding({ left: 12, right: 12, bottom: 4 }).width('100%').height('52vp')}.borderRadius(16).width('100%').height('100').backgroundColor(0xFFFFFF)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })Column() {GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Column() {Button() {Text($r('app.string.generate_rsa_key_randomly')).fontSize(16).fontWeight(500).lineHeight(22).fontColor('#FFFFFF')}.id('encryptRsaGenKey').borderRadius(20).type(ButtonType.Capsule).width('100%').height('40vp').margin({ bottom: 16 }).backgroundColor('#007DFF').onClick(() => {this.genRsaKey();});Button() {Text($r('app.string.sign')).fontSize(16).fontWeight(500).lineHeight(22).fontColor('#FFFFFF')}.borderRadius(20).id('signBtn').type(ButtonType.Capsule).margin({ left: 24, right: 24 }).width('100%').height('40vp').backgroundColor('#007DFF').onClick(() => {if (this.textFileUri === '' || this.keyFileUri === '') {promptAction.showToast({message: $r('app.string.null_message')});} else {this.signFunc();}});}}}.margin({ left: 24, right: 24 })}.width('100%').height('412vp').justifyContent(FlexAlign.End)}.width('100%').height('100%')}}async selectRsaKeyFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})this.keyFileUri = uri;// 获取到密钥文档文件的文件名称await TextFileManager.readTextFile(this.keyFileUri);this.keyFileName = TextFileManager.getName();this.keyString = TextFileManager.getString();}async selectTextFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})// 获取到文档文件的URIthis.textFileUri = uri;// 获取到文档文件的文件名称await TextFileManager.readTextFile(this.textFileUri);this.textFileName = TextFileManager.getName();this.plainText = TextFileManager.getString();}async createTextFileAndWrite() {let documentSaveOptions = new picker.DocumentSaveOptions();documentSaveOptions.newFileNames = ['signText.txt'];let documentPicker = new picker.DocumentViewPicker();let documentSaveResult = await documentPicker.save(documentSaveOptions);this.signFileUri = documentSaveResult[0];await TextFileManager.writeTextFile(this.signFileUri, this.cipherText);}async createKeyFileAndWrite() {let documentSaveOptions = new picker.DocumentSaveOptions();documentSaveOptions.newFileNames = ['rsaKey.txt'];let documentPicker = new picker.DocumentViewPicker();try {let documentSaveResult = await documentPicker.save(documentSaveOptions);this.createKeyUri = documentSaveResult[0];await TextFileManager.writeTextFile(this.createKeyUri, this.keyString);} catch (error) {Logger.error(TAG, `save key failed, ${error}`);}}async signFunc() {if (this.plainText === '' || this.keyFileUri === '') {promptAction.showToast({message: $r('app.string.null_message')});return;}try {this.cipherText = await this.CryptoOperation.rsaConvertAndSign(this.keyString, this.plainText);} catch (error) {promptAction.showToast({message: $r('app.string.sign_fail')});Logger.error(TAG, `sign failed, ${error}`);}if (this.cipherText === '' || this.cipherText === null || this.cipherText === undefined) {promptAction.showToast({message: $r('app.string.sign_fail')});return;} else {await this.createTextFileAndWrite();}if (this.signFileUri === '' || typeof (this.signFileUri) == 'undefined') {promptAction.showToast({message: $r('app.string.sign_fail')});} else {promptAction.showToast({message: $r('app.string.sign_success')});}}async genRsaKey() {promptAction.showToast({message: $r('app.string.slow_rsa_key_gen')});try {this.keyString = await this.CryptoOperation.generateRsaKey();} catch (error) {Logger.error(TAG, `gen rsa key failed, ${error}`);}if (this.keyString === '' || typeof (this.keyString) == 'undefined') {promptAction.showToast({message: $r('app.string.gen_key_fail')});return;} else {try {await this.createKeyFileAndWrite();} catch (error) {Logger.error(TAG, `write rsa key failed, ${error}`);}}if (this.createKeyUri === '' || typeof (this.createKeyUri) == 'undefined') {promptAction.showToast({message: $r('app.string.gen_key_fail')});} else {promptAction.showToast({message: $r('app.string.gen_key_success')});}}
}
- 对文本文件验签:在[Verify.ets]文件中依次点击打开文件、选择密钥、选择签名文件,通过filePicker选择密文文本文件、密钥文件和签名文件,点击验签按钮,调用验签函数实现对文本内容进行验签,并显示验签结果。 对消息验签的过程中采用cryptoFramework.Verify完成验签操作。
/** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import { promptAction } from '@kit.ArkUI';
import Logger from '../util/Logger';
import { picker } from '@kit.CoreFileKit';
import { CryptoOperation } from '../cryptoframework/CryptoOperation';
import TextFileManager from '../textfilemanager/TextFileManager';const TAG: string = '[Crypto_Framework]';@Component
export struct Verify {@State keyFileName: string = '';@State keyFileUri: string = '';@State textFileUri: string = '';@State textFileName: string = '';@State keyString: string = '';@State plainText: string = '';@State message: string = '';@State signFileUri: string = '';@State signFileName: string = '';@State signText: string = '';@State createKeyUri: string = '';private CryptoOperation: CryptoOperation = new CryptoOperation();build() {Stack({ alignContent: Alignment.Center }) {Column() {GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {List() {ListItem() {Row() {Text($r('app.string.open_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.textFileName === '' ? $r('app.string.please_choose') : this.textFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('52vp').padding({ top: 4, left: 12, right: 12 })}.onClick(() => {this.selectTextFileAndRead();})ListItem() {Row() {Text($r('app.string.select_key_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.keyFileName === '' ? $r('app.string.please_choose') : this.keyFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('48vp').padding({ left: 12, right: 12 })}.onClick(() => {this.selectRsaKeyFileAndRead();})}.width('100%').height('100%').borderRadius(16)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {List() {ListItem() {Row() {Text($r('app.string.select_signature_file')).fontSize(16).textAlign(TextAlign.Start).lineHeight(22)Blank()Text(this.signFileName === '' ? $r('app.string.please_choose') : this.signFileName).fontSize(14).textAlign(TextAlign.Start).lineHeight(19)Image($r('app.media.right_arrow')).height('19vp').width('10vp').margin({ left: 9, right: 9, top: 6, bottom: 6 })}.backgroundColor(0xFFFFFF).width('100%').height('56vp').padding({ left: 12, right: 12, top: 4, bottom: 4 })}.onClick(() => {this.selectSignFileAndRead();})}.width('100%').borderRadius(16)}}}.height('56vp').margin({ left: 12, right: 12, bottom: 12 })GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Column() {Row() {Text($r('app.string.text_context')).fontSize(16).textAlign(TextAlign.Start).fontWeight(500).lineHeight(22)}.padding({ left: 12, right: 12 }).width('100%').height('48vp')Row() {Text() {Span(this.plainText).fontSize(16).fontWeight(400).fontColor('#182431')}.textAlign(TextAlign.Start)}.padding({ left: 12, right: 12, bottom: 4 }).width('100%').height('52vp')}.borderRadius(16).width('100%').height('100').backgroundColor(0xFFFFFF)}}}.height('100vp').margin({ left: 12, right: 12, bottom: 12 })Column() {GridRow() {GridCol({ span: { xs: 12, sm: 12, md: 12, lg: 12 } }) {Column() {Button() {Text($r('app.string.verify')).fontSize(16).fontWeight(500).lineHeight(22).fontColor('#FFFFFF')}.borderRadius(20).id('verifyBtn').type(ButtonType.Capsule).margin({ left: 24, right: 24 }).width('100%').height('40vp').backgroundColor('#007DFF').onClick(() => {if (this.textFileUri === '' || this.keyFileUri === '' || this.signFileUri === '') {promptAction.showToast({message: $r('app.string.null_message')});} else {this.verifyFunc();}});}}}.margin({ left: 24, right: 24 })}.width('100%').height('340vp').justifyContent(FlexAlign.End)}.width('100%').height('100%')}}async selectRsaKeyFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})// 获取到密钥文档文件的URIthis.keyFileUri = uri;// 获取到密钥文档文件的文件名称await TextFileManager.readTextFile(this.keyFileUri);this.keyFileName = TextFileManager.getName();this.keyString = TextFileManager.getString();}async selectTextFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})// 获取到文档文件的URIthis.textFileUri = uri;// 获取到文档文件的文件名称await TextFileManager.readTextFile(this.textFileUri);this.textFileName = TextFileManager.getName();this.plainText = TextFileManager.getString();}async selectSignFileAndRead() {let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['.txt'];documentSelectOptions.maxSelectNumber = 1;let uri: string = '';let documentViewPicker = new picker.DocumentViewPicker();await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to text file succeed and uris are:' + uri);}).catch((err: Error) => {console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);})// 获取到文档文件的URIthis.signFileUri = uri;// 获取到文档文件的文件名称await TextFileManager.readTextFile(this.signFileUri);this.signFileName = TextFileManager.getName();this.signText = TextFileManager.getString();}async createKeyFileAndWrite() {let documentSaveOptions = new picker.DocumentSaveOptions();documentSaveOptions.newFileNames = ['rsaKey.txt'];let documentPicker = new picker.DocumentViewPicker();try {let documentSaveResult = await documentPicker.save(documentSaveOptions);this.createKeyUri = documentSaveResult[0];await TextFileManager.writeTextFile(this.createKeyUri, this.keyString);} catch (error) {Logger.error(TAG, `save key failed, ${error}`);}}async verifyFunc() {let verifyRes: Boolean = false;if (this.plainText === '' || this.keyFileUri === '' || this.signText === '') {promptAction.showToast({message: $r('app.string.null_message')});return;}try {verifyRes = await this.CryptoOperation.rsaConvertAndVerify(this.keyString, this.plainText, this.signText);} catch (error) {Logger.error(TAG, `verify failed, ${error}`);}if (verifyRes != true) {promptAction.showToast({message: $r('app.string.verify_fail')});return;} else {promptAction.showToast({message: $r('app.string.verify_success')});}}
}
以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下:
内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!
鸿蒙【北向应用开发+南向系统层开发】文档
鸿蒙【基础+实战项目】视频
鸿蒙面经

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!
相关文章:
鸿蒙系统开发【加解密算法库框架】安全
加解密算法库框架 介绍 本示例使用ohos.security.cryptoFramework相关接口实现了对文本文件的加解密、签名验签操作。 实现场景如下: 1)软件需要加密存储本地文本文件,需要调用加解密算法库框架选择密钥文本文件,对本地文本文…...
C语言——二维数组和字符数组
二维数组 二维数组本质上是一个行列式的组合,也就是二维数组是有行和列两部分构成。二维数组数据是通过行列进行解读。 定义形式: 类型(说明符) 数组名[行数(常量表达式1)][列数(常量表达式…...
Python 爬虫入门(九):Scrapy安装及使用「详细介绍」
Python 爬虫入门(九):Scrapy安装及使用「详细介绍」 前言1. Scrapy 简介2. Scrapy 的安装2.1 环境准备2.2 安装 Scrapy 3. 创建 Scrapy 项目3.1 创建项目3.2 项目结构简介 4. 编写爬虫4.1 创建爬虫4.2 解析数据4.3 运行爬虫 5. 存储数据5.1 存…...
扩展addr2line程序的功能,group_add2line() 脚本的实现
------------------------------------------------------------ author: hjjdebug date: 2024年 08月 05日 星期一 16:19:07 CST descrition: 扩展addr2line程序的功能,group_add2line() 脚本的实现 ------------------------------------------------------------ 扩展addr2…...
idea中修改项目名称
公司最近有个小项目新加了很多功能,在叫原先的项目名有点不合适了。所以在网上查了下资料,发现步骤都比较复杂。自己研究了一下找到了一个相对简单的方法,只需要两步,特此记录一下。 1.修改项目文件夹名称 关闭当前项目ÿ…...
Flink开发语言使用Java还是Scala合适?
目录 1. Flink简介 1.1 什么是Apache Flink? 1.2 Flink的核心组件 2. Java与Scala在Flink开发中的比较 2.1 语言特性对比 2.2 开发体验对比 3. 实际开发中的应用 3.1 使用Java进行Flink开发 3.2 使用Scala进行Flink开发 4. 关键性能和优化 4.1 性能对比 …...
C++STL专题 vector底层实现
目录 一, vector的手搓 1.构造函数 2. 拷贝构造的实现 3.析构函数 4.begin() end() 的实现 5.reserve的实现 6.size和capacity的实现 7.push_back的实现 8.pop_back的实现 9.empty的实现 10.insert的实现 11.erase的实现 12.resize的实现 13.clear的实…...
【Linux】装机常用配置
文章目录 1. 下载常用软件包2. 更新yum源3. vim编辑器配置4. 安装C语言和C的静态库(换root)5. git6. sudo给普通用户提权7. 更新git版本(centos默认安装1.8.x,我们更新到2.x)8. getch9. json10. 升级gcc版本11. 跨系统…...
oracle库PASSWORD_VERSIONS 对应的加密方式
oracle库PASSWORD_VERSIONS 对应的加密方式 10G DES 11G SHA-1 12C SHA-2-based SHA-512官方文档: https://docs.oracle.com/database/121/DBSEG/authentication.htm#DBSEG487...
分享一个基于微信小程序的乡村医疗上门服务预约平台(源码、调试、LW、开题、PPT)
💕💕作者:计算机源码社 💕💕个人简介:本人 八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流&…...
切香肠(Sausage)
题目描述 有 n 条香肠,每条香肠的长度相等。我们打算将这些香肠切开后分给 k 名客人,且要求每名客人获得一样多的香肠,且要将所有的香肠分配完,不做保留。 请问最少需要切几刀才能完成?一刀只能切断一条香肠…...
Session与Cookie以及Cache区别,及应用场景
Session、Cookie和Cache是Web开发中常用的数据存储方式,它们在功能、存储位置和应用场景上有所不同。 一、Session、Cookie和Cache的区别 Session 存储位置:服务器端。功能:通过在服务器上存储唯一的标识符(Session IDÿ…...
Debian | 更换 Gnome 至 Xfce4
Debian | 更换 Gnome 至 Xfce4 更新源 sudo apt update && sudo apt upgrade安装 xfce4 sudo apt install xfce4我选择 lightdm,回车 切换桌面 sudo update-alternatives --config x-session-manager输入 xfce 所在序号,我这里是 3 卸载 …...
在使用JSON过程中遇到的一个空间释放问题
在对完成的模块进行空间访问检查中发现了这个问题,这刚开始接触JSON的使用,也不知道他的内部实现,因此该问题找了好久,终于发现是每个节点创建都会自动开辟空间,因此造成空间未成功释放的错误。 JSON未成功替换节点空间…...
基于ThinkPHP开发的校园跑腿社区小程序系统源码,包含前后端代码
基于ThinkPHP开发的校园跑腿社区小程序系统源码,包含前后端代码 最新独立版校园跑腿校园社区小程序系统源码 | 附教程 测试环境:NginxPHP7.2MySQL5.6 多校版本,多模块,适合跑腿,外卖,表白,二…...
不同专业方向如何在ChatGPT的帮助下完成选题
学境思源,一键生成论文初稿: AcademicIdeas - 学境思源AI论文写作 选择一个合适的论文题目是每个论文写作同学必须面对的重要任务。无论是历史专业、计算机科学专业,还是其他各个领域,找到一个既有研究价值又符合个人兴趣的选题往…...
MathType7.4中文版本功能详解!你的数学公式编辑神器
嘿,亲爱的小伙伴们,今天我要跟大家分享一个超实用的工具——MathType7中文版。作为一个自媒体人,我常常需要编辑各种复杂的数学公式,而这款软件简直就是我的救星!接下来,就让我带你们领略一下它的神奇之处吧…...
在 PhpStorm 中为 .java 文件启用语法高亮,需要正确配置文件类型和关联语言。
点击访问我的技术博客https://ai.weoknow.comhttps://ai.weoknow.com 因为我同时使用java和php混编所以在一个项目中如果同时打开IntelliJ IDEA和PhpStorm不符合我完美主义的本性。 捣鼓了一下搞定了 1. 添加文件类型关联 将 .java 文件与 Java 语言支持关联: …...
2024年8月1日(前端服务器的配置以及tomcat环境的配置)
[rootstatic ~]# cd eleme_web/ [rootstatic eleme_web]# cd src/ [rootstatic src]# ls views/ AboutView.vue HomeView.vue [rootstatic src]# vim views/HomeView.vue [rootstatic src]# nohup npm run serve nohup: 忽略输入并把输出追加到"nohup.out" 构建项目…...
基于tcp,html,数据库的在线信息查询系统项目总结
1.项目背景 在线信息查询系统是一种可用于检索和展示各种信息的计算机程序或平台。主要特点包括: 用户接口:通常提供友好的界面,用户可以方便地输入查询条件。 数据存储:系统往往连接到数据库,存储大量信息…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
