使用CryptoJS进行AES加密会破坏unicode表情符号

Bon*_*pta 4 javascript unicode cryptojs

我正在编写一个系统,用户可以在其中编写内容(通过移动浏览器),并且"String"将使用用户选择的密码进行加密.由于经常使用unicode表情符号,因此也必须支持它们.

作为加密的lib,我选择CryptoJs - 以便加密可以在设备上本地完成.

目前,当我加密字符串并解密相同的刺痛时,所有表情符号都会消失/被随机字符替换.

var key = "123";
var content = "secret text with an emoji, ";

var encrypted = aes_encrypt(key, content); //U2FsdGVkX19IOHIt+eRkaOcmNuZrc1rkU7JepL4iNdUknzhDaLOnSjYBCklTktSe

var decrypted = aes_decrypt(key, encrypted);//secret text with an emoji, Ø<ß®
Run Code Online (Sandbox Code Playgroud)

我正在使用一对这样的辅助函数:

function aes_encrypt(key, content){
  var key_string = key + "";
  var content_string = ascii_to_hex(content) + "";
  var key_sha3 = sha3(key_string);
  var encrypted = CryptoJS.AES.encrypt(content_string, key_sha3, {
      mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.Iso10126});
  return encrypted + "";
};
Run Code Online (Sandbox Code Playgroud)

谁能告诉我我做错了什么?

小智 6

警告:正确获取加密代码非常困难.在JavaScript中可能更难,在那里你经常缺乏对执行环境的控制,并且(如下所述)缺乏语言支持导致了不一致的约定.我没有对CryptoJS库进行足够的研究来了解它的设计或安全性,或者是否在这种情况下安全地使用它.

未经专业审核,请不要依赖任何此代码真正安全.

在JavaScript中使用加密代码时的一个常见问题是,没有内置的方法来表示二进制数据.这已在现代引擎(具有类型Blobs,TypedArrays在浏览器和BuffersNode.js中)中得到解决,但仍有许多代码由于历史或兼容性原因而未利用此功能.

如果没有这些内置类型,一个常见的约定(由内置函数atobbtoa函数使用)是使用内置字符串类型来保存二进制数据.JavaScript字符串实际上是一个双字节值列表(通常包含UCS-2/UTF-16编码的Unicode字符).想要存储二进制数据的用户通常只使用较低的字节,完全忽略较高的字节.

如果您只处理与ASCII兼容的数据,那么在使用这样的代码时可能会忽略这些细节(即事情会起作用 - 但可能会产生微妙的安全后果).这是因为编码为ASCII的文本看起来与编码为UTF-16的文本相同,并且高字节被剥离.但是当你冒险超越它时,你需要做一些编码.

除了使用真正的二进制类型之外,最正确的做法是获取输入的字符串,将其编码为UTF-8,并将该数据放在输出字符串的低字节中.但是,JavaScript不提供内置函数来执行此操作.作为一个粗略但简单的替代方案,encodeURIComponent函数将任何有效的unicode字符串编码为基于UTF-8的完全URL安全字符的表示,这些字符都是ASCII兼容的.在您的代码的情况下,这将意味着这样的事情:

var key = "123";
var content = "secret text with an emoji, ";

var encrypted = aes_encrypt(key, encodeURIComponent(content));

var decrypted = decodeURIComponent(aes_decrypt(key, encrypted));
Run Code Online (Sandbox Code Playgroud)

如果您有许多非URL安全字符,这可能导致编码数据远大于必要,但它应该是安全的.此外,encodeURIComponent显然会为包含"未配对的代理字符"的字符串抛出错误.我不认为这些应该在普通输入中出现,但有人可以制作它们.

我希望在CryptoJS中有一种更正确的方法来处理这样的事情,但我不知道它.如果您计划将此代码部署以供公众使用,请考虑进一步研究.