Криптографические методы защиты в языках программирования

Виктор Рудометов

Основные проблемы и способы их решения

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

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

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

Математическая криптография возникла как наука о шифровании — наука о криптосистемах. В классической модели системы секретной связи имеются два участника, которым необходимо передать секретную (конфиденциальную) информацию, не предназначенную для третьих лиц. Данная задача об обеспечении конфиденциальности, защиты секретной информации от внешнего противника, является одной из первых задач криптографии.

Существует несколько подходов к решению поставленной задачи.

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

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

Третий способ — это использовать общедоступный канал связи, но передавать данные в преобразованном виде, так чтобы восстановить их мог лишь адресат. Разработкой методов преобразования информации, обеспечивающей ее шифрование, и занимается криптография.

Со временем область применения криптографии расширилась и ушла далеко вперед от своей начальной цели. В качестве иллюстрации этого положения можно рассмотреть следующий пример. Допустим, клиент банка намерен переслать деньги со своего счета на счет какой-либо организации. Здесь следует отметить, что не вся передаваемая информация является конфиденциальной. Действительно, необходимо переслать лишь банковские реквизиты, которые общеизвестны и общедоступны. Однако банку важно убедиться, что деньги хочет перевести именно их обладатель, а не злоумышленник. Клиент же заинтересован в том, чтобы сумма не была изменена, и никто не смог бы переслать деньги от его имени или поменять информацию о получателе денег.

Стоит отметить, что криптосистема работает по определенной методологии (процедуре).

Эта методология предусматривает использование:

·        одного или более алгоритмов шифрования, которые можно выразить в виде математических формул;

·        ключей, используемых данными алгоритмами шифрования,

·        системы управления ключами,

·        незашифрованного текста,

·        зашифрованного текста (шифртекста).

Пример схемы методологии шифрования с использованием ключей представлен на рис. 1.

Рис. 1. Пример схемы шифрования.

Классификация криптографических алгоритмов

Существуют две методологии с использованием ключей: симметричная, предусматривающая применение секретного ключа, и асимметричная — с открытым ключом. Каждая методология использует свои собственные процедуры, способы распределения ключей, их типы и алгоритмы шифрования и расшифровки.

В симметричной (symmetric) методологии с секретным ключом используется один ключ, с помощью которого производится как шифрование, так и расшифровка одним и тем же алгоритмом симметричного шифрования. Этот ключ передается двум участникам взаимодействия безопасным образом до передачи зашифрованных данных. Проблемой является тот факт, что безопасно распространять секретные ключи довольно трудно. К достоинствам данной системы можно отнести сравнительно большое быстродействие при шифровании и расшифровке передаваемых сообщений.

Примером постоянного использования симметричной методологии является сеть банкоматов ATM. Эти системы являются оригинальными разработками владеющих ими банков и не продаются.

В асимметричной (asymmetric) методологии с открытым ключом используются два взаимосвязанных ключа. Один из ключей хранится в секрете, а другой публикуется в открытых источниках. Данные, зашифрованные одним ключом, могут быть расшифрованы только другим ключом. Один из важнейших недостатков — это необходимость использования очень больших по размеру ключей для обеспечения безопасности, что, несомненно, отражается на скорости работы алгоритмов шифрования.

Часто обе методологии комбинируются. Например, генерируется симметричный (секретный) ключ, который передается с помощью алгоритмов асимметричной методологии.

К распространенным алгоритмам симметричной методологии можно отнести DES (Data Encryption Standard), 3-DES, RC2, RC4 и RC5. Примером же асимметричной являются RSA и ECC. И отдельную позицию занимает один из наиболее популярных алгоритмов цифровой подписи DSA (Digital Signature Algorithm).

Актуальность проблемы сохранения целостности или конфиденциальности информации была очевидна во все времена. Но особенно остро она проявилась с развитием информационных технологий, в частности, глобальной сети Интернет. Эта сеть обеспечивает удобный, оперативный способ связи. Использование же специальных средств обеспечивает необходимые уровни конфиденциальности. При этом в современной жизни пользователю компьютера нередко приходится встречаться с такими сложнейшими алгоритмами, как RSA или DSA. В результате уже почти ни у кого не вызывает удивления возможность использования цифровой подписи или даже шифрование писем электронной почты E-mail (рис. 2).

