C代码使用openssl库实现AES-128-CBC-PKCS5padding加密解密

it2022-05-09  23

刚刚帮小伙伴实现了这个(已经和java对接正常),貌似网上没有好用的C实现,贴到这里吧,希望可以帮助到有需要的人。

<code>

#include <openssl/aes.h> #include <openssl/evp.h> #include <openssl/err.h> #include <openssl/bio.h>   #include <openssl/buffer.h>   

char * base64Encode(const char *buffer, int length, int newLine); char * base64Decode(char *input, int length, int newLine);

void handleOpenSSLErrors(void) {     unsigned long errCode;

    printf("An error occurred\n");     while(errCode = ERR_get_error()) {         char *err = ERR_error_string(errCode, NULL);         printf("%s\n", err);     }     //abort(); } /* AES_CBC_PKCS5_BASE64_Encrypt * 入参: * src:明文 * srcLen:明文长度 * key:密钥 长度只能是16/24/32字节 否则OPENSSL会对key进行截取或PKCS0填充 * keyLen:密钥长度 * outLen:密文base64后长度 * 返回值: 密文base64后的字符串,使用后请free

   //todo:EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc() ...中的EVP_aes_128_cbc 目前硬编码后续可以优化 */ #define AES_BLOCK_SIZE 16 unsigned char *AES_CBC_PKCS5_BASE64_Encrypt(unsigned char *src, int srcLen, unsigned char *key, int keyLen, int *outLen, unsigned char *iv) {     EVP_CIPHER_CTX *ctx = NULL;     char * res = NULL;     int blockCount = 0;     int quotient = srcLen / AES_BLOCK_SIZE;     int mod = srcLen % AES_BLOCK_SIZE;     blockCount = quotient + 1;

    int padding = AES_BLOCK_SIZE - mod;     char *in = (char *)malloc(AES_BLOCK_SIZE*blockCount);     memset(in, padding, AES_BLOCK_SIZE*blockCount);     memcpy(in, src, srcLen);

    //out     char *out = (char *)malloc(AES_BLOCK_SIZE*blockCount);     memset(out, 0x00, AES_BLOCK_SIZE*blockCount);     *outLen = AES_BLOCK_SIZE*blockCount;          do {         if(!(ctx = EVP_CIPHER_CTX_new())) {             handleOpenSSLErrors();             break;         }                  if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)) {             handleOpenSSLErrors();             break;         }                      if(1 != EVP_EncryptUpdate(ctx, (unsigned char*)out, outLen, in, AES_BLOCK_SIZE*blockCount)) {             handleOpenSSLErrors();                 break;         }         res = base64Encode(out, *outLen, 0);     }while(0);          free(in);     free(out);     if (ctx != NULL)         EVP_CIPHER_CTX_free(ctx);

    return (unsigned char*)res; }

/* AES_CBC_PKCS5_Decrypt * 入参: * src:base64编码后的密文 * srcLen:密文长度 * key:密钥 长度只能是16/24/32字节 否则OPENSSL会对key进行截取或PKCS0填充 * keyLen:密钥长度 * outLen:明文长度 * 返回值: 明文 需要free */ unsigned char *AES_CBC_PKCS5_BASE64_Decrypt(unsigned char *src, int srcLen, unsigned char *key, int keyLen, int *outLen, unsigned char *iv) {     EVP_CIPHER_CTX *ctx = NULL;     char *in = base64Decode(src, srcLen, 0);     char *out = (char*)malloc(srcLen);     do {         /* Create and initialise the context */         if(!(ctx = EVP_CIPHER_CTX_new())) {             handleOpenSSLErrors();             break;         }

        /* Initialise the encryption operation. IMPORTANT - ensure you use a key         * and IV size appropriate for your cipher         * In this example we are using 256 bit AES (i.e. a 256 bit key). The         * IV size for *most* modes is the same as the block size. For AES this         * is 128 bits */         if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)) {             handleOpenSSLErrors();             break;         }                  if(1 != EVP_DecryptUpdate(ctx, out, outLen, in, srcLen*3/4)) {             handleOpenSSLErrors();             break;         }     }while(0);     free(in);     if (ctx != NULL)         EVP_CIPHER_CTX_free(ctx);          //PKCS5 UNPADDING     int unpadding = out[*outLen - 1];     *outLen = *outLen - unpadding;     out[*outLen] = '\0';     return (unsigned char*)out; }

