Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
=> Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Linux Kernel 2.6...5164 
 Trees...935 
 Максвелл 3...861 
 Go Web ...814 
 William Gropp...795 
 Ethreal 3...779 
 Ethreal 4...766 
 Gary V.Vaughan-> Libtool...764 
 Rodriguez 6...755 
 Steve Pate 1...748 
 Clickhouse...748 
 Ext4 FS...748 
 Ethreal 1...736 
 Secure Programming for Li...720 
 C++ Patterns 3...711 
 Ulrich Drepper...693 
 Assembler...687 
 DevFS...655 
 Стивенс 9...644 
 MySQL & PosgreSQL...621 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

Шифрование с использованием библиотек OpenSSL

By Vinayak Hegde

О чем эта статья

Линукс уже сделал свои первые уверенные шаги в корпоративном мире . Одним из требований этого мира является защита данных. И тут для сокрытия коммерческих данных от третьих лиц на помощь приходит криптование . Open-source имеет репутацию софта с безопасным программированием . Эта статья - еще один шаг в этом направлении .

Библиотека OpenSSL - это как раз то , что вам нужно для шифрования без погружения в детали того , как реализован этот алгоритм . Проблема в том , что документации по этому вопросу действительно мало . Можно почитать исходники , поиграть с компиляцией и посмотреть , что выходит . Имена функций в некотором смысле интуитивно помогают . Еще один вариант - подписка на рассылку на сайте OpenSSL . Командные утилиты OpenSSL также хорошо документированы и легки в использовании . В этой статье я буду обьяснять , как использовать алгоритм blowfish для криптования с использованием библиотек OpenSSL.

В раннюю эпоху криптографии алгоритмы , как и ключи , были секретны . Но все меняется . Теперь алгоритмы общеизвестны . Примером является RSA-алгоритм , который широко известен . RSA - это а-симметричный алгоритм , использующий разные ключи на входе и на выходе . Также использование RSA для криптования больших обьемов данных неоправданно из-за больших вычислительных ресурсов .

Для криптования больших обьемов данных предпочтительны менее интенсивные вычислительные алгоритмы . В этой статье мы используем алгоритм blowfish . Blowfish - симметричный алгоритм , использующий один и тот же ключ для шифрования и дешифровки. Blowfish был разработан знаменитым криптографом Bruce Schneier. Blowfish - это быстрый алгоритм .

Генерация ключей

Мы будем использовать 128-битный ключ.В программе он хранится как символьный массив . Также мы сгенерируем 64-битный вектор(IV). Мы будем использовать режим Cipher Block Chaining (CBC) . Функции blowfish будут использоваться не напрямую , а с помощью специального интерфейса . Начальный вектор IV - (initialization vector) - это набор случайной информации , которая используется на входе шифрования и обеспечивает работу всех его последующих стадий. (blowfish использует 64-битные блоки для шифрования). IV генерит условия для шифрования 1-го блока данных , из которого генерится 2-й блок данных , и т.д. Случайные биты генерятся с помощью специального файла /dev/random , который обеспечивает достаточно хорошую случайную последовательность чисел . Для более детальной информации смотрите manpage.
 int
 generate_key ()
 {
 	int i, j, fd;
 	if ((fd = open ("/dev/random", O_RDONLY)) == -1)
 		perror ("open error");
 
 	if ((read (fd, key, 16)) == -1)
 		perror ("read key error");
 
 	if ((read (fd, iv, 8)) == -1)
 		perror ("read iv error");
 	
 	printf("128 bit key:\n");
 	for (i = 0; i < 16; i++)
 		printf ("%d \t", key[i]);
 	printf ("\n ------ \n");
 
 	printf("Initialization vector\n");
 	for (i = 0; i < 8; i++)
 		printf ("%d \t", iv[i]);
 
 	printf ("\n ------ \n");
 	close (fd);
 	return 0;
 }
 

Функция для Encryption

Функция для шифровки имеет 2 параметра - файловый дескриптор входящего файла и файл , куда будут записаны зашифрованные данные . Перед использованием буфера в памяти его желательно обнулить . Это важно в случае повторного использования этого буфера . В следующем примере входящие данные шифруются поблочно по 1 килобайту . Последовательность шифрования следующая :

  1. Создание шифрованного контекста
  2. Инициализация контекста с помощью ключа и IV
  3. Вызов EVP_EncryptUpdate для криптования поблочно по 1k
  4. Вызов EVP_EncryptFinal для криптования оставшихся данных
  5. Вызов EVP_CIPHER_CTX_cleanup
