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

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

#include
#include
#include
#include  
#include   

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;
}

 

同时贴下java的版本:

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")));

    }
}

golang的版本:

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)]
}

你可能感兴趣的:(随手乱记)