Libgcrypt в C возвращает 42

Я хотел бы предварить это тем, что я новичок в C и особенно использую такую ​​​​большую библиотеку, как libgcrypt, поэтому, если это что-то невероятно простое, пожалуйста, поймите.

Итак, я пытался просто зашифровать какой-то текст просто для своего рода панели запуска, и таким образом я получаю больше уверенности, прежде чем просто шифровать байты, что является одной из конечных целей этого маленького приложения, если вы хотите так его назвать. Я следил за этим, но до сих пор борюсь с тем, чтобы заставить его работать. Что меня действительно смущает, так это то, что я передаю ему выходной буфер, размер которого соответствует размеру входящего текста. Я нахожу странным, что этот сайт говорит мне сделать выходной буфер того же размера, что и вход, хотя обычно при шифровании с помощью AES выходные данные велики с точки зрения байтов. Может быть, я пропустил что-то, с чем мне может помочь кто-то более опытный, я прочитал их код по крайней мере 3-4 раза и чувствую, что это должно быть что-то очень простое, что мне здесь не хватает.

РЕДАКТИРОВАТЬ

client.c

#include "client.h"

void printGCRYPTError(gcry_error_t err) {
    if (err) {
         {
           fprintf (stderr, "Failure: %s/%s\n",
                    gcry_strsource (err),
                    gcry_strerror (err));
           fprintf (stdout, "Failure: %s/%s\n",
                    gcry_strsource (err),
                    gcry_strerror (err));
         }
    }
}

char* Encrypt(char* in, char* key, char* iv){
    size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER);
    size_t blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER);

    if(strlen(key) != keyLength) {
        printf("Invalid Key Size. Expected %zu got %lu\n", keyLength, strlen(key));
        return NULL;
    }
    if(strlen(iv) != blkLength) {
        printf("Invalid BLK/IV Size. Expected %zu got %lu\n", blkLength, strlen(iv));
        return NULL;
    }

    gcry_cipher_hd_t handle;
    gcry_error_t err = 0;

    size_t inLen = strlen(in)+1;
    char * out = malloc(inLen);

    // Open
    err = gcry_cipher_open(&handle, GCRY_CIPHER, GCRY_C_MODE, 0);
    printGCRYPTError(err);

    // Set Key
    err = gcry_cipher_setkey(handle, key, keyLength);
    printGCRYPTError(err);

    // Set IV
    err = gcry_cipher_setiv(handle, iv, blkLength);
    printGCRYPTError(err);

    // Enc
    printf("Encrypting...\n");
    err = gcry_cipher_encrypt(handle, out, inLen, in, inLen);
    printGCRYPTError(err);
    printf("Encrypted.\n");
    gcry_cipher_final(handle);


    //Out
    printf("Plaintext Message: %s\n", in);
    printf("Encrypted Message: ");
    int index = 0;
    for (index = 0; index<inLen; index++) {
        printf("%02X", (unsigned char)out[index]);
    }
    printf("\n");

    // Cleanup!
    gcry_cipher_close(handle);

    // Return
    return out;
}

char* Decrypt(char* in, char* key, char* iv){
    size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER);
    size_t blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER);

    if(strlen(key) != keyLength) {
        printf("Invalid Key Size. Expected %zu got %lu\n", keyLength, strlen(key));
        return NULL;
    }
    if(strlen(iv) != blkLength) {
        printf("Invalid BLK/IV Size. Expected %zu got %lu\n", blkLength, strlen(iv));
        return NULL;
    }

    gcry_cipher_hd_t handle;
    gcry_error_t err = 0;

    size_t inLen = strlen(in);
    char * out = malloc(inLen);

    // Open
    err = gcry_cipher_open(&handle, GCRY_CIPHER, GCRY_C_MODE, 0);
    printGCRYPTError(err);

    // Set Key
    err = gcry_cipher_setkey(handle, key, keyLength);
    printGCRYPTError(err);

    // Set IV
    err = gcry_cipher_setiv(handle, iv, blkLength);
    printGCRYPTError(err);

    // Dec
    printf("Decrypting...\n");
    err = gcry_cipher_decrypt(handle, out, inLen, in, inLen);
    printGCRYPTError(err);
    printf("Decrypted.\n");
    gcry_cipher_final(handle);

    //Out
    printf("Encrypted Message: ");
    int index = 0;
    for (index = 0; index<inLen; index++) {
        printf("%02X", (unsigned char)out[index]);
    }
    printf("\n");
    printf("Decrypted Message: %s\n", out);

    // Cleanup!
    gcry_cipher_close(handle);

    // Return
    return out;
}

