Openssl EVP加密和解密文件 [英] Openssl EVP encryption and decryption from a file

查看:170
本文介绍了Openssl EVP加密和解密文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是使用openssl EVP进行加密和解密的示例代码.当我同时执行加密和解密时,似乎工作正常.当我在文件中写入加密的字符串并从文件中删除时,我得到了错误

encrypt.c

  #include< openssl/conf.h>#include< openssl/evp.h>#include< openssl/err.h>#include< openssl/bio.h>#include< string.h>#include< iostream>#include< fstream>#include< stdint.h>#include< assert.h>void handleErrors(void){ERR_print_errors_fp(stderr);abort();}int crypto(unsigned char * plaintext,int plaintext_len,unsigned char * key,unsigned char * iv,unsigned char *密文){EVP_CIPHER_CTX * ctx;英伦int ciphertext_len;/*创建并初始化上下文*/if(!(ctx = EVP_CIPHER_CTX_new()))handleErrors();if(1!= EVP_EncryptInit_ex(ctx,EVP_aes_256_ecb(),NULL,键,iv))handleErrors();if(1!= EVP_EncryptUpdate(ctx,密文,& len,明文,plaintext_len))handleErrors();ciphertext_len = len;if(1!= EVP_EncryptFinal_ex(ctx,密文+ len,& len))handleErrors();ciphertext_len + = len;/* 清理 */EVP_CIPHER_CTX_free(ctx);返回ciphertext_len;}int main(int argc,char * argv []){如果(argc!= 2){printf(用法:< process>< file> \ n");退出(0);}/* 256位密钥*/unsigned char * key =(unsigned char *)"key";/* 128位IV应该在加密和解密中都进行硬编码.*/unsigned char * iv =(unsigned char *)"iv";/*要加密的邮件*/无符号字符* plaintext =(未签名的字符*)密码";无符号字符密文[128],base64 [128];/*解密文本的缓冲区*/无符号字符解密文本[128];int解密文本_len,密文_len;/*初始化库*/ERR_load_crypto_strings();OpenSSL_add_all_algorithms();OPENSSL_config(NULL);/*加密明文*/ciphertext_len =加密(明文,strlen((char *)明文),密钥,iv,密文);/*在这里对密文做一些有用的事情*/printf(密文为:\ n");BIO_dump_fp(stdout,(const char *)密文,ciphertext_len);printf(%d%s \ n",ciphertext_len,密文);int encode_str_size = EVP_EncodeBlock(base64,密文,ciphertext_len);printf(%d%s \ n",encode_str_size,base64);std :: ofstream outFile(argv [1]);outFile<<base64;outFile.close();/* 清理 */EVP_cleanup();ERR_free_strings();返回0;} 

decrypt.c

  #include< openssl/conf.h>#include< openssl/evp.h>#include< openssl/err.h>#include< string.h>#include< iostream>#include< fstream>使用命名空间std;void handleErrors(void){ERR_print_errors_fp(stderr);abort();}int解密(unsigned char *密文,int ciphertext_len,unsigned char * key,unsigned char * iv,unsigned char * plaintext){EVP_CIPHER_CTX * ctx;英伦int plaintext_len;/*创建并初始化上下文*/if(!(ctx = EVP_CIPHER_CTX_new()))handleErrors();if(1!= EVP_DecryptInit_ex(ctx,EVP_aes_256_ecb(),NULL,密钥,iv))handleErrors();if(1!= EVP_DecryptUpdate(ctx,明文,& len,密文,ciphertext_len))handleErrors();plaintext_len = len;if(1!= EVP_DecryptFinal_ex(ctx,明文+ len,& len))handleErrors();plaintext_len + = len;/* 清理 */EVP_CIPHER_CTX_free(ctx);返回plaintext_len;}int main(int argc,char * argv []){如果(argc!= 2){printf(用法:< process>< file> \ n");退出(0);}/* 256位密钥*/unsigned char * key =(unsigned char *)"key";/* 128位IV */unsigned char * iv =(unsigned char *)"iv";unsigned char ciphertext [128] =",base64_in [128] =",base64_out [128] =";/*解密文本的缓冲区*/unsigned char cryptoedtext [128] =";int解密文本_len,密文_len;/*初始化库*/ERR_load_crypto_strings();OpenSSL_add_all_algorithms();OPENSSL_config(NULL);/*加密明文*/char fileBuffer [128] =";ifstream infile(argv [1],ios :: binary);infile.getline(fileBuffer,sizeof(fileBuffer));infile.close();strcpy((char *)base64_in,fileBuffer);ciphertext_len =(strlen(reinterpret_cast< const char *>(base64_in)));;printf(%d%s \ n",密文_len,base64_in);int长度= EVP_DecodeBlock(base64_out,base64_in,ciphertext_len);while(base64_in [-ciphertext_len] =='=')长度-;printf(%d%s \ n",length,base64_out);BIO_dump_fp(stdout,(const char *)base64_out,长度);decryptedtext_len =解密(base64_out,长度,密钥,iv,解密文本);/*添加一个NULL终止符.我们期待可打印的文本*/decryptedtext [decryptedtext_len] ='\ 0';/*显示解密的文本*/printf(解密后的文本是:\ n");printf(%d%s \ n",unlockedtext_len,decryptedtext);/* 清理 */EVP_cleanup();ERR_free_strings();返回0;} 

