Java AES算法和UNIX下OpenSSL之间的加解密

关于加解密的问题在网上搜索了很多资料,用Java AES和UNIX下OpenSSL各自加解密都没什么问题,但是如果要JAVA AES算法的加密文件发送到UNIX下openssl解密,或者UNIX OpenSSL加密的文件发给JAVA AES算法解密可就没那么容易了。大家可以先看看  。这篇文章已经讲的很清楚了,我也是通过这篇文章实现加解密的,我主要讲一下在UNIX下openssl加解密编译时链接库的问题,也就是makefile的编写,由于对makefile不太熟悉,所以还是研究了老半天才解决问题,希望碰到跟我遇到一样的问题也能够解决。

我先贴出源码:

aes.c:

/**
  build with shell:
  gcc -Wall aes.c -lcrypto -o aes
**/
   
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
 
void encrypt(unsigned char* in, int inl, unsigned char *out, int* len, unsigned char * key){
    unsigned char iv[8];
    EVP_CIPHER_CTX ctx;
    //此init做的仅是将ctx内存 memset为0 
    EVP_CIPHER_CTX_init(&ctx);
 
    //cipher  = EVP_aes_128_ecb(); 
    //原型为int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv)   
    //另外对于ecb电子密码本模式来说,各分组独立加解密,前后没有关系,也用不着iv 
    EVP_EncryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, key, iv); 
 
    *len = 0;
    int outl = 0;
    //这个EVP_EncryptUpdate的实现实际就是将in按照inl的长度去加密,实现会取得该cipher的块大小(对aes_128来说是16字节)并将block-size的整数倍去加密。
    //如果输入为50字节,则此处仅加密48字节,outl也为48字节。输入in中的最后两字节拷贝到ctx->buf缓存起来。 
    //对于inl为block_size整数倍的情形,且ctx->buf并没有以前遗留的数据时则直接加解密操作,省去很多后续工作。 
    EVP_EncryptUpdate(&ctx, out+*len, &outl, in+*len, inl);
    *len+=outl;
    //余下最后n字节。此处进行处理。
    //如果不支持pading,且还有数据的话就出错,否则,将block_size-待处理字节数个数个字节设置为此个数的值,如block_size=16,数据长度为4,则将后面的12字节设置为16-4=12,补齐为一个分组后加密 
    //对于前面为整分组时,如输入数据为16字节,最后再调用此Final时,不过是对16个0进行加密,此密文不用即可,也根本用不着调一下这Final。
    int test = inl>>4;
    if(inl != test<<4){
        EVP_EncryptFinal_ex(&ctx,out+*len,&outl); 
        *len+=outl;
    }
    EVP_CIPHER_CTX_cleanup(&ctx);
}
 
 
void decrypt(unsigned char* in, int inl, unsigned char *out, unsigned char *key){
    unsigned char iv[8];
    EVP_CIPHER_CTX ctx;
    //此init做的仅是将ctx内存 memset为0 
    EVP_CIPHER_CTX_init(&ctx);
 
    //cipher  = EVP_aes_128_ecb(); 
    //原型为int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv)   
    //另外对于ecb电子密码本模式来说,各分组独立加解密,前后没有关系,也用不着iv 
    EVP_DecryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, key, iv); 
    int len = 0;
    int outl = 0;
 
    EVP_DecryptUpdate(&ctx, out+len, &outl, in+len, inl);
    len += outl;
       
    EVP_DecryptFinal_ex(&ctx, out+len, &outl); 
    len+=outl;
    out[len]=0;
    EVP_CIPHER_CTX_cleanup(&ctx);
}
int main(int argc, char **argv)
{
    unsigned char content[400];
    unsigned char key[] = "HelloWorld";
     
    unsigned char en[400],de[400],base64[400], base64_out[400];
    int len; 
    memset(content, 0,400);
    memset(en, 0, 400);
    memset(de, 0, 400);
    memset(base64, 0,400);
    memset(base64_out, 0, 400);
    strcpy(content, "HelloHbnfjkwahgruiep");
     
    printf("%d %s\n", strlen((const char*)content), content);
    encrypt(content,strlen((const char*)content), en, &len, key);
     
    int encode_str_size = EVP_EncodeBlock(base64, en, len);
    printf("%d %s\n", encode_str_size, base64);
     
    int length = EVP_DecodeBlock(base64_out, base64, strlen((const char*)base64));
    //EVP_DecodeBlock内部同样调用EVP_DecodeInit + EVP_DecodeUpdate + Evp_DecodeFinal实现,但是并未处理尾部的'='字符,因此结果字符串长度总是为3的倍数
    while(base64[--encode_str_size] == '=') length--;
     
    decrypt(base64_out, length, de, key);
    printf("%d %s\n", strlen((const char*)de), de);
    return 0;
}

makefile

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/7be7e22c96e9147b2d442eaf0457d071.html