Рис. 2. Пример возможности использования криптографических систем защиты при отправке информации через Интернет

Наличие встроенных механизмов защиты информации в прикладных системах все чаще приобретает определяющее значение при выборе их потребителями. Поэтому данному вопросу уже давно уделяют внимание разработчики программных средств.

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

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

Примером может служить фирма Sun Microsystems, предлагающая разработчикам программного обеспечения язык Java с широким набором интерфейсов, реализующих основные криптографические алгоритмы и протоколы.

Криптография в Java

Рассматривая язык Java, следует напомнить, что этот язык создан сравнительно недавно и имеет как множество достоинств, так и немало недостатков. Часто  достоинства сводят к возможности создания машинно-независимых приложений. Однако существуют и другие, возможно, даже более важные в условиях стремительного развития информационного общества. Речь идет, например, о сетевой направленности при разработке языка. В 1993 году компания Sun обратила внимание на рост популярности Интернета и начала дорабатывать Java таким образом, чтобы написанные программы можно было запускать из Web-броузеров (апплеты). Также в язык были встроены и расширенные возможности создания приложений типа клиент/сервер.

В связи с  явной сетевой направленностью языка Java потребовалось уделить должное внимание средствам защиты. В первую очередь это касается пересылки важных данных между, например, клиентом и сервером, а также запуска программ или апплетов. Такие средства были разработаны и встроены в набор стандартных библиотек (JDK security API).

Примером необходимости защиты может служить желание пользователя-получателя иметь возможность верификации, что дает определенные гарантии подлинности документа или кода.. В качестве подписываемого объекта могут выступать апплеты, которые широко распространены в Интернете. В результате у получателя появляется уверенность, что информация получена именно от ожидаемого отправителя, а не возможного злоумышленника, и не была изменена в процессе пересылки. Для обеспечения такого рода безопасности служат цифровые подписи и сертификаты.

Алгоритм DSA

Основная идея цифровой подписи (digital signature) заключается в следующем.

Допустим, отправитель хочет послать получателю некоторые данные. Он "подписывает" документ или код с помощью специального закрытого ключа (private key). Этот ключ генерируется с помощью утилиты keytool или средствами API. В данном случае "подписывает" означает, что генерируется специальная цифровая подпись с помощью утилиты jarsigner или средствами API.

Диаграмма, иллюстрирующая прохождение через все этапы подписи jar-архива (работа отправителя), представлена на рис. 3. Следует отметить, что в jar-файле могут быть произвольные данные, например, программа, картинка или документ Word.

Рис. 3. Последовательность действий при подписи jar-архива.

Диаграмма, иллюстрирующая работу получателя jar-архива, представлена на рис. 4.

Рис. 4. Последовательность действий при верификации полученного jar-архива.

В процессе генерации закрытого ключа, создается и так называемый открытый ключ (public key), который "соответствует" закрытому.

Получателю отправляются следующие данные:

1.      исходный документ или код,

2.      цифровая подпись (либо отдельно, либо в составе jar-файла),

3.      открытый ключ.

Получатель, приняв все три компоненты, с помощью открытого ключа определяет подлинность подписи и целостность документа. Защищенность данного метода заключается в том, что для подделки или взлома необходимо сгенерировать закрытый ключ. При этом для данной задачи не существует "быстрого" алгоритма при условии, что длина ключей довольно велика.

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

Примером могут служить сертификаты (certificate). Они поставляются сторонними организациями и содержат в себе открытый ключ и некоторую дополнительную информацию. В качестве последней выступает информация об отправителе, данные о поставщике сертификата и цифровая подпись, дающие определенную гарантию, что открытый ключ принадлежит отправителю.

В такой ситуации, если имеет место доверие составителю сертификата, проблему можно считать решенной. В противном случае необходимо обратиться к еще одной сторонней организации и запросить новый сертификат, удостоверяющий подлинность уже имеющегося сертификата. И так далее до тех пор, пока пользователь не нейдет организацию, которой он может полностью доверять. В противном случае можно попытаться использовать самоподписанные сертификаты (CSR).