int main(int argc, char *argv[]) {     int outLen = 0;     char *res = AES_CBC_PKCS5_BASE64_Encrypt(argv[1], strlen(argv[1]), "7854156156611111", 16, &outLen, "0000000000000000");     printf("the result[%s]\r\n", res);     char *res2 = AES_CBC_PKCS5_BASE64_Decrypt(res, strlen(res), "7854156156611111", 16, &outLen, "0000000000000000");     printf("the org[%s] \r\n", res2); }

// base64 编码 char * base64Encode(const char *buffer, int length, int newLine) {     BIO *bmem = NULL;     BIO *b64 = NULL;     BUF_MEM *bptr;

    b64 = BIO_new(BIO_f_base64());     if (!newLine) {         BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);     }     bmem = BIO_new(BIO_s_mem());     b64 = BIO_push(b64, bmem);     BIO_write(b64, buffer, length);     BIO_flush(b64);     BIO_get_mem_ptr(b64, &bptr);     BIO_set_close(b64, BIO_NOCLOSE);

    char *buff = (char *)malloc(bptr->length + 1);     memcpy(buff, bptr->data, bptr->length);     buff[bptr->length] = 0;     BIO_free_all(b64);

    return buff; }

// base64 解码 char * base64Decode(char *input, int length, int newLine) {     BIO *b64 = NULL;     BIO *bmem = NULL;     char *buffer = (char *)malloc(length);     memset(buffer, 0, length);     b64 = BIO_new(BIO_f_base64());     if (!newLine) {         BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);     }     bmem = BIO_new_mem_buf(input, length);     bmem = BIO_push(b64, bmem);     BIO_read(bmem, buffer, length);     BIO_free_all(bmem);

    return buffer; }

</code>

 

同时贴下java的版本:

<code>

import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec;

import java.util.Base64;

public class Main {     public static String encrypt(String key, String initVector, String value) {         try {             IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));             SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");             cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

            byte[] encrypted = cipher.doFinal(value.getBytes());             System.out.println("encrypted string: " + Base64.getEncoder().encodeToString(encrypted));

            return Base64.getEncoder().encodeToString(encrypted);         } catch (Exception ex) {             ex.printStackTrace();         }

        return null;     }

    public static String decrypt(String key, String initVector, String encrypted) {         try {             IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));             SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");             cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

            byte[] original = cipher.doFinal(Base64.getDecoder().decode(encrypted));

            return new String(original);         } catch (Exception ex) {             ex.printStackTrace();         }

        return null;     }

    public static void main(String[] args)  {

        String key = "7854156156611111";         String initVector = "0000000000000000"; // 16 bytes IV

        System.out.println(decrypt(key, initVector, encrypt(key, initVector, "test1111111111111111111111111111111111111111111111111111111111lkjflajfldkjasldfkjalhzlclz1xxxxxxxxxxxxxxxxxx")));

    } }

</code>

golang的版本:

<code>

package main import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "fmt" ) const ( key = "7854156156611111" iv = "0000000000000000" ) func main() { str := "test1234" es, _ := AesEncrypt(str, []byte(key)) fmt.Println(es) ds, _ := AesDecrypt(es, []byte(key)) fmt.Println(string(ds)) } func AesEncrypt(encodeStr string, key []byte) (string, error) { encodeBytes := []byte(encodeStr) //根据key 生成密文 block, err := aes.NewCipher(key) if err != nil { return "", err } blockSize := block.BlockSize() encodeBytes = PKCS5Padding(encodeBytes, blockSize) blockMode := cipher.NewCBCEncrypter(block, []byte(iv)) crypted := make([]byte, len(encodeBytes)) blockMode.CryptBlocks(crypted, encodeBytes) return base64.StdEncoding.EncodeToString(crypted), nil } func PKCS5Padding(ciphertext []byte, blockSize int) []byte { padding := blockSize - len(ciphertext)%blockSize //填充 padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } func AesDecrypt(decodeStr string, key []byte) ([]byte, error) { //先解密base64 decodeBytes, err := base64.StdEncoding.DecodeString(decodeStr) if err != nil { return nil, err } block, err := aes.NewCipher(key) if err != nil { return nil, err } blockMode := cipher.NewCBCDecrypter(block, []byte(iv)) origData := make([]byte, len(decodeBytes)) blockMode.CryptBlocks(origData, decodeBytes) origData = PKCS5UnPadding(origData) return origData, nil } func PKCS5UnPadding(origData []byte) []byte { length := len(origData) unpadding := int(origData[length-1]) return origData[:(length - unpadding)] }

</code>


最新回复(0)