Как закодировать текст в Base64 через UTF-16
- Введите или вставьте текст в поле Ввод · текст. В поле Кодировка уже выбрана UTF-16LE.
- Скопируйте Base64 из поля Результат · Base64. Счётчик Ввод показывает число байтов в UTF-16: для обычного английского текста оно вдвое больше длины.
- Если получатель работает с big-endian, переключите поле Кодировка на UTF-16BE.
- Поменять местами снова декодирует результат для быстрой проверки; есть и отдельный декодер, Base64 в UTF-16.
UTF-16LE и UTF-16BE
UTF-16 хранит каждый символ как одну или две 16-битные кодовые единицы. Little-endian пишет сначала младший байт, big-endian начинает со старшего. Windows и .NET используют little-endian, а кодировщик UTF-16 в Java и многие сетевые форматы используют big-endian.
| Текст | Байты UTF-16LE | Base64 UTF-16LE | Base64 UTF-16BE |
|---|---|---|---|
Hi | 48 00 69 00 | SABpAA== | AEgAaQ== |
Hello | 10 байтов | SABlAGwAbABvAA== | AEgAZQBsAGwAbw== |
€ | AC 20 | rCA= | IKw= |
👋 | 3D D8 4B DC | PdhL3A== | 2D3cSw== |
Символы за пределами базовой многоязычной плоскости (BMP), включая все эмодзи, занимают две кодовые единицы, так называемую суррогатную пару. 👋 (U+1F44B) превращается в D83D DC4B, это и есть 4 байта в последней строке.
Частые буквы A выдают Base64 от UTF-16: каждая ASCII-буква идёт в паре с нулевым байтом. Если вы видите их в строке Base64, это хороший намёк декодировать её как UTF-16.
Где используется Base64 от UTF-16
- PowerShell
-EncodedCommand.powershell -EncodedCommand RwBlAHQALQBEAGEAdABlAA==выполняетGet-Date. Частая причина, по которой такие команды не работают: скрипт закодирован в UTF-8. Инструмент PowerShell EncodedCommand добавляет префикс команды, предупреждает об ограничении длины вcmd.exeи умеет декодировать команды, найденные в логах. - Код на .NET.
Encoding.Unicodeв C# означает UTF-16LE, поэтомуConvert.ToBase64String(Encoding.Unicode.GetBytes(s))даёт тот же результат, что и эта страница. - Данные Windows. Строки из реестра, из столбцов
NVARCHAR, приведённых к binary в SQL Server, и из многих API Windows хранятся в UTF-16LE.
Метка порядка байтов
Этот инструмент не пишет метку порядка байтов (BOM), и именно этого ждут PowerShell и большинство API. Некоторые библиотеки добавляют её автоматически:
| Источник | Первые байты | Base64 от Hi |
|---|---|---|
| Этот инструмент, UTF-16LE | 48 00 | SABpAA== |
Python "Hi".encode("utf-16") | FF FE 48 00 | //5IAGkA |
Java "Hi".getBytes(UTF_16) | FE FF 00 48 | /v8ASABp |
Если ваш Base64 должен совпасть с одним из этих вариантов, кодируйте в коде с явным порядком байтов, как ниже.
UTF-16 в Base64 в коде
import base64
base64.b64encode("Get-Date".encode("utf-16-le")).decode() # 'RwBlAHQALQBEAGEAdABlAA=='
base64.b64encode("Hi".encode("utf-16-be")).decode() # 'AEgAaQ=='
// Node.js has a little-endian codec only
Buffer.from("Get-Date", "utf16le").toString("base64"); // "RwBlAHQALQBEAGEAdABlAA=="
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes('Get-Date'))
В Python используйте utf-16-le, а не utf-16, если BOM вам не нужен. Больше примеров: Python, Node.js.
Вопросы и ответы
Почему PowerShell нужен Base64 от UTF-16LE?
powershell -EncodedCommand ждёт Base64 от байтов скрипта в UTF-16LE, потому что именно так Windows хранит строки внутри. Base64 от UTF-8 декодируется в не те символы, и команда падает. Готовую командную строку соберёт инструмент PowerShell EncodedCommand.
Чем UTF-16LE отличается от UTF-16BE?
Порядком двух байтов в каждой кодовой единице. H записывается как 48 00 в little-endian и 00 48 в big-endian, поэтому Hi кодируется как SABpAA== или AEgAaQ==.
Добавляет ли кодировщик метку порядка байтов (BOM)?
Нет. В результате только байты самого текста. Кодек "utf-16" в Python и кодировка UTF_16 в Java её добавляют, поэтому их Base64 начинается с //5 или /v8.
Почему Base64 от UTF-16 такой длинный?
UTF-16 тратит минимум 2 байта на символ, так что английский текст удваивается ещё до того, как Base64 добавит свою треть. Hello в UTF-8 даёт 8 символов Base64, а в UTF-16 уже 16.