3DES加密实现兼容java的解密
=================

#### 问题现象

ArkTS中使用3DES加密算法加密的数据在java侧无法解密，如何解决该问题。

#### 背景知识

3DES算法的加解密过程分别是对明文/密文数据进行三次DES加密或解密，得到相应的密文或明文。

当前支持以字符串参数完成3DES加解密，具体的“字符串参数”由“对称密钥类型（加解密算法+密钥长度）”、“分组模式”和“填充模式”使用符号“|”拼接而成，用于在创建对称加解密实例时，指定算法规格。

#### 解决方案

ArkTS在生成密文后，需要使用base64的util.Type.BASIC生成无换行符的字符串后传递到java侧进行解密。提供ArkTS代码和java代码。

ArkTS侧对“This is a test”进行加密：

import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { buffer, util } from '@kit.ArkTS';

@Entry
@Component
struct Index {
  message: string = '加密';

  build() {
    RelativeContainer() {
      Text(this.message)
        .id('encrypt')
        .fontSize($r('app.float.page\_text\_font\_size'))
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '\_\_container\_\_', align: VerticalAlign.Center },
          middle: { anchor: '\_\_container\_\_', align: HorizontalAlign.Center }
        })
        .onClick(() => {
          encrypt\_3DES();
        })
    }
    .height('100%')
    .width('100%')
  }
}

_/\*\*_
 _\* 加密消息_
 _\*_
 _\* @param symKey symKey_
 _\* @param plainText plainText_
 _\* @returns 加密后的内容_
 _\*/_
async function encryptMessagePromise(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) {
  let cipher = cryptoFramework.createCipher('3DES192|ECB|PKCS7');
  await cipher.init(cryptoFramework.CryptoMode.ENCRYPT\_MODE, symKey, null);
  let encryptData = await cipher.doFinal(plainText);
  return encryptData;
}

_/\*\*_
 _\* 通过key data值获取symKey_
 _\* @param symKeyData keyData_
 _\* @returns void_
 _\*/_
async function genSymKeyByData(symKeyData: Uint8Array) {
  let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
  let symGenerator = cryptoFramework.createSymKeyGenerator('3DES192');
  let symKey = await symGenerator.convertKey(symKeyBlob);
  console.info('convertKey success');
  return symKey;
}

_/\*\*_
 _\* 将uint8转换为 string值_
 _\* @param uint Uint8Array值_
 _\* @returns string值_
 _\*/_
function uint8ToString(uint: Uint8Array): string {
  let base64Helper = new util.Base64Helper();
  let result = base64Helper.encodeToStringSync(uint, util.Type.BASIC);
  console.info('result = ', result);
  return result;

}

_/\*\*_
 _\* 3DES\_ECB模式加密_
 _\*/_
export async function encrypt\_3DES() {
 _ // 此处填写实际值_
  let keyData =
    new Uint8Array(\[238, 249, 61, 55, 128, 220, 183, 224, 139, 253, 248, 239, 239, 41, 71, 25, 235, 206, 230, 162, 249,
      27, 234, 114\]);
  _// 获取symKey_
  let symKey = await genSymKeyByData(keyData);
 _ // 待加密的信息_
  let message = 'This is a test';
 _ // 将待加密的信息转换为plainText_
  let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
 _ // 生成加密后的密文_
  let encryptText = await encryptMessagePromise(symKey, plainText);
  console.info('encrypt:', uint8ToString(encryptText.data));
}

java侧对加密后的信息“7hp/cpn6R+5adY0ALFfktw==”进行解密：

package org.example;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.\*;
import javax.crypto.spec.SecretKeySpec;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class Triple\_DES {
   _ // key值_
    private static String keyString="7vk9N4Dct+CL/fjv7ylHGevO5qL5G+py";
   _ // 待解密的字符串信息_
    private static String encryptData="7hp/cpn6R+5adY0ALFfktw==";

   _ /\*\*_
     _\* 获取解密密钥_
     _\*_
     _\* @return SecretKey_
     _\*/_
    public static SecretKey makePrivateKey(){
        byte\[\] keyBytes = Base64.decodeBase64(keyString);
        return new SecretKeySpec(keyBytes, "DESede");
    }

  _  /\*\*_
     _\* 解密_
     _\*/_
    public static String decrypt(SecretKey key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); _// 注意：ECB模式不安全，推荐使用CBC模式并传入IV_
        cipher.init(Cipher.DECRYPT\_MODE, key);
        String encryptedData = encryptData; _// 加密后的数据，通常是Base64编码的字符串_
        byte\[\] encryptedBytes = Base64.decodeBase64(encryptedData);
        byte\[\] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes);
    }

    public static void main(String\[\] args) throws NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
        System.out.println(decrypt(makePrivateKey()));
    }

}