关于CBC NoPadding加密的HarmonyOS 鸿蒙Next应用

关于CBC NoPadding加密的HarmonyOS 鸿蒙Next应用

项目上用到CBC NoPadding的加密。加密的内容是base64后的字符串。

安卓上 对内容进行Base64解码得到32位的有符号的字节数组bytes。然后在执行cipher.doFinal(bytes)

鸿蒙上也是这做同样的操作new util.Base64Helper().decodeSync(str) 进行解码得到32位的无符号的字节数组uint8Array,

然后在执行 

let updateOutput = await cipher.doFinal({data:uint8Array})

let result = util.TextDecoder.create(‘utf-8’).decodeWithStream(updateOutput.data)

两者算出来的值不一致。排了很久也不知道哪里出问题了

整体代码流程如下:

let str = 'hagvQK6KOAt82o5BxVKLeiKn7S4G10zYDXaKdklrWz4='

let aesKey = '5147d0ba622a0e9a’

let iv = ‘8de34be60b473d0d’

//转换key
let symKeyBlob: crypto.DataBlob = { data: new Uint8Array(buffer.from(aesKey, ‘utf-8’).buffer) };
let aesGenerator = crypto.createSymKeyGenerator(“AES128”);
let symKey = await aesGenerator.convertKey(symKeyBlob);
// 初始化加解密操作环境
let mode = crypto.CryptoMode.ENCRYPT_MODE;
//创建加密器
let cipher = crypto.createCipher(“AES128|CBC|NoPadding”);
let ivBlob: crypto.DataBlob = { data: new Uint8Array(buffer.from(iv, ‘utf-8’).buffer)};
let ivParamsSpec: crypto.IvParamsSpec = {
algName: “IvParamsSpec”,
iv: ivBlob
};
//初始化加密
await cipher.init(mode, symKey, ivParamsSpec);
//开始加密
let updateOutput = await cipher.doFinal({ data: new util.Base64Helper().decodeSync(str) });
//转换字符串
let result = util.TextDecoder.create(‘utf-8’).decodeWithStream(updateOutput.data).trim()

 最后得到的是乱码 ���&mk�B�

N��PiE�,���n��x&����


更多关于关于CBC NoPadding加密的HarmonyOS 鸿蒙Next应用的实战教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

鸿蒙的base64和Android的可能不一样,我们这边开始用的base64也不行,后面换成了Hex编码:

function byteToHexString(byteArray: Uint8Array): string {
let str: string = ""
for (let i = 0; i < byteArray.length; i++) {
let tmp: string = ""
let num: number = byteArray[i]
tmp = num.toString(16)
if (tmp.length == 1) {
tmp = "0" + tmp
}
str += tmp
}
return str
}

更多关于关于CBC NoPadding加密的HarmonyOS 鸿蒙Next应用的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


你好,你的加密这种模式解决了吗? AES128|CBC|NoPadding 我的走 let cipherData = await cipher.doFinal(plainText); 这一步时,就散退了?

完整代码如下 static async AES128Encrypt(key: string, message: string): Promise<string> { // key类型转换 const keyUint8Array = StringUtil.stringToUint8Array(key) const symKey = await CryptoUtil.genSymKeyByData(keyUint8Array); // message 类型转换 const messageUint8Array = StringUtil.stringToUint8Array(message) const plainBlob: cryptoFramework.DataBlob = { data: messageUint8Array }; // 加密 const cipherData = await CryptoUtil.AES128EncryptWithBlob(symKey, plainBlob) // base64编码 const result = CryptoUtil.base64EncodeSync(cipherData.data) return result

}

/**

  • AES 128 生成密钥算法为AES、密钥长度为128位的对称密钥(SymKey)。
  • @param symKeyData
  • @returns */ static async genSymKeyByData(symKeyData: Uint8Array) { let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData }; let aesGenerator = cryptoFramework.createSymKeyGenerator(‘AES128’); let symKey = await aesGenerator.convertKey(symKeyBlob); console.info(’======>convertKey success’); return symKey; }

static async AES128EncryptWithBlob(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) { let cipher = cryptoFramework.createCipher(‘AES128|CBC|NoPadding’); let iv = CryptoUtil.genIvParamsSpec(); await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, iv); let cipherData = await cipher.doFinal(plainText); return cipherData; }

