解决Ionic 5解密PHP加密数据的Malformed UTF-8 data错误
解决Ionic 5解密PHP加密数据时的"Malformed UTF-8 data"错误
问题分析
你的TypeScript解密代码存在两处关键错误,导致生成的密钥与PHP端不匹配,最终解密出无效的UTF-8数据:
- 密码与salt拼接逻辑错误:直接将字符串密码与Hex解析后的salt(WordArray类型)拼接,会把salt转为字符串而非使用原始二进制数据参与MD5计算,破坏密钥生成的一致性。
- 密钥截取方式错误:将MD5拼接结果转为Hex字符串后截取前32位,仅相当于取了16字节原始数据,而PHP端实际使用的是32字节的二进制密钥。
修复后的TypeScript解密代码
async base64Decrypt(jsonStr: string, passphrase: string): Promise<any> { const json = JSON.parse(jsonStr); const salt = CryptoJS.enc.Hex.parse(json["s"]); const iv = CryptoJS.enc.Hex.parse(json["iv"]); const ct = CryptoJS.enc.Base64.parse(json["ct"]); // 将密码转为WordArray,与salt拼接(对齐PHP的 $passphrase . $salt 逻辑) const passphraseWA = CryptoJS.enc.Utf8.parse(passphrase); const passSalt = passphraseWA.concat(salt); const md5Results = []; let dx = CryptoJS.lib.WordArray.create(); // 对应PHP初始空值$dx for (let i = 0; i < 3; i++) { // 对齐PHP的 $dx = md5($dx . $passphrase . $salt, true) 逻辑 dx = CryptoJS.MD5(dx.concat(passSalt)); md5Results.push(dx); } // 拼接三次MD5结果得到48字节的salted数据(对齐PHP的$salted) const salted = md5Results[0].concat(md5Results[1]).concat(md5Results[2]); // 取前32字节作为密钥(对齐PHP的$key = substr($salted, 0, 32)) const key = CryptoJS.lib.WordArray.create(salted.words.slice(0, 8), 32); const decrypted = CryptoJS.AES.decrypt({ ciphertext: ct }, key, { iv: iv }); return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8)); }
关键修复点说明
- 二进制数据对齐:用
CryptoJS.enc.Utf8.parse将密码转为WordArray,再与salt拼接,确保使用原始二进制数据参与计算,和PHP端逻辑完全一致。 - 密钥生成流程匹配:循环3次生成MD5并拼接,直接从二进制结果中截取32字节作为密钥,避免Hex转换导致的长度和内容偏差。
- 移除冗余转换:全程操作WordArray类型的二进制数据,避免不必要的字符串转换,保证解密过程的准确性。
验证结果
使用你提供的加密数据和解密密钥测试修复后的代码,将正确解析出与PHP端一致的用户数据,不再出现"Malformed UTF-8 data"错误。
内容的提问来源于stack exchange,提问作者fagbemi ayodele
相关产品推荐
相关产品推荐