输出

  ./加密文件密文是:0000-52 6f a3 c6 6b ea 4a aa-a5 e8 9d 26 47 dc e9 b7 Ro..k.J ....& G ...16Ro  k J    &G H t.24个Um + jxmvqSqql6J0mR9zptw ==./解密文件24个Um + jxmvqSqql6J0mR9zptw ==16Ro  k J    &G0000-52 6f a3 c6 6b ea 4a aa-a5 e8 9d 26 47 dc e9 b7 Ro..k.J ....& G ...140405999580856:错误:06065064:数字信封例程:EVP_DecryptFinal_ex:错误的解密:evp_enc.c:529:中止(核心已弃用) 

核心

 核心是由"./decrypt file"生成的.程序以信号SIGABRT终止,异常终止.__GI_raise中的#0 0x00007efe46356428(sig = sig @ entry = 6)在../sysdeps/unix/sysv/linux/raise.c:5454 ../sysdeps/unix/sysv/linux/raise.c:无此类文件或目录.(gdb)bt__GI_raise中的#0 0x00007efe46356428(sig = sig @ entry = 6)在../sysdeps/unix/sysv/linux/raise.c:54__GI_abort()中的#1 0x00007efe4635802a在abort.c:89#2 0x000000000040110e在handleErrors()()中#3 0x00000000004011eb in解密(unsigned char *,int,unsigned char *,unsigned char *,unsigned char *)()#4 0x0000000000401485在main()中 

当我写入文件并从文件中读取内容时,我无法解密.

解决方案

传递给 EVP_EncryptInit_ex EVP_DecryptInit_ex 的密钥和IV不是字符串,而是固定大小的字符数组取决于密码.

对于AES 256,密钥为32字节(256位),IV的长度为16字节(128位).您传入的字符串常量不够长,无法满足这些约束.结果,上述函数读取了这些字符串的末尾,从而调用了未定义的行为./p>

关于最可能发生的情况,当您在同一程序中进行加密和解密时,它起作用的原因是因为您可能要将包含密钥和IV的相同缓冲区传递给这两个函数都一样,因此在每个字符串的末尾都读取相同的一组未知字节.然后,当您在两个不同的程序中执行相同操作时,未知数据将有所不同,因此您实际上拥有两组不同的key和IV.

声明密钥和IV为固定大小,并同时初始化两者.任何未显式初始化的字节都将设置为0,因此您将拥有已知数量.

  unsigned char key [32] =(unsigned char *)"key";unsigned char iv [16] =(unsigned char *)"iv"; 

Here is a sample code for encryption and decrption using openssl EVP. when i perform both encryption and decryption it seems to work fine. When i write the encryted string in file and decript from file i am getting error

encrypt.c

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <stdint.h>
#include <assert.h>

void handleErrors(void)
{
  ERR_print_errors_fp(stderr);
  abort();
}

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

  /* Create and initialise the context */
  if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

  if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, iv))
    handleErrors();

  if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
    handleErrors();
  ciphertext_len = len;

  if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
  ciphertext_len += len;

  /* Clean up */
  EVP_CIPHER_CTX_free(ctx);

  return ciphertext_len;
}

int main (int argc, char *argv[])
{
  if ( argc != 2 )
    {
        printf("Usage: <process> <file>\n");
        exit(0);
    }
  /* A 256 bit key */
  unsigned char *key = (unsigned char *) "key";

  /* A 128 bit IV  Should be hardcoded in both encrypt and decrypt. */
  unsigned char *iv = (unsigned char *)"iv";

  /* Message to be encrypted */
  unsigned char *plaintext =
                (unsigned char *)"Password";

  unsigned char ciphertext[128],base64[128];

  /* Buffer for the decrypted text */
  unsigned char decryptedtext[128];

  int decryptedtext_len, ciphertext_len;

  /* Initialise the library */
  ERR_load_crypto_strings();
  OpenSSL_add_all_algorithms();
  OPENSSL_config(NULL);

  /* Encrypt the plaintext */
  ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv,
                            ciphertext);

  /* Do something useful with the ciphertext here */
  printf("Ciphertext is:\n");
  BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);

  printf("%d %s\n", ciphertext_len, ciphertext);
  int encode_str_size = EVP_EncodeBlock(base64, ciphertext, ciphertext_len);
    printf("%d %s\n", encode_str_size, base64);

  std::ofstream outFile (argv[1]);
  outFile << base64;
  outFile.close();

  /* Clean up */
  EVP_cleanup();
  ERR_free_strings();

  return 0;
}