Стоит отметить, что для доказательства сложности «взлома» данного метода потребовались колоссальные математические исследования.

Рассмотрим возможность использования Java Security для генерации и верификации цифровой подписи.

Работа отправителя

Рис. 5. Схема действий при генерации подписи

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

Программист, не вникая в математические формулы и особенности их реализациии, может использовать уже доступные готовые алгоритмы и методы криптографии. Они предоставляются определенными организациями, так называемыми провайдерами (provider). По умолчанию встроенные средства Java поставляет провайдер "SUN". Таким образом, единственное, что необходимо делать, это указывать собственно алгоритм и провайдера.

В первую очередь необходимо сгенерировать пару ключей - public key и private key. Для этого  используется класс KeyPairGenerator. Для получения конкретного объекта этого класса необходимо вызвать static factory метод getInstance(). В качестве аргументов передаются строки с указанием алгоритма и провайдера. Например, для использования DSA (Digital Signature Algorithm) и провайдера SUN необходимо писать:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");

В связи с тем, что большинство криптографических алгоритмов являются вероятностными, необходимо создать вероятностный источник — объект класса SecureRandom. При этом существует возможность использовать разные методы, например, SHA1PRNG  (pseudo-random-number generation algorithm).

SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");

Теперь необходимо проинициализировать объект keyGen, передав ему 2 параметра — длину в битах и источник случайности.

keyGen.initialize(1024, random);

Последним этапом является собственно генерация пары ключей (метод generateKeyPair()) и выделение двух отдельных ключей (методы getPrivate() и getPublic()).

KeyPair pair = keyGen.generateKeyPair();

PrivateKey privKey = pair.getPrivate();

PublicKey pubKey = pair.getPublic();

Создание подписи.

В первую очередь необходимо создать объект класса Signature, вызвав метод getInstance():

Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");

В данном случае используется алгоритм DSA с SHA1 (хэш-функция). Затем идет процесс инициализации подписи ключом. На этом этапе используется закрытый ключ, полученный ранее:

dsa.initSign(privKey);

После этого необходимо свести подпись и сами данные. Для этого вызывается метод update(), получаемый в качестве параметра байтовый массив данных, которые должны быть подписаны.

На последнем этапе генерируется сама подпись, которая представляется в виде байтового массива.

byte[] realSig = dsa.sign();

Сохранение подписи.

После получения подписи и ключей необходимо сохранить их, например, в файл, и отправить адресату вместе с исходными данными. Следует подчеркнуть, что закрытый ключ не посылается, а остается у отправителя. Отсылается же открытый ключ.

Итак, отправитель посылает получателю, например, по электронной почте или через прямое сетевое соединение следующие файлы:

1.      Открытый ключ (public key)

2.      Цифровую подпись (digital signature)

3.      Исходные данные (подписанный документ или код).

Работа получателя.

Рис. 6. Схема действий при верификации подписи

Работа с ключом: чтение из файла и преобразование в PrivateKey.

Получатель располагает последовательностью байт, представляющих открытый ключ. Необходимо получить байтовый массив (Byte[] encKey), например, прочитать эти данные из файла в массив, а затем преобразовать его в объект класса PublicKey.

Для этого можно воспользоваться классом KeyFactory, который по спецификации ключа может восстановить объект класса Key (PrivateKey и PublicKey являются потомками класса Key). Таким образом, необходимо получить так называемую спецификацию ключа. Ее можно получить, основываясь на том, какой стандарт использовался при генерации ключа. В данном случае ключ был сгенерирован с помощью провайдера "SUN", поэтому он удовлетворяет стандарту X.509.

Генерация спецификации ключа (необходим пакет java.security.spec.*):

X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);

Создание объекта класса KeyFactory, соответствующего цифровой подписи и провайдеру "SUN".

KeyFactory keyFactory = KeyFactory.getInstance("DSA", "SUN");

Получение объекта класса PublicKey

PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);

Работа с подписью: чтение из файла и Signature.

Подпись также необходимо перевести в байтовый массив (Byte[] sigToVerify). Затем необходимо создать объект типа Signature, также как это делалось ранее.

Signature sig = Signature.getInstance("SHA1withDSA", "SUN");

sig.initVerify(pubKey);

