Различные шифротексты, когда я использовал инструменты командной строки OpenSSL AES и API-интерфейсы OpenSSL AES? - PullRequest
1 голос
/ 07 февраля 2012

Почему у меня были разные шифротексты, когда я использовал командные инструменты openssl aes и openssl AES apis?

Я использовал три типа шифрования:

  • Тип a) Командная строка openssltool
  • Тип b) классы в javax.cryto
  • Тип c) OpenSSL C api.

Используя типы (a) и (b), я получилтот же зашифрованный текст.Но я получил другой зашифрованный текст при использовании (c).

Я хочу получить те же самые зашифрованные тексты при использовании метода c и метода a / b.Я думаю, что что-то не так в типе c, но я не могу найти это.Обратите внимание, что я использовал ту же пару KEY, IV в вышеупомянутых трех методах.

Введите a :

openssl enc -aes-128-cbc -e -a -in pt.txt -out ct.txt -K 01010101010101010101010101010101 -iv 01010101010101010101010101010101 -p 

Введите b :
Java-код с использованием javax.crypto.Я не буду вставлять код, потому что таким образом я получил тот же зашифрованный текст с типом a.

Тип c : код C с использованием OpenSSL API:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/aes.h>

int main(int argc, char** argv) {

    AES_KEY aes;
    unsigned char key[AES_BLOCK_SIZE];        // AES_BLOCK_SIZE = 16
    unsigned char iv[AES_BLOCK_SIZE];        // init vector
    unsigned char* input_string;
    unsigned char* encrypt_string;
    unsigned char* decrypt_string;
    unsigned int len;        // encrypt length (in multiple of AES_BLOCK_SIZE)
    unsigned int i;

    // check usage
    if (argc != 2) {
        fprintf(stderr, "%s <plain text>\n", argv[0]);
        exit(-1);
    }

    // set the encryption length
    len = 0;
    if ( strlen(argv[1])>=AES_BLOCK_SIZE || 
         (strlen(argv[1]) + 1) % AES_BLOCK_SIZE == 0) {
        len = strlen(argv[1]) + 1;
    } else {
        len = ((strlen(argv[1]) + 1) / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;
    }

    // set the input string
    input_string = (unsigned char*)calloc(len, sizeof(unsigned char));
    if (input_string == NULL) {
        fprintf(stderr, "Unable to allocate memory for input_string\n");
        exit(-1);
    }
    strncpy((char*)input_string, argv[1], strlen(argv[1]));

    // Generate AES 128-bit key
    memset(key, 0x01, AES_BLOCK_SIZE);

    // Set encryption key
    memset(iv, 0x01, AES_BLOCK_SIZE);
    if (AES_set_encrypt_key(key, 128, &aes) < 0) {
        fprintf(stderr, "Unable to set encryption key in AES\n");
        exit(-1);
    }

    // alloc encrypt_string
    encrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));    
    if (encrypt_string == NULL) {
        fprintf(stderr, "Unable to allocate memory for encrypt_string\n");
        exit(-1);
    }

    // encrypt (iv will change)
    AES_cbc_encrypt(input_string, encrypt_string, len, &aes, iv, AES_ENCRYPT);

    /////////////////////////////////////

    // alloc decrypt_string
    decrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));
    if (decrypt_string == NULL) {
        fprintf(stderr, "Unable to allocate memory for decrypt_string\n");
        exit(-1);
    }

    // Set decryption key
    memset(iv, 0x01, AES_BLOCK_SIZE);
    if (AES_set_decrypt_key(key, 128, &aes) < 0) {
        fprintf(stderr, "Unable to set decryption key in AES\n");
        exit(-1);
    }

    // decrypt
    AES_cbc_encrypt(encrypt_string, decrypt_string, len, &aes, iv, 
            AES_DECRYPT);

    // print
    printf("input_string =%s\n", input_string);
    printf("encrypted string =");
    for (i=0; i<len; ++i) {
        printf("%u ", encrypt_string[i]);    
    }
    printf("\n");
    printf("decrypted string =%s\n", decrypt_string);

    return 0;
}

В чем может быть причина для разных выходов?

1 Ответ

2 голосов
/ 10 февраля 2012

В вашем коде C вы по существу используете заполнение нулями : вы выделяете область памяти, заполненную нулями (calloc), а затем копируете простой текст вэтой области, оставляя нули в конце нетронутыми.

openssl enc использует заполнение, отличное от вашего кода C.Документация для openssl enc гласит (выделено мной):

Все блочные шифры обычно используют PKCS # 5 заполнение , также известное как стандартное заполнение блоков: это позволяет выполнить элементарную проверку целостности или пароля.Однако, поскольку вероятность случайного прохождения данных по тесту выше, чем 1 из 256, это не очень хороший тест.

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

Документация для javax.crypto.Cipher (которую, я полагаю, вы использовали)говорит:

Преобразование имеет вид:

  • «алгоритм / режим / заполнение» или
  • «алгоритм»

(в последнем случае используются специфические для поставщика значения по умолчанию для режима и схема заполнения ).Например, следующее допустимое преобразование:

Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");

Так что, если вы просто используете AES или ARS/CBC без указания режима заполнения, он использует все, что находит подгонку, что вваш случай оказался таким же, как тот, который использовался OpenSSL (т. е. заполнение PKCS # 5).

Чтобы изменить вашу программу на C, вы должны будете сделать то же самое заполнение самостоятельно (по сути, это заполнение блокачисло x байтов, каждое из которых имеет то же значение, что и это число, при добавлении целого блока, заполненного 16, когда последний блок уже заполнен), или используйте EVP-функции более высокого уровня, которые должны предоставить вам способуказать режим заполнения для шифра.

...