В Stanford JavaScript Crypto Library (SJCL) вся криптографическая
обработка опирается на внутренний формат данных — bitArray.
Это не строки, не байты и не привычные массивы Uint8Array,
а структурированное представление битов, оптимизированное для
криптографических операций.
Ключевая особенность SJCL: любые входные данные перед вычислениями
приводятся к bitArray, а любые выходные — обратно в удобный
формат (hex, base64, строки).
bitArray — это массив 32-битных слов с дополнительным
элементом длины в битах.
Структура:
arr[0] ... arr[n] — 32-битные числаПример:
var ba = [0x61626300, 24];
Это строка "abc" в виде битов (3 байта = 24 бита).
Для работы со строками используется UTF-8 кодек:
var sjcl = require('sjcl');
var text = "hello";
var bits = sjcl.codec.utf8String.toBits(text);
var original = sjcl.codec.utf8String.fromBits(bits);
Важно учитывать:
Hex — один из самых популярных форматов для криптографии.
var bits = sjcl.codec.utf8String.toBits("hello");
var hex = sjcl.codec.hex.fromBits(bits);
console.log(hex);
Результат:
68656c6c6f
var bits = sjcl.codec.hex.toBits("68656c6c6f");
var text = sjcl.codec.utf8String.fromBits(bits);
console.log(text); // hello
Base64 часто используется для передачи бинарных данных через текстовые протоколы.
var bits = sjcl.codec.utf8String.toBits("hello");
var b64 = sjcl.codec.base64.fromBits(bits);
console.log(b64);
Результат:
aGVsbG8=
var bits = sjcl.codec.base64.toBits("aGVsbG8=");
var text = sjcl.codec.utf8String.fromBits(bits);
console.log(text);
SJCL поддерживает два режима base64:
= padding)Настройка:
sjcl.codec.base64._padchar = "=";
Поскольку обе кодировки работают через bitArray,
конвертация происходит через промежуточное представление:
var bits = sjcl.codec.hex.toBits("68656c6c6f");
var b64 = sjcl.codec.base64.fromBits(bits);
var bits = sjcl.codec.base64.toBits("aGVsbG8=");
var hex = sjcl.codec.hex.fromBits(bits);
SJCL не использует Uint8Array напрямую, но часто
требуется взаимодействие.
function bytesToBits(bytes) {
var out = [];
var i, tmp = 0;
for (i = 0; i < bytes.length; i++) {
tmp = tmp << 8 | bytes[i];
if ((i & 3) === 3) {
out.push(tmp);
tmp = 0;
}
}
if (i & 3) {
tmp = tmp << (8 * (4 - (i & 3)));
out.push(tmp);
}
out.push(bytes.length * 8);
return out;
}
function bitsToBytes(arr) {
var len = arr[arr.length - 1];
var out = [];
var i, j = 0;
for (i = 0; i < len; i += 8) {
var word = arr[i >> 5];
out.push((word >> (24 - (i % 32))) & 0xFF);
}
return new Uint8Array(out);
}
Все кодеки в SJCL следуют одному принципу:
string | hex | base64bitArraybitArraystring / hex / base64
↓
bitArray
↓
string / hex / base64
UTF-8 кодек SJCL строго следует стандарту, но важно учитывать:
Пример проблемного символа:
var text = "?"; // редкий Unicode символ
var bits = sjcl.codec.utf8String.toBits(text);
var back = sjcl.codec.utf8String.fromBits(bits);
Hex часто используют для визуальной проверки данных:
var data = "Crypto";
var bits = sjcl.codec.utf8String.toBits(data);
var hex = sjcl.codec.hex.fromBits(bits);
console.log(hex);
Вывод:
43727970746f
Каждая пара символов — один байт.
Base64 в SJCL особенно удобен для:
Пример:
var key = sjcl.codec.utf8String.toBits("secret-key");
var encoded = sjcl.codec.base64.fromBits(key);
sjcl.codec.hex.toBits("hello"); // ошибка
hex принимает только корректные шестнадцатеричные строки.
Если вручную модифицировать массив и забыть последний элемент:
arr.push(length);
SJCL не сможет корректно декодировать данные.
sjcl.codec.base64.toBits("!!!");
приведёт к исключению.
var sjcl = require("sjcl");
var input = "cryptographic data";
// string → bitArray
var bits = sjcl.codec.utf8String.toBits(input);
// bitArray → hex
var hex = sjcl.codec.hex.fromBits(bits);
// hex → bitArray
var bits2 = sjcl.codec.hex.toBits(hex);
// bitArray → base64
var b64 = sjcl.codec.base64.fromBits(bits2);
// base64 → string
var output = sjcl.codec.utf8String.fromBits(
sjcl.codec.base64.toBits(b64)
);
console.log(input);
console.log(hex);
console.log(b64);
console.log(output);
Причины архитектурные: