我正在使用OpenSSL和C语言来创建加密和解密应用程序。我有一个头文件(我必须按原样使用,无法修改),这是:
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <stdint.h>
#define CSM_SYM_KEY_MAX_SIZE 1024
typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint8_t uint8;
typedef uint16 Csm_ConfigIdType;
typedef uint8 Csm_AlignType;
typedef struct Csm_SymKeyType{
uint32 length;
Csm_AlignType data[CSM_SYM_KEY_MAX_SIZE];
} Csm_SymKeyType;
typedef enum Std_ReturnType {
E_OK, /* Request successful */
E_NOT_OK, /* Request failed */
CSM_E_BUSY, /* Request failed, service is still busy */
CSM_E_SMALL_BUFFER /* The provider buffer is too small to store the result */
} Std_ReturnType;
/* Encryption functions */
Std_ReturnType Csm_SymBlockEncryptStart(Csm_ConfigIdType cfgId, Csm_SymKeyType *keyPtr);
Std_ReturnType Csm_SymBlockEncryptUpdate(Csm_ConfigIdType cfgId, const uint8 *plaintextPtr, uint32 plainTextLength,
uint8 *cipherTextPtr, uint32 *plainTextLengthPtr);
Std_ReturnType Csm_SymBlockEncryptFinish(Csm_ConfigIdType cfgId);
/* Decryption functions */
Std_ReturnType Csm_SymBlockDecryptStart(Csm_ConfigIdType cfgId, Csm_SymKeyType *keyPtr);
Std_ReturnType Csm_SymBlockDecryptUpdate(Csm_ConfigIdType cfgId, const uint8 *cipherTextPtr, uint32 cipherTextLength,
uint8 *plainTextPtr, uint32 *cipherTextLengthPtr);
Std_ReturnType Csm_SymBlockDecryptFinish(Csm_ConfigIdType cfgId);
我写的代码是:
#include "CSM_library.h"
EVP_CIPHER_CTX *ctx;
uint32 ciphertext_len;
uint32 plaintext_len;
uint32 ct_len;
uint32 pt_len;
uint8 *ciphertext;
uint8 *plaintext;
uint8 *iv;
void OPENSSL_config();
Csm_SymKeyType *keyPtr;
void handleErrors(void){
ERR_print_errors_fp(stderr);
abort();
}
void ctx_init(){
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
handleErrors();
return;
}
void ctx_finish(){
EVP_CIPHER_CTX_free(ctx);
EVP_cleanup();
return;
}
Std_ReturnType Csm_SymBlockEncryptStart(Csm_ConfigIdType cfgId, Csm_SymKeyType *keyPtr){
uint32 ret;
ct_len = 0;
ciphertext_len = 0;
ctx_init();
ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, keyPtr->data, iv);
if (ret != 1)
handleErrors();
return E_OK;
}
Std_ReturnType Csm_SymBlockEncryptUpdate(Csm_ConfigIdType cfgId, const uint8 *plainTextPtr, uint32 plainTextLength,
uint8 *cipherTextPtr, uint32 *plainTextLengthPtr){
uint32 ret;
ret = EVP_EncryptUpdate(ctx, cipherTextPtr, &ct_len, plainTextPtr, plainTextLength);
if (ret != 1)
handleErrors();
ciphertext_len = ct_len;
ciphertext = cipherTextPtr;
return E_OK;
}
Std_ReturnType Csm_SymBlockEncryptFinish(Csm_ConfigIdType cfgId){
uint32 ret;
ret = EVP_EncryptFinal_ex(ctx, ciphertext + ct_len, &ct_len);
if (ret != 1)
handleErrors();
ciphertext_len += ct_len;
ctx_finish();
return E_OK;
}
Std_ReturnType Csm_SymBlockDecryptStart(Csm_ConfigIdType cfgId, Csm_SymKeyType *keyPtr){
uint32 ret;
pt_len = 0;
plaintext_len = 0;
ctx_init();
ret = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, keyPtr->data, iv);
if (ret != 1)
handleErrors();
return E_OK;
}
Std_ReturnType Csm_SymBlockDecryptUpdate(Csm_ConfigIdType cfgId, const uint8 *cipherTextPtr, uint32 cipherTextLength,
uint8 *plainTextPtr, uint32 *cipherTextLengthPtr){
uint32 ret;
ret = EVP_DecryptUpdate(ctx, plainTextPtr, &pt_len, cipherTextPtr, cipherTextLength);
if (ret != 1)
handleErrors();
plaintext_len = pt_len;
plaintext = plainTextPtr;
return E_OK;
}
Std_ReturnType Csm_SymBlockDecryptFinish(Csm_ConfigIdType cfgId){
uint32 ret;
ret = EVP_DecryptFinal_ex(ctx, plaintext + pt_len, &pt_len);
if (ret != 1)
handleErrors();
plaintext_len += pt_len;
ctx_finish();
return E_OK;
}
int main(){
Csm_ConfigIdType cfgId;
uint32 key_size;
uint32 iv_size;
uint32 cipherTextLength;
uint32 plainTextLength;
uint32 *plainTextLengthPtr;
uint32 *cipherTextLengthPtr;
const uint8 *plainTextPtr = "In the midway of this our mortal life, I found me in a gloomy wood";
const uint8 *cipherTextPtr2;
key_size = EVP_MAX_KEY_LENGTH; //64
iv_size = 4;
plainTextLength = strlen(plainTextPtr);
plainTextLengthPtr = &plainTextLength;
uint8 cipherTextPtr[128];
uint8 plainTextPtr2[128];
uint8 key[key_size];
iv = malloc(iv_size);
/* create key and inizialization vector */
RAND_bytes(key, key_size);
RAND_bytes(iv, iv_size);
keyPtr = malloc(sizeof(Csm_SymKeyType));
if (keyPtr == NULL){
printf("malloc() fails");
exit(1);
}
keyPtr->length = key_size;
memcpy(keyPtr->data, key, key_size);
/* encryption */
Csm_SymBlockEncryptStart(cfgId, keyPtr);
Csm_SymBlockEncryptUpdate(cfgId, plainTextPtr, plainTextLength, cipherTextPtr, plainTextLengthPtr);
Csm_SymBlockEncryptFinish(cfgId);
printf("Ciphertext is:\n");
BIO_dump_fp(stdout, (const char *)cipherTextPtr, cipherTextLength);
/* decryption */
Csm_SymBlockDecryptStart(cfgId, keyPtr);
cipherTextPtr2 = cipherTextPtr;
cipherTextLength = strlen(cipherTextPtr2);
cipherTextLengthPtr = &cipherTextLength;
Csm_SymBlockDecryptUpdate(cfgId, cipherTextPtr2, cipherTextLength, plainTextPtr2, cipherTextLengthPtr);
Csm_SymBlockDecryptFinish(cfgId);
plainTextPtr2[strlen(plainTextPtr2)] = '\0';
printf("Plaintext: %s\nof length %i\n", plainTextPtr2, strlen(plainTextPtr2));
free(keyPtr);
return 0;
}
我知道代码可以写得比它好,但它只是一个试验,我只是让它在这一步工作。 加密很好,解密阶段是可变的,有时它会没有错误地进行,但解密不正确(它在最后增加了一些内容和一些换行符):
Plaintext: This is my plaintext!
x-gnu/libcrypto.
of length 48
有时它会在执行期间给我这个错误:
140614667638424:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:581:
Aborted (core dumped)
阅读错误消息我认为它与解密的块长度有关,但我一再检查函数EVP_DecryptUpdate()
和EVP_DecryptFinal()
,它们对我来说似乎很好。有人可以帮我解决这个问题吗?提前谢谢。