Во время чтения необходимо применять метод update() объекта sig, аналогично случаю создания подписи.

Проверка подлинности (верификация).

Завершающим этапом работы получателя является собственно получение ответа на вопрос о правдивости подписи и данных. С помощью метода verify() объекта класса Signature можно получить результатом boolean:

boolean verifies = sig.verify(sigToVerify);

Значение будет true, если данная подпись (sigToVerify) действительная подпись для данных, созданная с использованием открытого ключа (pubKey).

Следует отметить, что первый этап, связанный с работой отправителя, требует некоторого времени для генерации необходимых для отправки данных. Для компьютера класса Intel Pentium III с частотой 733 МГц время генерации составляет приблизительно 10 секунд. Кстати, время, затрачиваемое для верификации на порядок меньше.

Кроме рассмотренного DSA, предоставляются и многие другие средства криптографической защиты, как RSA, DES и другие. Их использование подобно представленному DSA.

Исходные программы

Ниже представлены тексты уже готовых и работающих программ. GSig.java подписывает данные из файла data, генерирует открытый ключ и подпись, записывая их соответственно в файлы signature и publickey. и VSig.java читает данные из файлов signature, publickey и data и выводит на экран сообщение о правдивости подписи (о соответствии подписи данным).

Следует отметить, что первый этап (работа отправителя) требует определенного времени для генерации необходимых для отправки данных. Например, для компьютера с процессором Intel Pentium III 733 МГц время, требуемое для генерации 1024-битных ключей и подписи небольшого сообщения, составляет приблизительно 10 секунд. Кстати, время, затрачиваемое для верификации, на порядок меньше и составляет менее секунды.

GSig.java

/* Генерация DSA подписи */

import java.io.*;

import java.security.*;

class GSig

{

      //сохранение байтового массива в файл

      public static void saveToFile (byte[] info, String filename)

      {

            try

            {

                  FileOutputStream fos = new FileOutputStream(filename);

                  fos.write(info);

                  fos.close();

            }

            catch (Exception e)

            {

                  System.err.println("Caught exception " + e.toString());

            }

      }// saveToFile ()

      public static void main(String args[])

      {

            try

            {

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

                  KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");

                  SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");

                  keyGen.initialize(1024, random);

                  KeyPair pair = keyGen.generateKeyPair();

                  PrivateKey priv = pair.getPrivate();

                  PublicKey pub = pair.getPublic();

                  /* Создание объекта класса Signature */

                  Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");

                  /* Инициализация частным ключом */

                  dsa.initSign(priv);

                  /* Чтение данных из файла "data". Вызов метода update() */

                  FileInputStream fis = new FileInputStream("data");

                  BufferedInputStream bufin = new BufferedInputStream(fis);

                  byte[] buffer = new byte[1024];

                  int len;

                  while (bufin.available() != 0)

                  {

                        len = bufin.read(buffer);

                        dsa.update(buffer, 0, len);

                  }

                  bufin.close();

                  /* Генерация подписи */

                  byte[] realSig = dsa.sign();

                  /* Сохранение подписи в файл "signature" */

                  saveToFile (realSig,"signature");

                  /* Сохранение открытого ключа в файл "pubkey" */

                  byte[] key = pub.getEncoded();

                  saveToFile (key,"pubkey");

            }

            catch (Exception e)

            {

                  System.err.println("Caught exception " + e.toString());

            }

      }// main()

}// class GSig

VSig.java

/* Верификация DSA подписи */

import java.io.*;

import java.security.*;

import java.security.spec.*;

class VSig

{

      //чтение из файла в байтовый массив

      public static byte[] readFromFile (String fileName)

      {

            byte[] info;

            try

            {

                  FileInputStream fis = new FileInputStream(fileName);

                  info = new byte[fis.available()];

                  fis.read(info);

                  fis.close();

            }

            catch (Exception e)

            {

                  System.err.println("Caught exception " + e.toString());

                  info = new byte[0];

            }

            return(info);

      }// copyFromFile ()

      public static void main(String args[])

