C - совместимость с tiny-aes-c и Javascript CryptoJS - PullRequest
0 голосов
/ 10 мая 2018

Использование tiny-aes-c . Рассмотрим следующий код C:

int main(int argc, char const *argv[])
{
    uint8_t key[6] = { 's','e','c','r','e','t' };
    uint8_t iv[16]  = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };

    uint8_t in[6]  = { 'm','e','s','a','g','e'};

    uint8_t out[6] = {0x17, 0x8d, 0xc3, 0xa1, 0x56, 0x34};
    struct AES_ctx ctx;

    AES_init_ctx_iv(&ctx, key, iv);
    AES_CTR_xcrypt_buffer(&ctx, in, 6);    

    printf("idx\t encrypted\t expected");
    for(int i=0 ; i<6 ; i++){
        printf("\n[%i]\t %.2x\t\t %.2x" , i , in[i], out[i]);
    }

    return 0;
}

Код шифрует сообщение и сравнивает результаты с ожидаемым результатом. Код работает нормально, и вывод выглядит следующим образом:

idx      encrypted       expected
[0]      17              17
[1]      8d              8d
[2]      c3              c3
[3]      a1              a1
[4]      56              56
[5]      34              34

У меня есть другая служба, сервер NodeJS, который использует CryptoJS .
У меня вопрос : Как я могу преобразовать результаты C ({0x17, 0x8d, 0xc3, 0xa1, 0x56, 0x34}), чтобы они соответствовали тому, что CryptoJS мог обработать?


Edit: Развиваюсь немного. для целей данного обсуждения результат C передается по сети, поэтому его следует преобразовать в строку. Насколько я знаю, CryptoJS использует base64 в качестве входных данных для своего метода AES, расшифровывает в байты, которые позже могут быть преобразованы в обычный текст:

var bytes  = CryptoJS.AES.decrypt(BASE_64_STRING, SECRET);
var plaintext = bytes.toString(CryptoJS.enc.Utf8);

Зашифрованный результат для того же сообщения + секрет с CryptoJS: U2FsdGVkX1/TAYUIFnXzC76zb+sd8ol+2DfKCkwITfY= ( JS Fiddle ) и изменяется при каждом запуске.

Обновление 2:
Благодаря ответу @ MDTech.us_MAN я внес некоторые изменения в код JS и C, но мне все еще не хватает загадки.

C

int main(int argc, char const *argv[])
{
    uint8_t key[16] = { 's','e','c','r','e','t','s','e','c','r','e','t','1','2','3','4' };
    uint8_t iv[16]  = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
    uint8_t in[7]  = { 'm','e','s','s','a','g','e'};

    struct AES_ctx ctx;

    AES_init_ctx_iv(&ctx, key, iv);
    AES_CTR_xcrypt_buffer(&ctx, in, 7);

    printf("Encrypted: ");
    for(int i=0 ; i<7 ; i++){
        printf("%.2x" , in[i]);
    }

    return 0;
}

Вывод зашифрованной строки HEX C: cba9d5bc84113c, при преобразовании в Base64 результат: y6nVvIQRPA==

Что касается JS, я явно использую режим CTR без заполнения и запускаю (надеюсь) тот же iv, например, так:

const CryptoJS = require("crypto-js");
let iv = CryptoJS.enc.Hex.parse('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); // 16 Bytes (same as the C code)
let message = CryptoJS.AES.decrypt("y6nVvIQRPA==", "secretsecret1234", { iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
console.log(message.toString());

Дешифрованный результат: a47172dfe151c7, а не ожидаемый результат "message".

Чего мне не хватает?

Ответы [ 3 ]

0 голосов
/ 13 мая 2018

Вам следует внимательно прочитать документацию CryptoJS. По умолчанию он использует режим CBC для шифрования, поэтому вы должны изменить свою реализацию tiny-AES, чтобы использовать это.

CryptoJS поддерживает следующие режимы:

  • CBC (по умолчанию)

Также обратите внимание, что в CryptoJS по умолчанию включено заполнение, а в tiny-AES его вообще нет. Следовательно, количество сообщений должно быть кратно 16. (Или вы можете вручную использовать собственную реализацию заполнения)

Заполнение не предусмотрено, поэтому для CBC и ECB все буферы должны иметь кратные 16 байтов. Для заполнения рекомендуется PKCS7.

Затем обратите внимание, что CryptoJS автоматически выбирает вариант AES по размеру ключа:

CryptoJS поддерживает AES-128, AES-192 и AES-256. Он выберет вариант по размеру ключа, который вы передаете. Если вы используете фразу-пароль, он сгенерирует 256-битный ключ.

Итак, вы должны учитывать все эти факторы в вашем крошечном коде AES.

0 голосов
/ 13 мая 2018

Благодаря @ MDTech.us_MAN и этому вопросу о переполнении стека я нашел решение, после исправления режима и заполнения, разница была в том, как я анализировал секрет на стороне JS , В следующем примере секрет анализируется как шестнадцатеричная строка:

const CryptoJS = require("crypto-js");
let iv = CryptoJS.enc.Hex.parse('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); // 16 Bytes
let secret = CryptoJS.enc.Hex.parse('73656372657473656372657431323334'); // 16 Bytes == "secretsecret1234"
let message = CryptoJS.AES.decrypt("y6nVvIQRPA==", secret, { iv: iv, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding });
console.log(message.toString(CryptoJS.enc.Utf8)); // -> message
0 голосов
/ 10 мая 2018

Вы делаете две вещи

  1. Шифрование
  2. Преобразование в base64

После получения вы должны выполнить операции в обоих направлениях,в обратном порядке они были применены перед передачей

  1. Конвертировать из base64
  2. Расшифровать

Вы также можете поменять местами порядок шагов, но затемзаказ необходимо поменять как на передающей, так и на принимающей сторонах.

Также убедитесь, что секрет имеет одинаковый формат с обеих сторон.

...