应用启动中进行加解密处理时，出现闪退
==================

#### 问题现象

应用在启动中使用加解密功能的情况下，发生闪退。

#### 背景知识

*   JsCrash异常根据不同的异常场景，在Reason字段进行了分类，分为Error、TypeError、SyntaxError、ReferenceError、RangeError等错误类型。参考文档[JS Crash（进程崩溃）检测](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/jscrash-guidelines)。
*   JsCrash日志规格说明可以参考[日志规格](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/jscrash-guidelines#日志规格)。
*   [doFinal](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-cryptoframework#dofinal)和[doFinalSync](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-cryptoframework#dofinalsync12)用于加解密本次传入的数据，并获取加密或解密后的数据。
*   在数据存储或传输场景中，可以使用加解密操作用于保证数据的机密性，防止敏感数据泄露，详细可见[加解密开发指导](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/crypto-encrypt-decrypt-dev)。

#### 问题定位

1.  从faultlogger目录下获取到应用的JsCrash故障日志，故障原因是Error，故障信息为do final fail!，数据加解密失败。
    
    Reason:Error
    Error name:Error
    Error message:do final fail!
    Error code:
    Stacktrace:
    Cannot get SourceMap info, dump raw stack:
        at decryptSync (entry|@pura/harmony-utils|1.3.4|src/main/ets/crypto/CryptoUtil.ts:26:1)
        at decryptSync (entry|@pura/harmony-utils|1.3.4|src/main/ets/crypto/SM4.ts:66:1)
        at decryptECBSync (entry|@pura/harmony-utils|1.3.4|src/main/ets/crypto/SM4.ts:54:1)
        at sm4Decode (entry|entry|1.0.0|src/main/ets/utils/j1.ts:93:1)
        at aboutToAppear (entry|entry|1.0.0|src/main/ets/pages/GWLogin.ts:316:1)
        at anonymous (entry|entry|1.0.0|src/main/ets/d/n1.ts:698:1)
    
2.  排查hilog日志，搜索关键字HCF，从JsCipherDoFinalSync\[726\]: failed to do final!日志中可以看出，应用在调用[doFinalSync](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-cryptoframework#dofinalsync12)接口失败。
    
    07-30 14:34:30.066 14335 14335 E C02F0A/com.hx.example/HCF: CommonDoFinal\[592\]: EVP\_CipherFinal\_ex failed!
    07-30 14:34:30.066 14335 14335 E C02F0A/com.hx.example/HCF: JsCipherDoFinalSync\[726\]: failed to do final!
    
3.  由于分组加密算法对分组长度存在限制，必须使用填充方法对每个分组补足到规定长度，如果不符合要求就会导致[doFinalSync](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-cryptoframework#dofinalsync12)接口失败，需要排查加密算法的填充模式以及明文的长度是否正常，以及加解密密钥是否一致。

#### 分析结论

*   没有正确对明文进行填充，导致数据加解密失败。
*   加解密密钥不一致，导致无法正确解密。

#### 修改建议

*   选择正确的填充模式，例如PKCS5和PKCS7，或自行填充。
*   确保加解密使用的密钥保持一致。
    
    import { cryptoFramework } from '@kit.CryptoArchitectureKit';
    import { buffer } from '@kit.ArkTS';
    
    @Entry
    @Component
    struct EncryptComponent {
      @State data: string = '';
      @State encryptText: cryptoFramework.DataBlob | null = null;
      @State decryptTextString: string = '';
      @State result: string = '';
    
     _ // 加密消息_
      encryptMessage(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) {
        let cipher = cryptoFramework.createCipher('SM4\_128|ECB|PKCS7');
        cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT\_MODE, symKey, null);
        let encryptData = cipher.doFinalSync(plainText);
        return encryptData;
      }
    
      decryptMessage(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) {
        let decoder = cryptoFramework.createCipher('SM4\_128|ECB|PKCS7');
        decoder.initSync(cryptoFramework.CryptoMode.DECRYPT\_MODE, symKey, null);
        let decryptData = decoder.doFinalSync(cipherText);
        return decryptData;
      }
    
      genSymKeyByData(symKeyData: Uint8Array) {
        let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
        let symGenerator = cryptoFramework.createSymKeyGenerator('SM4\_128');
        let symKey = symGenerator.convertKeySync(symKeyBlob);
        return symKey;
      }
    
      encryptSuccess() {
        let keyData = new Uint8Array(\[7, 154, 52, 176, 4, 236, 150, 43, 237, 9, 145, 166, 141, 174, 224, 131\]);
        let symKey = this.genSymKeyByData(keyData);
        let message = this.data;
        let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
        this.encryptText = this.encryptMessage(symKey, plainText);
        this.result = \`加密结果(DataBlob)：${this.encryptText.data.toString()}\`;
      }
    
      decryptSuccess() {
        let keyData = new Uint8Array(\[7, 154, 52, 176, 4, 236, 150, 43, 237, 9, 145, 166, 141, 174, 224, 131\]);
        let symKey = this.genSymKeyByData(keyData);
        if (this.encryptText != null) {
          let decryptText = this.decryptMessage(symKey, this.encryptText);
          this.decryptTextString = buffer.from(decryptText.data).toString('utf-8');
          this.result = \`解密结果(DataBlob)：${decryptText.data.toString()}\\n解密结果(string)：${this.decryptTextString}\`;
        } else {
          this.result = '无加密内容，需先加密';
        }
      }
    
      build() {
        Column({ space: 15 }) {
          TextInput({ placeholder: '输入加密内容' })
            .onChange((value: string) => {
              this.data = value;
            })
            .margin({ left: 15, right: 15 })
          Button('加密')
            .onClick(() => {
              this.encryptSuccess();
            })
          Button('解密')
            .onClick(() => {
              this.decryptSuccess();
            })
          Text(this.result)
            .fontSize(20)
        }
        .height('100%')
        .width('100%')
        .justifyContent(FlexAlign.Center)
      }
    }