Предупреждение. Очень сложно получить правильный криптографический код. Это может быть еще сложнее в JavaScript, где вам часто не хватает контроля над средой выполнения и (как обсуждается ниже) отсутствие языковой поддержки приводит к несогласованным соглашениям. Я недостаточно исследовал библиотеку CryptoJS, чтобы знать о ее конструкции или безопасности, а также о том, безопасно ли она используется в этом контексте.
Пожалуйста, не полагайтесь на какой-либо из этих кодов, чтобы быть действительно безопасным без профессионального аудита.
Распространенной проблемой при работе с криптографическим кодом в JavaScript было отсутствие встроенного способа представления двоичных данных. Это было решено в современных движках (с типами Blobs
и TypedArrays
в браузере и Buffers
в Node.js), но все еще есть много кода, который не использует это преимущество по историческим причинам или по причинам совместимости.
Без этих встроенных типов одно общее соглашение (используемое встроенными atob
и btoa
) заключается в использовании встроенного строкового типа для хранения двоичных данных. Строка JavaScript на самом деле представляет собой список двухбайтовых значений (обычно содержащих символы Unicode в кодировке UCS-2/UTF-16). Пользователи, желающие хранить двоичные данные, часто просто используют младший байт, полностью игнорируя старший байт.
Если вы работаете только с данными, совместимыми с 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));
Если у вас много небезопасных для URL-адресов символов, это может привести к тому, что закодированные данные будут намного больше, чем необходимо, но это должно быть безопасно. Кроме того, encodeURIComponent
, по-видимому, выдаст ошибку для строк, содержащих «непарные суррогатные символы». Я не думаю, что это должно происходить при обычном вводе, но кто-то может их создать.
Я ожидаю, что в CryptoJS есть более правильный способ обработки подобных вещей, но я о нем не знаю. Пожалуйста, подумайте об этом подробнее, если вы планируете развернуть этот код для общего пользования.
person
Jeremy
schedule
20.02.2016
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 + "";
};
- person Bonar Scripta   schedule 20.02.2016Ø<ß®
- person Mike 'Pomax' Kamermans   schedule 20.02.2016ascii_to_hex
, но содержимое несовместимо с ASCII, это полный юникод. Это может быть причиной или усилением вашей проблемы, в зависимости от того, как работает CryptoJS. Я снова предлагаю попробоватьencodeURIComponent()
иdecodeURIComponent()
, чтобы создать строку, совместимую с ASCII. (Поведение, которое наблюдает Майк, заставляет меня усомниться в безопасности модели CryptoJS — я надеюсь, что она не используется для чего-то, где требуется реальная подлинная безопасность.) - person Jeremy   schedule 20.02.2016