decrypt.c

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
#include <iostream>
#include <fstream>
using namespace std;

void handleErrors(void)
{
  ERR_print_errors_fp(stderr);
  abort();
}

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

  /* Create and initialise the context */
  if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

  if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, iv))
    handleErrors();

  if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
    handleErrors();
  plaintext_len = len;

  if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
  plaintext_len += len;

  /* Clean up */
  EVP_CIPHER_CTX_free(ctx);

  return plaintext_len;
}

int main (int argc, char *argv[])
{
  if ( argc != 2 )
        {
                printf("Usage: <process> <file>\n");
                exit(0);
        }

  /* A 256 bit key */
  unsigned char *key = (unsigned char *)"key";

  /* A 128 bit IV */
  unsigned char *iv = (unsigned char *)"iv";

  unsigned char ciphertext[128] = "", base64_in[128] = "", base64_out[128] = "";

  /* Buffer for the decrypted text */
  unsigned char decryptedtext[128]="";

  int decryptedtext_len, ciphertext_len;

  /* Initialise the library */
  ERR_load_crypto_strings();
  OpenSSL_add_all_algorithms();
  OPENSSL_config(NULL);

  /* Encrypt the plaintext */
  char fileBuffer[128] = "";
  ifstream infile (argv[1], ios::binary);
  infile.getline(fileBuffer, sizeof(fileBuffer));
  infile.close(); 

  strcpy((char *)base64_in, fileBuffer);
  ciphertext_len =  (strlen(reinterpret_cast<const char *>(base64_in)));
  printf("%d %s\n",ciphertext_len, base64_in);

  int length = EVP_DecodeBlock(base64_out, base64_in, ciphertext_len);
  while(base64_in[--ciphertext_len] == '=') length--;
  printf("%d %s\n", length,base64_out);

  BIO_dump_fp (stdout, (const char *)base64_out, length);

  decryptedtext_len = decrypt(base64_out, length, key, iv,
   decryptedtext);

  /* Add a NULL terminator. We are expecting printable text */
  decryptedtext[decryptedtext_len] = '\0';

  /* Show the decrypted text */
  printf("Decrypted text is:\n");
  printf("%d %s\n", decryptedtext_len ,decryptedtext);

  /* Clean up */
  EVP_cleanup();
  ERR_free_strings();

  return 0;
}

output

./encrypt file
Ciphertext is:
0000 - 52 6f a3 c6 6b ea 4a aa-a5 e8 9d 26 47 dc e9 b7   Ro..k.J....&G...
16 Ro��k�J����&G�鷈H�t�
24 Um+jxmvqSqql6J0mR9zptw==

./decrypt file
24 Um+jxmvqSqql6J0mR9zptw==
16 Ro��k�J����&G���
0000 - 52 6f a3 c6 6b ea 4a aa-a5 e8 9d 26 47 dc e9 b7   Ro..k.J....&G...
140405999580856:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:529:
Aborted (core dumped)

core

Core was generated by `./decrypt file'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007efe46356428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007efe46356428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007efe4635802a in __GI_abort () at abort.c:89
#2  0x000000000040110e in handleErrors() ()
#3  0x00000000004011eb in decrypt(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*) ()
#4  0x0000000000401485 in main ()

When i write to a file and read the contents from a file i am not able to decrypt.

解决方案

The key and IV passed to EVP_EncryptInit_ex and EVP_DecryptInit_ex are not strings but character arrays of a fixed size depending on the cipher.

In the case of AES 256, the key is 32 bytes (256 bits) and the IV 16 bytes (128 bits) in length. The string constants you pass in are not long enough to satisfy those constraints. As a result, the above functions read past the end of those strings, invoking undefined behavior.

As to what is most likely happening, the reason it works when you do the encryption and decryption from within the same program is because you're probably passing the same buffer containing the key and IV to both functions, so both read the same set of unknown bytes after the end of each string. When you then do the same in two different programs this unknown data is different, so you effectively has two different sets of key and IV.

Declare your key and IV to be a fixed size and initialize both. Any bytes not explicitly initialized will be set to 0, so you'll have known quantities.

unsigned char key[32] = (unsigned char *) "key";
unsigned char iv[16] = (unsigned char *)"iv";

这篇关于Openssl EVP加密和解密文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