⬆️ ⬇️

Introduction to the libgcrypt encryption library

Good day, Habrahabr!



image In the process of writing one of my programs I needed to figure out the encryption and de-encryption of the text library. I figured it out and now I want to share my accumulated experience and knowledge with the community.



This article focuses on the libgcrypt library.



Foreword



I am writing a program under Linux. Therefore, the library was also looking for this OS. I did not try to find dozens of libraries, then to choose the best. I chose the one that fit my needs - the time that is used in fairly well-known products - two.

')

About the libgcrypt library itself



The library provides a high-level interface to low-level cryptography mechanisms. Simply put, you choose the encryption mechanism you need, invent a password and encode the text, without delving into how your chosen algorithm works.

The library is written as part of the GnuPG project and is distributed under the LGPL.



Encryption process



In the encryption process, we will use the following functions (listed in order of use):

  1. gcry_cipher_open - create a context descriptor
  2. gcry_cipher_setkey - set the password
  3. gcry_cipher_setiv - set the initialization vector
  4. gcry_cipher_encrypt - text encryption function
  5. gcry_cipher_close - closing context handle


Now more about each function.



gcry_error_t gcry_cipher_open (gcry_cipher_hd_t *hd, int algo, int mode, unsigned int flags) 


The function creates a context handle, which is required for further encryption functions and returns the handle to 'hd'. In case of an error, a non-zero error code is returned.



hd is a pointer to our future context descriptor.



algo is the algorithm we are going to use to encrypt text. Examples:

GCRY_CIPHER_IDEA - IDEA algorithm. Although you can choose it, it will not work. Since the algorithm is patented, for it there is no implementation in the free library.

GCRY_CIPHER_3DES - (Triple-DES with 3 Keys as EDE) symmetric block cipher.

GCRY_CIPHER_BLOWFISH - Blowfish algorithm. The current implementation allows you to use only a 128-bit key.

There are also RIJNDAEL, TWOFISH, AES, SERPENT and so on.

(The whole list of algorithms to find here )



mode is one of the following options:



flags - can be 0 (zero), or a combination of the following flags:



Example


 gcryError = gcry_cipher_open( &gcryCipherHd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS); 


In order to continue working with the handle, first of all we need to set the key using the gcry_cipher_setkey function.



 gcry_error_t gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *k, size_t l) 


hd - previously received handle

k - key, it is - the password (character string)

l - key length (strlen (k))



Most encryption modes require an initialization vector, which is usually a non-secret random string that acts as a salt. In the case of CTR mode, you must specify a counter, which is also similar to the value of “salt”. To set these values, use the functions:

Here we come to the key point - encryption. The encryption process itself is performed by the gcry_cipher_encrypt function.



 gcry_error_t gcry_cipher_encrypt (gcry_cipher_hd_t h, unsigned char *out, size_t outsize, const unsigned char *in, size_t inlen) 


The function can work with one or two buffers. If the in value is transmitted as NULL and inlen is 0 (zero), then encryption is performed with one buffer. In simple terms, the out buffer, in which, before calling a function, contains unencrypted text, upon exiting the function, will be rewritten with new, encrypted text. If the in value is transmitted as non-NULL, then the inlen byte is encrypted and placed in the out buffer (which must be at least inlean size). The outsize must display the size of the allocated piece of memory for the out buffer so that the function can check whether there is enough space for output. (Overlapping buffers is not allowed.)



Depending on the selected algorithm and encryption mode, the buffer length should be a multiple of the block size.



In case of successful encryption, the return code is 0 (zero). Otherwise, an error code is returned.



To free memory and handle use the gcry_cipher_close function.



 void gcry_cipher_close (gcry_cipher_hd_t h) 


This function will release the context created at runtime gcry_cipher_open. The function also overwrites all sensitive information that was created within the h descriptor with zeros.



De-encryption process



The de-encryption process is similar to the encryption process functions that need to be invoked. Namely (listed in order of use):

  1. gcry_cipher_open - create a context descriptor
  2. gcry_cipher_setkey - set the password
  3. gcry_cipher_setiv - set the initialization vector
  4. gcry_cipher_decrypt - text de-encryption function
  5. gcry_cipher_close - closing context handle


Since all functions (except gcry_cipher_decrypt) are similar, we consider only the de-encryption function itself.



 gcry_error_t gcry_cipher_decrypt (gcry_cipher_hd_t h, unsigned char *out, size_t outsize, const unsigned char *in, size_t inlen) 


h - context handle

out - the buffer where the resulting (decrypted) text will be placed

outsize - amount of allocated memory for the out buffer

