所以,我试图加密和解密一个字符串,在arch上使用libgcrypt库(版本1.8.7),此时我尝试了2种模式:CBC和GCM(不确定GCM,所以让我们先解决CBC),但同样的问题出现了。
我填充字符串,然后逐块对其进行加密。有时,顺便说一句,这会发生混乱,gcry_cipher_encrypt
函数返回错误的字节数(5、7、11...),但如果我理解正确,输出应该是 16 字节(128 位)。解密也会发生同样的事情,我以完全相同的方式逐块进行。我在整个加密或解密过程中使用相同的 GCRY 处理程序,感觉就像我真的错过了一些东西......这是一个示例,仅在 CBC 模式下加密,以便更容易找到问题。
代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gcrypt.h>
// Define cipher details
#define GCRY_CIPHER GCRY_CIPHER_AES256
#define GCRY_C_MODE GCRY_CIPHER_MODE_CBC
char * encrypt_block(gcry_cipher_hd_t handler, unsigned char * key, unsigned char * input) {
size_t key_length = 32;
size_t blk_length = 16;
// Encryption result variable
unsigned char * enc = (char *) calloc(16, sizeof(char));
// Error variable
gcry_error_t err = 0;
// Set key
err = gcry_cipher_setkey(handler, key, key_length);
if (err) {
printf("Couldn't set the key!\n%s\n%s\n", gcry_strsource(err), gcry_strerror(err));
exit(-1);
}
// Start encryption process
err = gcry_cipher_encrypt(handler, enc, blk_length, input, blk_length);
if (err) {
printf("Couldn't encrypt!\n%s\n%s\n", gcry_strsource(err), gcry_strerror(err));
exit(-1);
}
if (strlen(enc) != 16) {
printf("\n\nCORRUPTED BLOCK!\n\n");
}
// Printing the block result
printf("\nENC BLOCK:\t%d\t", strlen(enc));
for (unsigned short int i = 0; i < strlen(enc); ++i) {
printf("%X ", enc[i]);
}
printf("\n");
return enc;
}
int main() {
// Creating basic variables
unsigned char * input = (char *) calloc(2048, sizeof(char));
unsigned char * key = (char *) calloc(32, sizeof(char));
unsigned char * iv = (char *) calloc(16, sizeof(char));
// Taking user input
printf("Input (2048 max): ");
scanf(" %[^\n]", input);
printf("Key (32 max): ");
scanf(" %[^\n]", key);
printf("RAW DATA:\n\tinput: %d\t%s\n\tkey: %d\t%s\n\n", strlen(input), input, strlen(key), key);
// Create GCRY handler
gcry_cipher_hd_t handler;
gcry_error_t err = 0;
// Initialize cipher handler
err = gcry_cipher_open(&handler, GCRY_CIPHER, GCRY_C_MODE, 0);
if (err) {
printf("Couldn't initialize the cipher!\n%s\n%s\n", gcry_strsource(err), gcry_strerror(err));
exit(-1);
}
// Add padding to the input
if ((strlen(input) % 16) != 0) {
for (unsigned short int i = 0; i < (((strlen(input) / 16) * 16) - strlen(input)); ++i) {
strcat(input, "X");
}
}
// Add padding to the key
if (strlen(key) < 32) {
for (unsigned short int i = strlen(key); i < 32; ++i) {
key[i] = 0x0058;
}
}
// Generate random IV
char charset[] = "abcdefghijklmnopqrstuvwxyz0123456789";
unsigned short int iv_size = 16;
for (unsigned short int i = 0; i < iv_size; ++i) {
unsigned short int index = rand() % (unsigned short int) (sizeof charset - 1);
iv[i] = charset[index];
}
// Set the IV
err = gcry_cipher_setiv(handler, iv, 16);
if (err) {
printf("Couldn't set the IV!\n%s\n%s\n", gcry_strsource(err), gcry_strerror(err));
exit(-1);
}
printf("ENC DATA:\n\tinput: %d\t%s\n\tkey: %d\t%s\n\tiv: %d\t%s\n\n", strlen(input), input, strlen(key), key, strlen(iv), iv);
// Create encryption variables
unsigned char * input_buffer = (char *) calloc(16, sizeof(char));
unsigned char * enc_buffer = (char *) calloc(16, sizeof(char));
unsigned char * out = (char *) calloc(strlen(input), sizeof(char));
// Start encryption process block by block
for (unsigned short int i = 0; i < (strlen(input) / 16); ++i) {
// Create a new block
for (unsigned short int j = 0; j < 16; ++j) {
input_buffer[j] = input[(i * 16) + j];
}
printf("\nENC INPUT:\t%d\t%s\n", strlen(input_buffer), input_buffer);
// Check if this is a final round
if (i == ((strlen(input) / 16) - 1)) {
err = gcry_cipher_final(handler);
}
// Start encrypting the block
enc_buffer = encrypt_block(handler, key, input_buffer);
// Adding up the block to the out result
strcat(out, enc_buffer);
memset(input_buffer, 0, 16);
memset(enc_buffer, 0, 16);
}
// Print the encryption result
printf("\n\nENC RESULT:\n\t%d\n\t", strlen(out));
for (unsigned short int i = 0; i < strlen(out); ++i) {
printf("%X ", out[i]);
}
printf("\n");
gcry_cipher_close(handler);
}
输出:
Input (2048 max): This string is made for testing the program
Key (32 max): hey my password
RAW DATA:
input: 43 This string is made for testing the program
key: 15 hey my password
ENC DATA:
input: 48 This string is made for testing the programXXXXX
key: 32 hey my passwordXXXXXXXXXXXXXXXXX
iv: 16 t8jhfhkm7bo5ohxw
ENC INPUT: 16 This string is m
ENC BLOCK: 16 2 BF AA A0 1 7C A8 77 DA 4A 5A 72 29 EB FA F6
ENC INPUT: 16 ade for testing
ENC BLOCK: 16 41 BA CE 61 8A E3 F4 89 8A 46 50 2 47 5 11 A4
ENC INPUT: 16 the programXXXXX
CORRUPTED BLOCK!
ENC BLOCK: 12 AE D6 92 D2 5A AF 85 CB 57 2 1B 93
ENC RESULT:
44
2 BF AA A0 1 7C A8 77 DA 4A 5A 72 29 EB FA F6 41 BA CE 61 8A E3 F4 89 8A 46 50 2 47 5 11 A4 AE D6 92 D2 5A AF 85 CB 57 2 1B 93
我真的很抱歉这个烂摊子,只是我在这一点上发疯了,看起来解决方案很简单,但我就是无法理解。