Алгоритм Blowfish шифрует информацию поблочно по 64 бита . Иногда размер блока может быть меньше , чем 64 бита . Это случается , когда размер данных не кратен 8 байтам (64 битам). К нему добавляется данные и блок зашифровывается с помощью EVP_EncryptFinal. Длина данных хранится в переменной в конце блока .
 int
 encrypt (int infd, int outfd)
 {
 	unsigned char outbuf[OP_SIZE];
 	int olen, tlen, n;
 	char inbuff[IP_SIZE];
 	EVP_CIPHER_CTX ctx;
 	EVP_CIPHER_CTX_init (& ctx);
 	EVP_EncryptInit (& ctx, EVP_bf_cbc (), key, iv);
 
 	for (;;)
 	  {
 		  bzero (& inbuff, IP_SIZE);
 
 		  if ((n = read (infd, inbuff, IP_SIZE)) == -1)
 		    {
 			    perror ("read error");
 			    break;
 		    }
 		  else if (n == 0)
 			  break;
 
 		  if (EVP_EncryptUpdate (& ctx, outbuf, & olen, inbuff, n) != 1)
 		    {
 			    printf ("error in encrypt update\n");
 			    return 0;
 		    }
 
 		  if (EVP_EncryptFinal (& ctx, outbuf + olen, & tlen) != 1)
 		    {
 			    printf ("error in encrypt final\n");
 			    return 0;
 		    }
 		  olen += tlen;
 		  if ((n = write (outfd, outbuf, olen)) == -1)
 			  perror ("write error");
 	  }
 	EVP_CIPHER_CTX_cleanup (& ctx);
 	return 1;
 }
 

Функция дешифрования

Функция дешифровки основана на тех же принципах , что и предыдущая . Следующая функция показывает , как делается дешифровка .
 
 
 int
 decrypt (int infd, int outfd)
 {
 	unsigned char outbuf[IP_SIZE];
 	int olen, tlen, n;
 	char inbuff[OP_SIZE];
 	EVP_CIPHER_CTX ctx;
 	EVP_CIPHER_CTX_init (& ctx);
 	EVP_DecryptInit (& ctx, EVP_bf_cbc (), key, iv);
 
 	for (;;)
 	  {
 		  bzero (& inbuff, OP_SIZE);
 		  if ((n = read (infd, inbuff, OP_SIZE)) == -1)
 		    {
 			    perror ("read error");
 			    break;
 		    }
 		  else if (n == 0)
 			  break;
 
 		  bzero (& outbuf, IP_SIZE);
 
 		  if (EVP_DecryptUpdate (& ctx, outbuf, & olen, inbuff, n) != 1)
 		    {
 			    printf ("error in decrypt update\n");
 			    return 0;
 		    }
 
 		  if (EVP_DecryptFinal (& ctx, outbuf + olen, & tlen) != 1)
 		    {
 			    printf ("error in decrypt final\n");
 			    return 0;
 		    }
 		  olen += tlen;
 		  if ((n = write (outfd, outbuf, olen)) == -1)
 			  perror ("write error");
 	  }
 
 	EVP_CIPHER_CTX_cleanup (& ctx);
 	return 1;
 }
 

Полный код