in - cipher text

inlen - the size of the cipher text



Just like the encryption function, the de-encryption function can do with a single buffer. To do this, you must pass zeros instead of in and inlen. If, however, these parameters are not zero, then inlen bytes is decoded and put into the out buffer, which must be at least equal to inlen. The outsize must be set to a value equal to the number of bytes allocated for the out buffer so that the function can make sure that there is enough space for the result. (Overlap by buffer is not allowed.)



Depending on the selected algorithm and encryption mode, the buffer length should be a multiple of the block size.



If successful, the function returns 0. Otherwise, an error code is returned.



Illustrative example


 #include <stdio.h> #include <gcrypt.h> #define ENCR 1 #define DECR 0 void myCrypt(int encdec, const char * pass, const char * salt, const char * text) { gcry_error_t gcryError; gcry_cipher_hd_t hd; size_t i; size_t passLength = strlen(pass); size_t saltLength = strlen(salt); size_t textLength = strlen(text)+encdec; char * outBuffer = (char*)malloc(textLength); printf("%scryption...\n", encdec?"En":"De"); printf("passLength = %d\n", passLength); printf("saltLength = %d\n", saltLength); printf("textLength = %d\n", textLength); printf(" pass = %s\n", pass); printf(" salt = %s\n", salt); printf(" text = %s\n", encdec?text:"<null>"); //    - GCRY_CIPHER_AES128 //      //   GCRY_CIPHER_CBC_CTS,        gcryError = gcry_cipher_open(&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS); if (gcryError) { printf("gcry_cipher_open failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); return; } gcryError = gcry_cipher_setkey(hd, pass, passLength); if (gcryError) { printf("gcry_cipher_setkey failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); return; } gcryError = gcry_cipher_setiv(hd, salt, saltLength); if (gcryError) { printf("gcry_cipher_setiv failed: %s/%s\n", gcry_strsource(gcryError),gcry_strerror(gcryError)); return; } switch (encdec) { case ENCR: gcryError = gcry_cipher_encrypt(hd, outBuffer, textLength, text, textLength); break; case DECR: gcryError = gcry_cipher_decrypt(hd, outBuffer, textLength, text, textLength); } if (gcryError) { printf("gcry_cipher_encrypt failed: %s/%s\n", gcry_strsource(gcryError), gcry_strerror(gcryError)); return; } switch (encdec) { case ENCR: printf("Ecnrypted text = "); for (i = 0; i<textLength; i++) printf("%02X", (unsigned char)outBuffer[i]); printf("\n"); break; case DECR: printf("Original text = %s\n", outBuffer); } gcry_cipher_close(hd); free(outBuffer); } int main(int argc, char **argv) { if ( argc != 4 ) { printf("usage: %s <-e|-d> \"<password>\" \"<salt>\"\n", argv[0]); return 1; } int encdec = ENCR; char line[1024]; printf("Enter text: "); fgets(line, sizeof(line), stdin); if ( !strcmp(argv[1], "-d") ) { //    16    int i = 0; char a[3] = {"00"}; for (; i<strlen(line); i+=2) { sprintf(a, "%c%c", line[i], line[i+1]); line[i/2] = strtol(a, NULL, 16); } line[i/2-1] = '\0'; encdec = DECR; } myCrypt(encdec, argv[2], argv[3], line); return 0; } 


Compile for linux


gcc -o crypto main.c -lgcrypt



Run


[serge@magnum enc]$ ./crypto -e "This's my passwd" "It is kinda salt"

Enter text:

Encryption...

passLength = 16

saltLength = 16

textLength = 65

pass = This's my passwd

salt = It is kinda salt

text =

Ecnrypted text = 7DA4C2CB7088BC7432E243B1B1ACAE2A4301CE92D5884404B5AFF181EC4C1B17D3B0565FD82BD88D78916506048BA20E87FA5DDE39288FCC32CA3EF02647F7B140



[serge@magnum enc]$ ./crypto -d "This's my passwd" "It is kinda salt"

Enter text: 7DA4C2CB7088BC7432E243B1B1ACAE2A4301CE92D5884404B5AFF181EC4C1B17D3B0565FD82BD88D78916506048BA20E87FA5DDE39288FCC32CA3EF02647F7B140

Decryption...

passLength = 16

saltLength = 16

textLength = 65

pass = This's my passwd

salt = It is kinda salt

text =

Original text =




A more detailed description of the library and interface functions can be found at: http://www.gnupg.org/documentation/manuals/gcrypt

Source: https://habr.com/ru/post/120639/



All Articles