      {

            try

            {

                  /* Получение encoded public key из файла "pubkey" */

                  byte[] encKey = readFromFile("pubkey");

                  /* Создание спецификации ключа */

                  X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);

                  .* Создание объектов Лунафсещкн и ЗгидшсЛун*.

                  KeyFactory keyFactory = KeyFactory.getInstance("DSA", "SUN");

                  PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);

                  /* Чтение подписи из файла "signature" */

                  byte[] sigToVerify = readFromFile("signature");

                  /* Создание объекта класса Signature и инициализация с помощью открытого ключа */

                  Signature sig = Signature.getInstance("SHA1withDSA", "SUN");

                  sig.initVerify(pubKey);

                  /* Чтение данных из файла "data" и вызов метода update() */

                  FileInputStream datafis = new FileInputStream("data");

                  BufferedInputStream bufin = new BufferedInputStream(datafis);

                  byte[] buffer = new byte[1024];

                  int len;

                  while (bufin.available() != 0)

                  {

                        len = bufin.read(buffer);

                        sig.update(buffer, 0, len);

                  }

                  bufin.close();

                  /* Верификация */

                  boolean verifies = sig.verify(sigToVerify);

                  System.out.println("Signature verifies: " + verifies);

            }

            catch (Exception e)

            {

                  System.err.println("Caught exception " + e.toString());

            }

      }// main()

}// class VSig

Асимметричная криптография в Perl

Довольно популярный Интернет-направленный язык Perl также имеет встроенные средства обеспечения защиты.

Для примера рассмотрим использование криптографического алгоритма шифрования RSA.

Алгоритм RSA

Задача, которую решает RSA, это передача секретной информации таким образом, чтобы прочитать ее смог лишь адресат.

Суть метода заключается в следующем.

Потенциальным получателем шифрованного сообщения выполняются следующие действия:

·        генерируются два больших простых числа (например, 1024 бит, 308 знаков) — p и q;

·        подсчитывается их произведение = pq;

·        выбирается случайное число e, которое взаимно просто с числом (p‑1)(q‑1), а также не превосходит его;

·        подсчитывается величина d такая, что ed = mod (p‑1)(q‑1).

·        пара (n, e) становится открытым ключом (public key), а d — закрытым ключом (private key).

Открытый ключ публикуется в открытых источниках, например, пересылается через электронную почту.

Отправителю шифрованного сообщения для работы необходимо выполнить следующие действия:

·        получить открытый ключ;

·        создать сообщение в числовом виде m, не превосходящем n;

·        подсчитать величину c = (me) mod n;

·        с и есть зашифрованное сообщение, которое отправляется создателю открытого ключа.

Получатель закодированного сообщения вычисляет m = (cd) mod n и получает сообщение в расшифрованном виде.

Стойкость алгоритма RSA обеспечивается благодаря тому, что злоумышленнику необходимо получить число d, которое можно вычислить, факторизовав число n. Однако на данный момент не существует быстрых алгоритмов, решающих задачу факторизации больших чисел.

Основные методы работы с RSA

В языке Perl вся криптография поставляется через модули CPAN. Реализация RSA находится в пакете Crypt::RSA.

Генерация 2048-битовых ключей:

$rsa = new Crypt::RSA;

$public, $private) = $rsa->keygen( Size => 2048 )

Открытый ключ публикуется.

Шифрование данных (строка $message) с использованием открытого ключа:

my $c = $rsa->encrypt( Message => $message, Key => $public );

В результате получается шифрованное сообщение $c, которое отправляется обратно адресату. Получатель использует для расшифровки ранее сгенерированный закрытый ключ $private,:

$message = $rsa->decrypt( Ciphertext => $c, Key => $private );

Кроме представленных строк исходного текста на языке Perl, стоит отметить и некоторые дополнительные особенности пакета.

Для отправки защищенных сообщений информация должна быть представлена в виде одного или нескольких чисел, значения которых не превосходят n. При этом каждому сообщению соответствует определенное число и наоборот. Средства языка Perl позволяют дробить сообщение на последовательность таких чисел, а также в дальнейшем соединять их обратно в текст.

