1

I'm trying to compile the following program:

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>

#include <openssl/crypto.h>

#include <string.h>

int main (void)
{
  /* Set up the key and iv. Do I need to say to not hard code these in a
   * real application? :-)
   */

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

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

  /* Message to be encrypted */
  unsigned char *plaintext =
                (unsigned char *)"The quick brown fox jumps over the lazy dog";

  /* Buffer for ciphertext. Ensure the buffer is long enough for the
   * ciphertext which may be longer than the plaintext, dependant on the
   * algorithm and mode
   */
  unsigned char ciphertext[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);

  /* Decrypt the ciphertext */
  decryptedtext_len = decrypt(ciphertext, ciphertext_len, 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("%s\n", decryptedtext);

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

  return 0;
}


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

  /* 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_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
    handleErrors();

  /* Provide the message to be encrypted, and obtain the encrypted output.
   * EVP_EncryptUpdate can be called multiple times if necessary
   */
  if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
    handleErrors();
  ciphertext_len = len;

  /* Finalise the encryption. Further ciphertext bytes may be written at
   * this stage.
   */
  if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
  ciphertext_len += len;

  /* Clean up */
  EVP_CIPHER_CTX_free(ctx);

  return ciphertext_len;
}



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

  /* Initialise the decryption 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_256_cbc(), NULL, key, iv))
    handleErrors();

  /* Provide the message to be decrypted, and obtain the plaintext output.
   * EVP_DecryptUpdate can be called multiple times if necessary
   */
  if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
    handleErrors();
  plaintext_len = len;

  /* Finalise the decryption. Further plaintext bytes may be written at
   * this stage.
   */
  if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
  plaintext_len += len;

  /* Clean up */
  EVP_CIPHER_CTX_free(ctx);

  return plaintext_len;
}



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

This program is from https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption

Anyway, when I attempt to compile it I get the following errors:

test.c: In function âmainâ:
test.c:39:3: warning: âOPENSSL_configâ is deprecated [-Wdeprecated-declarations]
   OPENSSL_config(NULL);
   ^
In file included from /usr/local/include/openssl/crypto.h:32:0,
                 from /usr/local/include/openssl/bio.h:20,
                 from /usr/local/include/openssl/conf.h:13,
                 from test.c:1:
/usr/local/include/openssl/conf.h:92:1: note: declared here
 DEPRECATEDIN_1_1_0(void OPENSSL_config(const char *config_name))
 ^
test.c:42:20: warning: implicit declaration of function âencryptâ [-Wimplicit-function-declaration]
   ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv,
                    ^
test.c:50:23: warning: implicit declaration of function âdecryptâ [-Wimplicit-function-declaration]
   decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
                       ^
test.c: In function âencryptâ:
test.c:78:37: warning: implicit declaration of function âhandleErrorsâ [-Wimplicit-function-declaration]
   if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
                                     ^
test.c: At top level:
test.c:150:6: warning: conflicting types for âhandleErrorsâ
 void handleErrors(void)
      ^
test.c:78:37: note: previous implicit declaration of âhandleErrorsâ was here
   if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
                                     ^
/tmp/ccmG8aWM.o: In function `main':
test.c:(.text+0x47): undefined reference to `OPENSSL_init_crypto'
test.c:(.text+0x58): undefined reference to `OPENSSL_init_crypto'
test.c:(.text+0x65): undefined reference to `OPENSSL_config'
test.c:(.text+0xd1): undefined reference to `BIO_dump_fp'
/tmp/ccmG8aWM.o: In function `encrypt':
test.c:(.text+0x186): undefined reference to `EVP_CIPHER_CTX_new'
test.c:(.text+0x199): undefined reference to `EVP_aes_256_cbc'
test.c:(.text+0x1ad): undefined reference to `EVP_EncryptInit_ex'
test.c:(.text+0x1d2): undefined reference to `EVP_EncryptUpdate'
test.c:(.text+0x1ff): undefined reference to `EVP_EncryptFinal_ex'
test.c:(.text+0x21d): undefined reference to `EVP_CIPHER_CTX_free'
/tmp/ccmG8aWM.o: In function `decrypt':
test.c:(.text+0x264): undefined reference to `EVP_CIPHER_CTX_new'
test.c:(.text+0x277): undefined reference to `EVP_aes_256_cbc'
test.c:(.text+0x28b): undefined reference to `EVP_DecryptInit_ex'
test.c:(.text+0x2b0): undefined reference to `EVP_DecryptUpdate'
test.c:(.text+0x2dd): undefined reference to `EVP_DecryptFinal_ex'
test.c:(.text+0x2fb): undefined reference to `EVP_CIPHER_CTX_free'
/tmp/ccmG8aWM.o: In function `handleErrors':
test.c:(.text+0x328): undefined reference to `ERR_print_errors_fp'
collect2: error: ld returned 1 exit status

I added #include <openssl/crypto.h> to the source code since that's where https://www.openssl.org/docs/man1.1.0/crypto/OPENSSL_init_crypto.html implies that it lives and I still get the "undefined reference" errors.

Any ideas?

jww
  • 97,681
  • 90
  • 411
  • 885
neubert
  • 15,947
  • 24
  • 120
  • 212
  • Here are your duplicates for the OpenSSL link error: [How to use OpenSSL in GCC?](http://stackoverflow.com/q/1894013/608639) and [Errors that refer to a bunch of unresolved OpenSSL symbols that clearly exist?](http://stackoverflow.com/q/15318978/608639) – jww Jan 25 '17 at 01:06

1 Answers1

3

The header files you've included give you the declaration of the OpenSSL functions. However, the actual library still needs to be linked in.

When compiling, you need to add -lcrypto to the end of the gcc command line to link in the OpenSSL crypto library.

Also, you're using functions in your own code before you define them. As a result, the compiler implicitly declares them as accepting an arbitrary number of arguments and returning at int. Because this does match the actual declaration, this results in undefined behavior.

You should create declarations for each of your functions at the top of the file. That way, other functions know how to call them.

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>

#include <openssl/crypto.h>

#include <string.h>

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
  unsigned char *iv, unsigned char *ciphertext);
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
  unsigned char *iv, unsigned char *plaintext);
void handleErrors(void);

int main(void) 
{
    ...
dbush
  • 205,898
  • 23
  • 218
  • 273
  • I made the suggested changes and did `gcc -lcrypto test.c` and got the following errors back: http://pastebin.com/WKwx1NDv – neubert Jan 24 '17 at 21:09