HarmonyOS 鸿蒙Next 在 raw中可以解密成功,但是在沙箱中读取文件就解析不了,好像沙箱没有提供直接获取 Uint8Array 的方法

发布于 1周前 作者 yibo5220 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 在 raw中可以解密成功,但是在沙箱中读取文件就解析不了,好像沙箱没有提供直接获取 Uint8Array 的方法

正确读取沙箱中的加密 xml文件,然后解密出来内容。
 

2 回复
你可以参考这个demo,这个demo里边先创建文件,他会把工程里边的raw底下的xml文件复制到应用沙箱目录下面,然后再点击读取文件他会读取您刚才复制到沙箱的文件然后进行解密:
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { buffer, HashMap, util, xml } from '@kit.ArkTS';
import fs, { Options, ReadTextOptions } from '@ohos.file.fs';
let key = 'xxx'
let cipherAlgName = 'AES128|ECB|PKCS7';
let symAlgName = 'AES128';
let base64Helper = new util.Base64Helper;
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index {
  [@State](/user/State) message: string = 'Hello World';
  private fileDir: string = ''
  createFile(){
    let xmlContent: Uint8Array = getContext().resourceManager.getRawFileContentSync("mibook.xml");
    //let str:string = uint8ArrayToString(xmlContent)
    let cacheDir = getContext().filesDir;
    this.fileDir = cacheDir + '/HelloWorldlee.xml'
    let file = fs.openSync(this.fileDir, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
    let writeLen = fs.writeSync(file.fd, xmlContent.buffer);
    console.info("write data to file succeed and size is:" + writeLen);
    fs.closeSync(file)
  }
  readFile(){
    let stat = fs.statSync(this.fileDir);
    let arraybuf:ArrayBuffer = new ArrayBuffer(stat.size)
    let file = fs.openSync(this.fileDir, fs.OpenMode.READ_WRITE)
    fs.readSync(file.fd,arraybuf)
    let uint8Array: Uint8Array = new Uint8Array(arraybuf);
    let plainText: cryptoFramework.DataBlob = { data: uint8Array };
    this.AES_CBC_Update(plainText)
  }
  build() {
    Column() {
      Scroll() {
        Text(this.message)
          .id('HelloWorld')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .alignRules({
            center: { anchor: '__container__', align: VerticalAlign.Center },
            middle: { anchor: '__container__', align: HorizontalAlign.Center }
          })
      }
      Button('加解密数据')
        .onClick(() => {
          //获取加密文件
          let xmlContent: Uint8Array = getContext().resourceManager.getRawFileContentSync("mibook.xml");
          let plainText: cryptoFramework.DataBlob = { data: xmlContent };
          this.AES_CBC_Update(plainText)
        })
      Button('创建文件')
        .onClick(() => {
          this.createFile();
        })
      Button('读取文件')
        .onClick(() => {
          this.readFile();
        })
    }
    .height('100%')
    .width('100%')
  }
  async AES_CBC_Update(plainText: cryptoFramework.DataBlob) {
    //解密
    await this.aesDecryptAll(plainText, key);
  }
  // 解密
  async aesDecrypt(globalCipherText: cryptoFramework.DataBlob, key: string) {
    let globalPlainText = "";
    try {
      let globalCipher = cryptoFramework.createCipher(cipherAlgName);
      let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);
      let dataUint8Array = base64Helper.decodeSync(key)
      let keyBlob: cryptoFramework.DataBlob = { data: dataUint8Array }
      /*
      * 偏移量
      * */
      let cbcParamsSpec: cryptoFramework.IvParamsSpec = {
        iv: { data: stringToUint8Array("your-iv-your-iva") },
        algName: 'IvParamsSpec'
      };
      let promiseSymKey = await symKeyGenerator.convertKey(keyBlob)
      await globalCipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, promiseSymKey, null);
      let updateLength = 1024;
      for (let i = 0; i <= globalCipherText.data.length / updateLength; i++) {
        let messageArr = globalCipherText.data.slice(i * updateLength, (i + 1) * updateLength);
        let message = new Uint8Array(messageArr);
        let messageBlob: cryptoFramework.DataBlob = { data: message };
        let updateOutput = await globalCipher.update(messageBlob);
        if (updateOutput) {
          globalPlainText += uint8ArrayToString(updateOutput.data);
        }
      }
      let finalOutput = await globalCipher.doFinal(null);
      globalPlainText += uint8ArrayToString(finalOutput.data)
      //this.message = globalPlainText
      // console.log("解密后的明文==》" + globalPlainText)
      let strXml = globalPlainText
      // let textEncoder: util.TextEncoder = new util.TextEncoder();
      // let arrBuffer: Uint8Array = textEncoder.encodeInto(strXml); // 对数据编码,防止包含中文字符乱码
      // // 1.基于ArrayBuffer构造XmlPullParser对象
      // let that: xml.XmlPullParser = new xml.XmlPullParser(arrBuffer.buffer as object as ArrayBuffer, 'UTF-8');
      // let options: xml.ParseOptions = { supportDoctype: true, ignoreNameSpace: true, tagValueCallbackFunction: func };
      // that.parse(options);
      let textEncoder: util.TextEncoder = new util.TextEncoder();
      let arrBuffer: Uint8Array = textEncoder.encodeInto(strXml); // 对数据编码,防止包含中文字符乱码
      let that: xml.XmlPullParser = new xml.XmlPullParser(arrBuffer.buffer as object as ArrayBuffer, 'UTF-8');
      let options: xml.ParseOptions = {
        supportDoctype: false,
        ignoreNameSpace: false,
        tagValueCallbackFunction: func,
        attributeValueCallbackFunction: func1
      };
      that.parse(options);
      console.info(str); // 一次打印出所有的属性及其值
      console.log("解密后的明文==》" + globalPlainText.length)
    } catch (err) {
      console.log(err.message)
    }
  }
  // 解密
  async aesDecryptAll(globalCipherText: cryptoFramework.DataBlob, key: string) {
    let globalPlainText = "";
    try {
      let globalCipher = cryptoFramework.createCipher(cipherAlgName);
      let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);
      let dataUint8Array = base64Helper.decodeSync(key)
      let keyBlob: cryptoFramework.DataBlob = { data: dataUint8Array }
      let promiseSymKey = await symKeyGenerator.convertKey(keyBlob)
      await globalCipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, promiseSymKey, null);
      let updateOutput = await globalCipher.update(globalCipherText);
      let finalOutput = await globalCipher.doFinal(null);
      globalPlainText = uint8ArrayToString(updateOutput.data) + uint8ArrayToString(finalOutput.data)
      //this.message = globalPlainText
      // console.log("解密后的明文==》" + globalPlainText)
      let strXml = globalPlainText
      // let textEncoder: util.TextEncoder = new util.TextEncoder();
      // let arrBuffer: Uint8Array = textEncoder.encodeInto(strXml); // 对数据编码,防止包含中文字符乱码
      // // 1.基于ArrayBuffer构造XmlPullParser对象
      // let that: xml.XmlPullParser = new xml.XmlPullParser(arrBuffer.buffer as object as ArrayBuffer, 'UTF-8');
      // let options: xml.ParseOptions = { supportDoctype: true, ignoreNameSpace: true, tagValueCallbackFunction: func };
      // that.parse(options);
      namesMap.clear()
      let textEncoder: util.TextEncoder = new util.TextEncoder();
      let arrBuffer: Uint8Array = textEncoder.encodeInto(strXml); // 对数据编码,防止包含中文字符乱码
      let that: xml.XmlPullParser = new xml.XmlPullParser(arrBuffer.buffer as object as ArrayBuffer, 'UTF-8');
      let options: xml.ParseOptions = {
        supportDoctype: true,
        ignoreNameSpace: true,
        tagValueCallbackFunction: func,
        attributeValueCallbackFunction: func1,
      };
      namesMap.length
      that.parse(options);
      console.info("解析后的属性:" + str1); // 一次打印出所有的属性及其值
      console.log("解密后的明文==》" + globalPlainText.length)
    } catch (err) {
      console.log(err.message)
    }
  }
}
let str: string = '';
let tempName = ""
let namesMap: HashMap<string, string> = new HashMap()
let chapterNamesMap: HashMap<string, string> = new HashMap()
let chaptersXml = false
function isNull(content: string): boolean {
  return content == null || content == undefined || content.length <= 0 || content.indexOf("\n") != -1
}
function func(name: string, value: string): boolean {
  if (!isNull(name)) {
    if ("chapters" == name) {
      chaptersXml = !chaptersXml
    }
    tempName = name
  }
  if (!isNull(value) && !isNull(tempName)) {
    if (chaptersXml) {
      chapterNamesMap.set(tempName, value)
    } else {
      namesMap.set(tempName, value)
    }
  }
  str = name + value;
  console.info('xml解析 func :', "name:" + name + " value:" + value);
  return true; //true:继续解析 false:停止解析
}
let str1: string = '';
function func1(name: string, value: string): boolean {
  str1 += name + ' ' + value + ' ';
  console.log("func1", "解析属性值 name:" + name + " value:" + value)
  return true; // true:继续解析 false:停止解析
}
let str2: string = '';
function func2(name: xml.EventType, value: xml.ParseInfo): boolean {
  str2 = name + ' ' + value.getDepth(); // getDepth 获取元素的当前深度
  console.info(str2)
  return true; //true:继续解析 false:停止解析
}
// 字符串转成字节流
function stringToUint8Array(str: string) {
  return new Uint8Array(buffer.from(str, 'utf-8').buffer);
}
// 字节流转成可理解的字符串
function uint8ArrayToString(array: Uint8Array) {
  // 将UTF-8编码转换成Unicode编码
  let out: string = "";
  let index: number = 0;
  let len: number = array.length;
  while (index < len) {
    let character = array[index++];
    switch (character >> 4) {
      case 0:
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
      case 7:
        out += String.fromCharCode(character);
        break;
      case 12:
      case 13:
        out += String.fromCharCode(((character & 0x1F) << 6) | (array[index++] & 0x3F));
        break;
      case 14:
        out += String.fromCharCode(((character & 0x0F) << 12) | ((array[index++] & 0x3F) << 6) |
          ((array[index++] & 0x3F) << 0));
        break;
      default:
        break;
    }
  }
  return out;
} 

更多关于HarmonyOS 鸿蒙Next 在 raw中可以解密成功,但是在沙箱中读取文件就解析不了,好像沙箱没有提供直接获取 Uint8Array 的方法的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next系统中,沙箱环境与raw环境在文件访问权限和数据处理方式上存在显著差异。raw环境中解密成功不代表沙箱中可以直接沿用相同的处理方式,因为沙箱增加了安全隔离机制,限制了某些敏感操作。

沙箱环境未直接提供Uint8Array获取方法,主要是因为安全沙箱设计原则之一是限制对底层数据的直接访问,以防止潜在的安全风险。在沙箱中读取文件后,数据可能以不同的形式(如Blob或ArrayBuffer)存在,需要转换格式以适应Uint8Array的使用。

可以尝试以下方法处理:

  • 确认沙箱中读取文件后的数据类型,如果是Blob或ArrayBuffer,可以使用相应API转换为Uint8Array。例如,ArrayBuffer可通过new Uint8Array(arrayBuffer)转换。
  • 检查沙箱中文件读取权限是否完整,确保有权限读取文件内容。
  • 验证解密算法在沙箱环境中是否适用,有时算法实现依赖底层环境特性,需做适当调整。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部