К сожалению, в системе RSA есть одна важная особенность, снижающая степень защищенности. Если злоумышленник может заставить отправителя закодировать уже известное ему сообщение, то величины p и q могут быть подсчитаны без факторизации n. Однако с этим можно успешно бороться, перегружая исходное сообщение “мусором” (padding). Со временем для этой операции был разработан стандарт PKCS #1. Crypt::RSA реализует не только PKCS #1, но и более современный OAEP, который использует padding по умолчанию. При использовании PKCS #1 необходимо передать соответствующий параметр конструктору.

$rsa = new Crypt::RSA ( ES => 'PKCS1v15 )

Пример использования цифровой подписи

RSA

Проверка подлинности и целостности сообщения обычно решается с помощью DSA алгоритма. Однако есть возможность использовать и пакет Crypt::RSA.

В первую очередь необходимо сгенерировать ключи. Чаще всего ключи уже готовы и хранятся в файле под паролем. Для  создания $private используется конструктор Crypt::RSA::Key::Private(), которому в качестве параметров передается имя файла и пароль.

$private = new Crypt::RSA::Key::Private(

Filename => "keys/имя_файла.private",

Password => 'пароль'

); 

Подпись осуществляется с помощью $rsa->sign(). При этом в качестве параметров выступает сообщение и закрытый ключ.

$rsa = new Crypt::RSA;

$signature = $rsa->sign ( Message => $message, Key => $private );

Сообщение $message и подпись $signature отправляются адресату, который, используя открытый ключ, получает подтверждение подлинности подписи:

$public = new Crypt::RSA::Key::Public( 
                            Filename => "keys/имя_файла.public",); 
$rsa->verify( Message => $message, 
              Signature => $signature, 
              Key => $public ) 
             || die "Подпись поддельная!\n";

DSA

DSA реализуется в пакете Crypt::DSA. Использование DSA аналогично RSA-подписи, но есть и свои особенности.

Сначало генерируется DSA-ключ:

use Crypt::DSA;
$dsa = Crypt::DSA->new;
$key = $dsa->keygen( Size => 512 );

Подпись осуществляется стандартным образом:

$sig = $dsa->sign( Message => $message, Key => $key );

Получателю опять же посылаются сообщение, подпись и открытый ключ. В процессе верификация (используется открытый ключ $pub_key) подпись либо принимается ($valid=true), либо отвергается ($valid=false).

$valid = $dsa->verify(      Signature => $sig, 
                               $message, 
                               Key => $pub_key        );

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

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

Универсальные криптографические интерфейсы

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

Первоначально многие интерфейсы возникали в качестве внутрикорпоративных  стандартов. Таким образом, появились CryptoAPI (Microsoft), Cryptoki (RSA Data Security), GCS-API (X/Open). Международная организация по стандартизации IETF (Internet Engineering Task Force) попыталась создать единый универсальный стандарт, который был назван GSS-API. CpyptoAPI ориентирована на использование в ОС Windows NT, в то время как остальные не имеют четких ограничений, но все же чаще используются в ОС Unix.

В дополнение к вышесказанному следует отметить, что разработчики программного обеспечения обычно не задумываются над тем, какие алгоритмы криптографической защиты будут использоваться в их продукте. Обеспечивается лишь необходимый интерфейс вызова функций защиты, разработанных сторонним производителем.

Microsoft CryptoAPI

Порядок взаимодействия приложений с криптографическими модулями операционной системы регламентирует документ, который называется Microsoft Cryptographic Application Programming Interface (MS CryptoAPI). Функции, описанные в нем, поддерживаются Windows 9x и Windows NT/2000/XP. В последних ОС функции CryptoAPI содержатся в модулях crypt32.dll и advapi32.dll. На самом деле эти модули не реализуют криптографические алгоритмы, а обращаются к другим модулям, называемым Cryptographic Service Providers (CSP). Одновременно в операционной системе можно установить несколько CSP. При первом обращении к CryptoAPI прикладная программа выбирает, с каким именно модулем CSP она будет работать в зависимости от того, какие криптографические алгоритмы ей необходимы (рис. 7). Следует отметить, что система, используемая в Java, по организации схожа с данной.

Рис. 7. Схема архитектуры CryptoAPI

CryptoAPI позволяет шифровать данные подписывать документы цифровой подписью и многое другое. Существуют встроенные средства, например, Microsoft Base Cryptographic Provider.

Таким образом, есть возможность использовать CryptoAPI в таких программах разработки, как Visual Studio. То есть автоматически осуществляется поддержка таких языков, как Visual C++, Visual Basic, Visual FoxPro и другие.

С развитием компанией Microsoft языковой платформы .NET, большинство языков программирования, включая набирающий популярность язык C#, поддерживают криптографические методы защиты.

Примером функции генерации ключей может быть CryptGenKey(). Для шифрования и дешифрования  — это функции CryptEncrypt() и CryptDecrypt() и так далее.

Использование криптозащиты в других языках

Если в языке нет встроенных средств криптографической защиты, то существует две возможности.

Во-первых, можно попытаться сделать все “с нуля”. К сожалению, чаще всего это не предоставляется возможным, так как связано с реализацией сравнительно сложных алгоритмов.

Второй способ — это использование объектных модулей, созданных с использованием  трансляторов с разных языков программирования.

Допустим, имеется ряд языков, на которых уже реализованы требуемые алгоритмы. Трансляторами с этих языков обеспечивается получение объектных кодов, которые можно  использовать при разработке приложения на другом языке. Естественно, это не всегда легко реализуемо. Однако такие языки, как, например, Алгол, Фортран, PL1 благодаря схожему синтаксису языковых конструкций и реализации трансляторов, как правило, вполне совместимы в данном смысле.

Пример работы представлен на рис. 8.

Рис. 8. Пример схемы объединения модулей, созданных на разных языках.

Рассматривая возможность применения указанного способа, необходимо отметить, что в случае больших трудностей стыковки модулей, созданных на разных языках программирования, как правило, имеется возможность использования для этой цели ассемблера. При этом соответствующие структуры ассемблера могут применяться как для промежуточной передачи параметров, так и для осуществления вызова объектных модулей.

Заключение

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

В дополнение к этому следует еще раз отметить, что, как показывает практика, криптографические методы защиты действительно обеспечивают безопасность на сравнительно высоком уровне. Несомненно, данное направление будет быстро развиваться с появлением новых коммуникационных аппаратно-программных средств. Большинство современных компаний стараются разработать универсальные криптографические интерфейсы и оградить разработчика программного обеспечения от самостоятельных реализаций сложных алгоритмов. И JDK security API  и CryptoAPI, и встроенные средства .NET предоставляют богатый набор средств шифрования, позволяющих организовать собственную систему защиты данных. Однако надо отметить, что на пути реализации эффективной защиты информации существуют еще многие технологические трудности. Тем не менее, соответствующие аппаратно-программные средства стремительно развиваются. Это позволяет рассчитывать на появление новых решений, которые, можно надеяться, будут лишены существующих пока изъянов.

Литература

1.          “Введение в криптографию” / Под общ. ред. В.В.Ященко. — М.:МЦНМО, ”ЧеРо”, 1998. — 272c.

2.          А.Никитин, “Универсальные криптографические интерфейсы”, Защита информации, Конфидент,  N5, 1997.

3.          М.Могран, “Java 2. Руководство разработчика”, Пер. с англ. : Уч. пос. — М.: “Вильямс”, 2000. — 720c. : ил.

4.          Vipul Ved Prakash, Benjamin Trott, “Asymmetric Cryptography in Perl”, O'Reilly, 2001.

5.          R.Coleridge, “The Cryptography API, or How to Keep a Secret”, MSDN, 1996.

6.          D.Esposito, “Supporting CryptoAPI in Real-World Applications”, MSDN, 1997.

7.          http://spec-zone.ru

8.          S.K.Parmar, “An introduction to security”, Fred Cohen &Associates, 2000.

9.          R.L/Rivest, A.Shamir and L.Adleman, “A method for obtaining digital signatures and public key cryptosystems”. Commun. ACM, vol.21, p. 120-126, 1978.

10.       W.Diffie and M.E.Hellman, “New directions in cryptograpgy”, IEEE Trans.Inf.Theory, vol.IT-22, N6, p.644-654, Nov. 1976.

11.       A.Menezes, P.van Oorschot, S.Vanstone, “Handbook of applied cryptography”, CRC Press, 1996.


Статья опубликована в журнале Компьютер Пресс (http://www.compress.ru/).