Расшифровать 256-битное сообщение AES-CTR из браузера с помощью API-интерфейсов window.crypto.subtle

Мне нужно расшифровать в браузере сообщение, закодированное с помощью AES-CTR 256 бит (закодированное с использованием OpenSSL).

Используя OpenSSL, я получаю что-то вроде:

key=189BBBB00C5F1FB7FBA9AD9285F193D1771D7611CB891E5C1F4E24C20E50FB1D
iv =4103C88663AE12CE18EA46E894280C4D
msg=nhVKeu8zNO2PRTwJrDE=

Что ж, моя проблема заключается в преобразовании этих строк в объекты, которыми могут управлять window.crypto.subtle API. Например.

const counter = ???;
const ciphertext = ???;
const rawKey = ???;

const key = window.crypto.subtle.importKey(
    "raw",
    key,
    "AES-CTR",
    true,
    ["encrypt", "decrypt"]
);

const decrypted = await window.crypto.subtle.decrypt(
{
    name: "AES-CTR",
    counter,
    length: 64
  },
  key,
  ciphertext
);

let dec = new TextDecoder();
const msg = dec.decode(decrypted);
console.log(msg);

Может ли кто-нибудь помочь мне перейти от key, iv, msg к counter, ciphertext, rawkey?

Большое тебе спасибо


person Daniele Pallastrelli    schedule 02.04.2020    source источник


Ответы (1)


Ключ, счетчик (или IV) и зашифрованный текст могут быть переданы как TypedArray, т.е. вам нужно два преобразования, одно из шестнадцатеричного, а второе из строки, закодированной в Base64, в TypedArray, например.

из шестнадцатеричной закодированной строки, здесь:

const fromHex = hexString => new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));

из строки в кодировке Base64, здесь:

const fromBase64 = base64String => Uint8Array.from(atob(base64String), c => c.charCodeAt(0));

В самом коде отсутствует оператор await, а в функции importKey вместо key нужно использовать rawKey (вероятно, ошибки копирования/вставки). Все вместе:

const fromHex = hexString => new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
const fromBase64 = base64String => Uint8Array.from(atob(base64String), c => c.charCodeAt(0));
		
async function test(){
		
    const rawKey = fromHex("189BBBB00C5F1FB7FBA9AD9285F193D1771D7611CB891E5C1F4E24C20E50FB1D");
    const counter = fromHex("4103C88663AE12CE18EA46E894280C4D");
    const ciphertext = fromBase64("nhVKeu8zNO2PRTwJrDE=");

    const key = await window.crypto.subtle.importKey(   // add >await<
        "raw",
        rawKey,                                         // replace >key< with >rawKey<
        "AES-CTR",
        true,
        ["encrypt", "decrypt"]
    );

    const decrypted = await window.crypto.subtle.decrypt(
        {
            name: "AES-CTR",
            counter,
            length: 64
        },
        key,
        ciphertext
    );

    let dec = new TextDecoder();
    const msg = dec.decode(decrypted);
    console.log(msg);
}

test();

Это расшифровывает зашифрованный текст:

hello, world!
person user 9014097    schedule 02.04.2020
comment
Большое спасибо за ваш ответ. К сожалению, в хроме я получил ошибку: ожидание допустимо только в асинхронной функции. Однако, если я удалю ожидание (оба), я получаю: Не удалось выполнить «декодирование» для «TextDecoder»: предоставленное значение не имеет типа «(ArrayBuffer или ArrayBufferView) - person Daniele Pallastrelli; 06.04.2020
comment
await необходимо использовать в контексте функции async, см. полный код в обновленном решении. Я протестировал это решение в Chrome, и оно там работает. Пожалуйста, попробуйте это. Также обратите внимание, что async/await — это синтаксический сахар для обещаний, см., например. здесь и здесь. - person user 9014097; 06.04.2020
comment
Топако, не могли бы вы помочь мне и с этим вопросом? stackoverflow.com/questions/61096703/ - person Daniele Pallastrelli; 09.04.2020