int main() {
    //aesTest();
    char* encrypted = Encrypt("My test message", "sBK0hcXddz6mIKEsBK0hcXddz6mIKEAS", "sBK0uhSAUSUSHKES");
    char* decrypted = Decrypt(encrypted, "sBK0hcXddz6mIKEsBK0hcXddz6mIKEAS", "sBK0uhSAUSUSHKES");
}

Вывод в консоль

Encrypting...
Encrypted.
Plaintext Message: My test message
Encrypted Message: 153C01DD7821E5113C25D2038F3644F7
Decrypting...
Failure: gcrypt/Invalid length
Failure: gcrypt/Invalid length
Decrypted.
Encrypted Message: 0000000000001000000000000000101400
Decrypted Message: 

Спасибо, что посмотрели!


person Sean Mitchell    schedule 23.05.2019    source источник
comment
хотя обычно при шифровании с помощью AES вывод получается большим в байтах ... обычно определяют. Многие режимы AES являются потоковыми режимами работы. Вы получите это только для CBC/ECB/PCBC без кражи зашифрованного текста. Используйте режим счетчика, если вы хотите, чтобы размер зашифрованного текста соответствовал размеру ввода (в битах/байтах). Я не вижу никакой функции для вычисления выходного зашифрованного текста, предположительно gcrypt считает, что это ваша обязанность вычислять и выполнять заполнение. Это какая-то низкоуровневая библиотека шифрования, если это так. По сравнению с ними функции OpenSSL EVP будут считаться высокоуровневыми.   -  person Maarten Bodewes    schedule 23.05.2019
comment
В следующий раз, пожалуйста, не пропускайте такие вещи, как GCRY_CIPHER, где происходит ошибка и т. д.   -  person Maarten Bodewes    schedule 23.05.2019
comment
Это не было причиной ответа, и я действительно заявил, что это был AES, поэтому заполнение независимо от GCRY_CIPHER все равно было бы хорошим местом для поиска.   -  person Sean Mitchell    schedule 23.05.2019


Ответы (3)


Согласно документам для libgcrypt:

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

Поэтому я подозреваю, что вам нужно сделать две вещи:

  1. Проверьте результат кода ошибки из gcry_cipher_encrypt в соответствии с тем, как вы выполняли предыдущие вызовы функций.

  2. Вызовите gcry_cipher_final(handle) после вызова encrypt — предполагая, что вы выполняете одноразовое шифрование буфера, который меньше, чем длина блока вашего шифра.

person selbie    schedule 23.05.2019
comment
Никаких изменений, и это странно, я не получаю никаких ошибок при выполнении. - person Sean Mitchell; 23.05.2019
comment
Я должен извиниться, я думал, что он напечатал ошибку после шифрования. Моя вина. - person Sean Mitchell; 23.05.2019

Как предложил selbie, полезно проверить ошибку, возвращаемую gcry_cipher_encrypt: она говорит: "Ошибка: gcrypt/Недопустимая длина".

Основная причина, по-видимому, inLen:

size_t inLen = strlen(in);
...
err = gcry_cipher_encrypt(handle, out, inLen, in, inLen);
printGCRYPTError(err);
gcry_cipher_final(handle);

возвращает (ожидаемый?) вывод,

Message: My test message!
Encrypted Message = AEDBBB645CA54F16B5A279D77772A97B
person Trevor Keller    schedule 23.05.2019
comment
Я думал, что распечатал ошибку после шифрования. Моя вина. Со своей стороны тоже буду тестить. - person Sean Mitchell; 23.05.2019
comment
Мне нужна была прокладка. - person Sean Mitchell; 23.05.2019
comment
Еще один небольшой вопрос: если я дам вам только зашифрованный текст, сможете ли вы расшифровать его без длины открытого текста? Например, я хочу иметь возможность передавать эти данные без необходимости отправлять с ними размер открытого текста. - person Sean Mitchell; 23.05.2019

В дополнение к ключевым проблемам мне нужно было добавить дополнение к моему открытому тексту AES перед шифрованием.

person Sean Mitchell    schedule 23.05.2019