openssl evp 對稱加密(AES_ecb,ccb)php
evp.h 封裝了openssl經常使用密碼學工具,如下主要說對稱加密的接口算法
1. 以下使用 aes_256_ecb 模式的加密解密測試代碼api
unsigned char key[32] = {1}; unsigned char iv[16] = {0}; unsigned char *inStr = "this is test string"; int inLen = strlen(inStr); int encLen = 0; int outlen = 0; unsigned char encData[1024]; printf("source: %s\n",inStr); //加密 EVP_CIPHER_CTX *ctx; ctx = EVP_CIPHER_CTX_new(); EVP_CipherInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, iv, 1); EVP_CipherUpdate(ctx, encData, &outlen, inStr, inLen); encLen = outlen; EVP_CipherFinal(ctx, encData+outlen, &outlen); encLen += outlen; EVP_CIPHER_CTX_free(ctx); //解密 int decLen = 0; outlen = 0; unsigned char decData[1024]; EVP_CIPHER_CTX *ctx2; ctx2 = EVP_CIPHER_CTX_new(); EVP_CipherInit_ex(ctx2, EVP_aes_256_ecb(), NULL, key, iv, 0); EVP_CipherUpdate(ctx2, decData, &outlen, encData, encLen); decLen = outlen; EVP_CipherFinal(ctx2, decData+outlen, &outlen); decLen += outlen; EVP_CIPHER_CTX_free(ctx2); decData[decLen] = '\0'; printf("decrypt: %s\n",decData);
如上這種init,update,final的調用方式和以前 提供的哈希接口調用方式差很少ide
大體流程工具
EVP_CipherInit_ex 初始化加密使用的key,iv,算法模式,最後 一個參數,1表示加密,0表示解密測試
EVP_CipherUpdate 加密解密處理ui
EVP_CipherFinal 獲取結果this
2. 由上測試代碼中 EVP_CipherInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, iv, 1); 使用的算法模式爲 EVP_aes_256_ecb()加密
根據接口 evp.h可知其餘的對稱加密算法有以下 idea
const EVP_CIPHER *EVP_des_ecb(void); const EVP_CIPHER *EVP_des_ede(void); const EVP_CIPHER *EVP_des_ede3(void); ... const EVP_CIPHER *EVP_idea_ecb(void); const EVP_CIPHER *EVP_idea_cfb64(void); const EVP_CIPHER *EVP_idea_ofb(void); ..... const EVP_CIPHER *EVP_bf_cbc(void); const EVP_CIPHER *EVP_bf_cfb64(void); ..... const EVP_CIPHER *EVP_cast5_ecb(void); const EVP_CIPHER *EVP_cast5_cbc(void); ..... const EVP_CIPHER *EVP_aes_128_ecb(void); const EVP_CIPHER *EVP_aes_128_cbc(void); const EVP_CIPHER *EVP_aes_128_cfb1(void); ...... const EVP_CIPHER *EVP_aes_256_ecb(void); const EVP_CIPHER *EVP_aes_256_cbc(void); const EVP_CIPHER *EVP_aes_256_cfb1(void); .... const EVP_CIPHER *EVP_camellia_128_cfb1(void); const EVP_CIPHER *EVP_camellia_128_cfb8(void); const EVP_CIPHER *EVP_camellia_128_cfb128(void); ...... //以上省略表示還有不少,這裏只是列出部分
選取相應的算法對應修改上面的測試代碼便可,實現對稱加密體系中其餘算法的加密解密
3. EVP中對稱加密的主要接口有
__owur int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv); /*__owur*/ int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv); /*__owur*/ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl); /*__owur*/ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); /*__owur*/ int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); __owur int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv); /*__owur*/ int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv); /*__owur*/ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl); __owur int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl); /*__owur*/ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl); __owur int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int enc); /*__owur*/ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc); __owur int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl); __owur int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl); __owur int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
4. 上面的例子之中,我使用的是EVP_Cipher相關api處理的對稱加密
以下,咱們還能夠直接使用上面的 EVP_Encrypt,EVP_Decrypt 接口來處理加密解密
封裝加密解密
//加密 int kk_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) { EVP_CIPHER_CTX *ctx; int len; int ciphertext_len; ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len); ciphertext_len = len; EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); ciphertext_len += len; EVP_CIPHER_CTX_free(ctx); return ciphertext_len; } //解密 int kk_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx; int len; int plaintext_len; ctx = EVP_CIPHER_CTX_new(); EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len); plaintext_len = len; EVP_DecryptFinal_ex(ctx, plaintext + len, &len); plaintext_len += len; EVP_CIPHER_CTX_free(ctx); return plaintext_len; }
調用測試:
unsigned char key[32] = {8}; unsigned char iv[16] = {6}; unsigned char *plaintext = (unsigned char *)"This is Test Plain Data,This is Test Plain Data."; unsigned char ciphertext[128]; unsigned char decryptedtext[128]; int decryptedtext_len, ciphertext_len; printf("source is: \n%s\n",plaintext); //加密 ciphertext_len = kk_encrypt (plaintext, strlen ((char *)plaintext), key, iv, ciphertext); //解密 decryptedtext_len = kk_decrypt(ciphertext, ciphertext_len, key, iv, decryptedtext); decryptedtext[decryptedtext_len] = '\0'; printf("Decrypted text is:\n"); printf("%s\n", decryptedtext);
和上面第一個例子的流程差很少,修改其中的對稱體系使用的算法便可實現其餘算法處理
5. 若是不使用EVP提供的接口,固然還能夠直接使用 aes.h 提供的接口
主要接口有
/* This should be a hidden type, but EVP requires that the size be known */ struct aes_key_st { # ifdef AES_LONG unsigned long rd_key[4 * (AES_MAXNR + 1)]; # else unsigned int rd_key[4 * (AES_MAXNR + 1)]; # endif int rounds; }; typedef struct aes_key_st AES_KEY; const char *AES_options(void); int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key); void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key); void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc); void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, const int enc); void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, int *num, const int enc); void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, int *num, const int enc); void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, int *num, const int enc); void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, int *num); /* NB: the IV is _two_ blocks long */ void AES_ige_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, const int enc); /* NB: the IV is _four_ blocks long */ void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, const AES_KEY *key2, const unsigned char *ivec, const int enc); int AES_wrap_key(AES_KEY *key, const unsigned char *iv, unsigned char *out, const unsigned char *in, unsigned int inlen); int AES_unwrap_key(AES_KEY *key, const unsigned char *iv, unsigned char *out, const unsigned char *in, unsigned int inlen);
測試接口AES_encrypt,AES_decrypt
//測試1 void kk_aes_encrypt(char *inData,char *key,char *outData) { AES_KEY encKey; AES_set_encrypt_key(key, 128, &encKey); int inLen = strlen(inData); int encLen = 0; //分組加密 while (encLen <inLen) { AES_encrypt(inData, outData, &encKey); inData += AES_BLOCK_SIZE; outData+=AES_BLOCK_SIZE; encLen +=AES_BLOCK_SIZE; } } void kk_aes_decrypt(char *inData,char *key,char *outData) { AES_KEY decKey; AES_set_decrypt_key(key, 128, &decKey); int inLen = strlen(inData); int decLen = 0; //分組處理 while (decLen < inLen) { AES_decrypt(inData, outData, &decKey); inData += AES_BLOCK_SIZE; outData+=AES_BLOCK_SIZE; decLen +=AES_BLOCK_SIZE; } } //測試 void testSIMPLEAES() { char *key = "this key"; char *ins = "test str dat,test str dat,test str dat,test str dat,QQQS"; printf("src:%s\n",ins); char *encDT = malloc(strlen(ins)); kk_aes_encrypt(ins, key, encDT); char *decDT = malloc(strlen(encDT)); kk_aes_decrypt(encDT, key, decDT); printf("dec:%s\n",decDT); }
測試AES_cbc_encrypt接口
AES_KEY encKEy; unsigned char *uk = "uk123"; char encIV[AES_BLOCK_SIZE] = {0}; AES_set_encrypt_key(uk, 128, &encKEy); char *inStr = "This wiki is intended as a place for collecting, organizing, and refining useful information about OpenSSL that is currently strewn among multiple locations and formats."; char *encData = malloc(1024); AES_cbc_encrypt(inStr, encData, strlen(inStr), &encKEy, encIV, AES_ENCRYPT); printf("src:%s\n",inStr); AES_KEY decKey; AES_set_decrypt_key(uk, 128, &decKey); char decIV[AES_BLOCK_SIZE] = {0}; char *decData = malloc(1024); AES_cbc_encrypt(encData,decData, strlen(encData), &decKey, decIV, AES_DECRYPT); decData[strlen(inStr)] = '\0'; printf("dec:%s\n",decData); if (strcmp(inStr, decData)==0) { printf("PASS\n"); }
總結:EVP 提供的兩套對稱加密的接口和上篇文章提到的哈希接口調用流程上很類似;
功能很是完善。
參考:https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
測試使用openssl 1.1.0c