/**

  • AES固定向量
  • @returns */ private static genIvParamsSpec() { let vector = CommonConstants.AES_ENCRYPT_KEY let dataIv = StringUtil.stringToUint8Array(vector) let ivBlob: cryptoFramework.DataBlob = { data: dataIv }; let ivParamsSpec: cryptoFramework.IvParamsSpec = { algName: “IvParamsSpec”, iv: ivBlob }; return ivParamsSpec; }

public static stringToUint8Array(str: string): Uint8Array { return new Uint8Array(buffer.from(str, ‘utf-8’).buffer) }

static uint8ArrayToHexString(data: Uint8Array): string { return buffer.from(data).toString(‘hex’) }

static unit8ArrayToStr(src: Uint8Array, encoding: buffer.BufferEncoding = ‘utf-8’): string { let textDecoder = util.TextDecoder.create(encoding, { ignoreBOM: true }) let result = textDecoder.decodeWithStream(src, { stream: true }); return result; }

我们这边用的let cipherAlgName = ‘AES128|CBC|PKCS5’; 这种padding5的加密模式,没有试过NoPadding

这个解决了吗?

你是不是需要的是解密原Base64字符串,而非加密?密文用Base64倒是常用形式,明文字符串用Base64有点非主流:)

如果是解密,把 let mode = crypto.CryptoMode.ENCRYPT_MODE; 改成 DECRYPT_MODE。

如果真是加密,TextDecoder来转码不合适,基本上是乱码,Base64或Hex转码是密文显示常用的。

另:用AES CBC|NoPadding加密 要自己保证明文数据的对齐,即数据长度要符合某个长度的位数,可参考文档说明。

是进行加密。let str = ‘hagvQK6KOAt82o5BxVKLeiKn7S4G10zYDXaKdklrWz4=’ 是服务器下发的base64字符串。拿到后先Base64解密之后。然后在将解密后的内容进行CBC加密。

我一开始也怀疑使用TextDecoder来转码是不是有问题,于是我试了一下把安卓上的执行的 cipher.doFinal()的结果转换成 Uint8Array传给最后一步。即执行 util.TextDecoder.create(‘utf-8’).decodeWithStream(“ Uint8Array”).trim()得到的结果是对的。 我把每个步骤执行结果和安卓的做对比, 发现 let updateOutput = await cipher.doFinal({ data: strData })这个计算结果和安卓上不一致,其它都是对的。

加密后的结果用TextDecoder转码通常是乱码,你用Java能得到正常字符串?方便贴一下安卓解密后转码的结果吗? 顺便问一下,你开发的应用环境是HOS API 9吗?还是更早版本? 如果方便,把Java和ArkTS相关代码贴一下。

我是用的HOS API 11 结果:jmGt5EsrhP8KNEdJZdpH.

import android.util.Base64 import java.math.BigInteger import java.nio.charset.StandardCharsets import java.security.KeyFactory import java.security.MessageDigest import java.security.interfaces.RSAPublicKey import java.security.spec.X509EncodedKeySpec import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec

val keySpec = SecretKeySpec(key.toByteArray(StandardCharsets.US_ASCII), “AES”) val cipher = Cipher.getInstance(“AES/CBC/NoPadding”) val params = IvParameterSpec(iv.toByteArray()) cipher.init(Cipher.DECRYPT_MODE, keySpec, params) val bytes = Base64.decode(content, 0) val original = cipher.doFinal(bytes) return String(original,StandardCharsets.UTF_8).trim { it<= ’ '}

关于CBC NoPadding加密在HarmonyOS鸿蒙Next应用中的问题,作为IT专家,以下是我的解答:

CBC(Cipher Block Chaining)模式是一种加密模式,它将明文分成固定长度的块,并使用前一个密文块(通过某种方式与当前明文块结合)对当前明文块进行加密。而NoPadding模式则是一种不使用填充算法的加密模式,要求输入数据长度必须是分组长度的整数倍。

在HarmonyOS鸿蒙Next应用中,如果使用CBC NoPadding加密,需要确保待加密的数据长度满足这一要求。否则,加密过程可能会失败或产生错误。

此外,CBC模式相比ECB模式等具有更高的安全性,因为它引入了反馈机制,使得每个明文块的加密都依赖于前一个密文块。然而,NoPadding模式虽然简洁,但可能不适用于所有场景,特别是当数据长度不是分组长度的整数倍时。

如果在使用CBC NoPadding加密时遇到问题,建议检查数据长度是否符合要求,并尝试使用其他填充模式(如PKCS5或PKCS7)来解决问题。如果问题依旧没法解决,请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部