Минимальная интерактивная программа с реализацией вышеуказанных функций приведена здесь :
 #include < openssl/blowfish.h>
 #include < openssl/evp.h>
 #include < fcntl.h>
 #include < stdio.h>
 #include < sys/stat.h>
 #include < sys/types.h>
 
 #define IP_SIZE 1024
 #define OP_SIZE 1032
 
 unsigned char key[16];
 unsigned char iv[8];
 
 int
 generate_key ()
 {
 	int i, j, fd;
 	if ((fd = open ("/dev/random", O_RDONLY)) == -1)
 		perror ("open error");
 
 	if ((read (fd, key, 16)) == -1)
 		perror ("read key error");
 
 	if ((read (fd, iv, 8)) == -1)
 		perror ("read iv error");
 	
 	printf("128 bit key:\n");
 	for (i = 0; i < 16; i++)
 		printf ("%d \t", key[i]);
 	printf ("\n ------ \n");
 
 	printf("Initialization vector\n");
 	for (i = 0; i < 8; i++)
 		printf ("%d \t", iv[i]);
 
 	printf ("\n ------ \n");
 	close (fd);
 	return 0;
 }
 
 int
 decrypt (int infd, int outfd)
 {
 	unsigned char outbuf[IP_SIZE];
 	int olen, tlen, n;
 	char inbuff[OP_SIZE];
 	EVP_CIPHER_CTX ctx;
 	EVP_CIPHER_CTX_init (&ctx);
 	EVP_DecryptInit (&ctx, EVP_bf_cbc (), key, iv);
 
 	for (;;)
 	  {
 		  bzero (&inbuff, OP_SIZE);
 		  if ((n = read (infd, inbuff, OP_SIZE)) == -1)
 		    {
 			    perror ("read error");
 			    break;
 		    }
 		  else if (n == 0)
 			  break;
 
 		  bzero (&outbuf, IP_SIZE);
 
 		  if (EVP_DecryptUpdate (&ctx, outbuf, &olen, inbuff, n) != 1)
 		    {
 			    printf ("error in decrypt update\n");
 			    return 0;
 		    }
 
 		  if (EVP_DecryptFinal (&ctx, outbuf + olen, &tlen) != 1)
 		    {
 			    printf ("error in decrypt final\n");
 			    return 0;
 		    }
 		  olen += tlen;
 		  if ((n = write (outfd, outbuf, olen)) == -1)
 			  perror ("write error");
 	  }
 
 	EVP_CIPHER_CTX_cleanup (&ctx);
 	return 1;
 }
 
 int
 encrypt (int infd, int outfd)
 {
 	unsigned char outbuf[OP_SIZE];
 	int olen, tlen, n;
 	char inbuff[IP_SIZE];
 	EVP_CIPHER_CTX ctx;
 	EVP_CIPHER_CTX_init (&ctx);
 	EVP_EncryptInit (&ctx, EVP_bf_cbc (), key, iv);
 
 	for (;;)
 	  {
 		  bzero (&inbuff, IP_SIZE);
 
 		  if ((n = read (infd, inbuff, IP_SIZE)) == -1)
 		    {
 			    perror ("read error");
 			    break;
 		    }
 		  else if (n == 0)
 			  break;
 
 		  if (EVP_EncryptUpdate (&ctx, outbuf, &olen, inbuff, n) != 1)
 		    {
 			    printf ("error in encrypt update\n");
 			    return 0;
 		    }
 
 		  if (EVP_EncryptFinal (&ctx, outbuf + olen, &tlen) != 1)
 		    {
 			    printf ("error in encrypt final\n");
 			    return 0;
 		    }
 		  olen += tlen;
 		  if ((n = write (outfd, outbuf, olen)) == -1)
 			  perror ("write error");
 	  }
 	EVP_CIPHER_CTX_cleanup (&ctx);
 	return 1;
 }
 
 int
 main (int argc, char *argv[])
 {
 	int flags1 = 0, flags2 = 0, outfd, infd, decfd;
 	mode_t mode;
 	char choice, temp;
 	int done = 0, n, olen;
 
 	bzero (&key, 16);
 	bzero (&iv, 8);
 	bzero (&mode, sizeof (mode));
 
 	flags1 = flags1 | O_RDONLY;
 	flags2 = flags2 | O_RDONLY;
 	flags2 = flags2 | O_WRONLY;
 	flags2 = flags2 | O_CREAT;
 
 	mode = mode | S_IRUSR;
 	mode = mode | S_IWUSR;
 
 	while (!done)
 	  {
 		  printf ("E - Encrypt a file\n");
 		  printf ("D - Decrypt a file\n");
 		  printf ("G - Generate a key\n");
 		  printf ("Q - Quit\n");
 
 		  choice = getchar ();
 		  temp = getchar ();
 
 		  switch (choice)
 		    {
 		    case 'e':
 		    case 'E':
 
 			    if ((infd = open (argv[1], flags1, mode)) == -1)
 				    perror ("open input file error");
 
 			    if ((outfd = open (argv[2], flags2, mode)) == -1)
 				    perror ("open output file error");
 
 			    encrypt (infd, outfd);
 
 			    close (infd);
 			    close (outfd);
 			    break;
 
 		    case 'd':
 		    case 'D':
 
 			    if ((outfd = open (argv[2], flags1, mode)) == -1)
 				    perror ("open output file error");
 
 			    if ((decfd = open (argv[3], flags2, mode)) == -1)
 				    perror ("open output file error");
 
 			    decrypt (outfd, decfd);
 
 			    close (outfd);
 			    fsync (decfd);
 			    close (decfd);
 			    break;
 
 		    case 'g':
 		    case 'G':
 			    generate_key ();
 			    break;
 
 		    case 'Q':
 		    case 'q':
 			    done = 1;
 			    break;
 
 		    default:
 			    printf ("ERROR: Unrecognized command.  Try again.\n");
 			    break;
 		    }
 	  }
 	return 0;
 } 
Компиляция программы :
# gcc -o blowfish sym_funcs.c -lcrypto
 
Программе в качестве параметров нужно указать 3 внешних файла :

  1. Файл , который нужно зашифровать
  2. Файл , в который все будет зашифровано
  3. Файл , в котором все будет расшифровано
Не забудьте сгенерировать ключи перед шифрованием .

Пример приложения - Secure Instant Messenger

Рассмотрим программу instant messenger software (IM) , который взаимодействует с другим IM. Может быть апробирован следующий метод :

  1. Каждый IM-клиент имеет свой private ключи.
  2. IM-клиент имеет также public keys , как и все остальные IM.
  3. Клиентом генерится т.н. сессионный ключ . Этот ключ используется для шифрования данных между 2-мя клиентами .
  4. Этот сессионный ключ шифруется и обменивается между 2-мя клиентами с помощью public-ключа . (RSA-алгоритм).
  5. Обмен шифрованными данными (с помощью Blowfish) происходит после "секретного рукопожатия".

Ресурсы

  1. OpenSSL Homepage
  2. The Blowfish Algorithm
  3. Handbook of Applied Cryptography

Copyright © 2003, Vinayak Hegde. Copying license http://www.linuxgazette.com/copying.html
Published in Issue 87 of Linux Gazette, February 2003
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье