文档管理中心
FAQ应用框架开发本地数据和文件本地文件管理如何实现加解密下载文件

如何实现加解密下载文件

问题现象

如何实现文件下载后加密存储到公共目录,使之无法打开查看,需要再次读取公共目录保存的加密文件进行解密后再次保存,方可正常查看?

背景知识

  • @ohos.file.fs (文件管理):该模块为基础文件操作API,提供基础文件操作能力,包括文件基本管理、文件目录管理、文件信息统计、文件流式读写等常用功能。
  • 加解密开发指导:在数据存储或传输场景中,可以使用加解密操作用于保证数据的机密性,防止敏感数据泄露。
  • DocumentViewPicker:适用于文件类型文件的选择与保存。DocumentViewPicker对接的选择资源来自于FilePicker,负责文件类型的资源管理,文件类型不区分后缀,比如浏览器下载的图片、文档等,都属于文件类型。通过Picker访问相关文件,将拉起对应的应用,引导用户完成界面操作,接口本身无需申请权限。

解决方案

由问题可知实现此功能重点是如下两步:

  1. 文件读取并加密后保存至公共目录;
  2. 选择公共目录下的加密文件解密后,再次保存至公共目录。

示例代码如下(代码中使用AES对称密钥(ECB模式)加解密,亦可选择其他加解密算法;前置步骤需要配置网络权限已省略,请参考配置网络权限):

收起
自动换行
深色代码主题
复制
  1. import { BusinessError, request } from '@kit.BasicServicesKit';
  2. import picker from '@ohos.file.picker';
  3. import fs from '@ohos.file.fs';
  4. import { cryptoFramework } from '@kit.CryptoArchitectureKit';
  5. let keyData = new Uint8Array([83, 217, 231, 76, 28, 113, 23, 219, 250, 71, 209, 210, 205, 97, 32, 159]);
  6. let symKey = genSymKeyByData(keyData);
  7. function genSymKeyByData(symKeyData: Uint8Array) {
  8. let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
  9. let aesGenerator = cryptoFramework.createSymKeyGenerator('AES128');
  10. let symKey = aesGenerator.convertKeySync(symKeyBlob);
  11. return symKey;
  12. }
  13. // 加密消息
  14. function encryptMessage(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) {
  15. let cipher = cryptoFramework.createCipher('AES128|ECB|PKCS7');
  16. cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, null); // ECB模式params为null。
  17. let cipherData = cipher.doFinalSync(plainText);
  18. return cipherData;
  19. }
  20. // 解密消息
  21. function decryptMessage(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) {
  22. let decoder = cryptoFramework.createCipher('AES128|ECB|PKCS7');
  23. decoder.initSync(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, null); // ECB模式params为null。
  24. let decryptData = decoder.doFinalSync(cipherText);
  25. return decryptData;
  26. }
  27. function getPlainText(file: fs.File) {
  28. let stat = fs.statSync(file.path); // 获取文件状态
  29. let buf = new ArrayBuffer(stat.size); // 创建一个ArrayBuffer对象
  30. let num = fs.readSync(file.fd, buf); // 读取文件
  31. let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buf.slice(0, num)) };
  32. return plainText;
  33. }
  34. @Entry
  35. @Component
  36. export struct DocumentSave {
  37. context = this.getUIContext().getHostContext() as Context;
  38. // downloadUrl替换为实际文件下载链接
  39. downloadUrl: string = 'https://xxx/xxx/xx.docx';
  40. // 下载文件并加密内容
  41. downloadFileAndEncrypt() {
  42. // 自定义文件名以及文件格式
  43. const fileName = `test${Date.now()}.docx`;
  44. request.downloadFile(this.context, {
  45. enableMetered: true,
  46. url: this.downloadUrl,
  47. filePath: `${this.context.filesDir}/${fileName}`, // 沙箱路径
  48. }).then((downloadTask: request.DownloadTask) => {
  49. downloadTask.on('complete', () => {
  50. const documentSaveOptions = new picker.DocumentSaveOptions(); // 创建文件管理器保存选项实例
  51. documentSaveOptions.newFileNames = [fileName]; // 保存文件名
  52. const documentViewPicker = new picker.DocumentViewPicker;
  53. documentViewPicker.save(documentSaveOptions)
  54. .then(async (documentSaveResult) => {
  55. // 获取到图片或者视频文件的URI后进行文件读取等操作
  56. let uri = documentSaveResult[0];
  57. if (uri) {
  58. // 沙箱路径文件
  59. let sanFile =
  60. fs.openSync(`${this.context.filesDir}/${fileName}`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  61. let pubFile = fs.openSync(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  62. const plainText = getPlainText(sanFile);
  63. // 加密
  64. let encryptText = encryptMessage(symKey, plainText);
  65. fs.writeSync(pubFile.fd, encryptText.data.buffer);
  66. fs.unlink(sanFile.path);
  67. } else {
  68. // 取消保存到用户目录之后,删除沙箱目录下保存的文件
  69. fs.rmdirSync(`${this.context.filesDir}/${fileName}`);
  70. }
  71. }
  72. );
  73. });
  74. }
  75. ).catch((err: BusinessError) => {
  76. console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
  77. });
  78. }
  79. // 文件解密
  80. async decryptFile() {
  81. let uri: string = '';
  82. // 自定义文件名以及文件格式
  83. const fileName = `test${Date.now()}.docx`;
  84. let documentSelectOptions = new picker.DocumentSelectOptions();
  85. documentSelectOptions.fileSuffixFilters = [];
  86. documentSelectOptions.maxSelectNumber = 1;
  87. let documentViewPicker = new picker.DocumentViewPicker();
  88. await documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {
  89. uri = decodeURIComponent(documentSelectResult[0]);
  90. let pubFile = fs.openSync(uri, fs.OpenMode.READ_ONLY);
  91. let file =
  92. fs.openSync(`${this.context.filesDir}/${fileName}`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); // 打开文件
  93. const plainText = getPlainText(pubFile);
  94. let decryptText = decryptMessage(symKey, plainText);
  95. fs.writeSync(file.fd, decryptText.data.buffer);
  96. const documentSaveOptions = new picker.DocumentSaveOptions(); // 创建文件管理器保存选项实例
  97. documentSaveOptions.newFileNames = [fileName];
  98. documentViewPicker.save(documentSaveOptions).then(async (documentSaveResult) => {
  99. let uri = documentSaveResult[0];
  100. if (uri) {
  101. let pubFile = fs.openSync(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  102. fs.copyFileSync(file.fd, pubFile.fd);
  103. fs.unlink(file.path);
  104. } else {
  105. fs.rmdirSync(`${this.context.filesDir}/${fileName}`);
  106. }
  107. });
  108. }).catch((err: Error) => {
  109. console.error(`Invoke documentViewPicker.select failed, code is ${err}, message is ${err.message}`);
  110. });
  111. }
  112. build() {
  113. RelativeContainer() {
  114. Row() {
  115. Button('下载加密保存')
  116. .fontSize(20)
  117. .fontWeight(FontWeight.Bold)
  118. .onClick(() => {
  119. this.downloadFileAndEncrypt();
  120. });
  121. Button('解密后保存')
  122. .fontSize(20)
  123. .fontWeight(FontWeight.Bold)
  124. .onClick(() => {
  125. this.decryptFile();
  126. });
  127. };
  128. }
  129. .height('100%')
  130. .width('100%');
  131. }
  132. }
在 FAQ 中进行搜索
请输入您想要搜索的关键词