habrahabr

Криптон. Оживляем «криптографический танк» из девяностых

  • воскресенье, 8 декабря 2024 г. в 00:00:09
https://habr.com/ru/companies/timeweb/articles/846650/
Приветствую всех!
Не так давно я рассказывал про построенный на базе «гражданского» девайса портативный шифратор ‭«Электроника МК-85С‭». Самое время поведать миру о ещё одном, не менее значимом, но чуть менее известном девайсе — отечественном криптопроцессоре «Блюминг-1», а также об алгоритме, который он реализовывал.



Итак, в сегодняшней статье рассмотрим ещё одного представителя российской шифровальной техники — построенную на данном чипе плату шифрования ‭«Криптон‭». Узнаем, как работает эта штука и где она применялась. Заодно посмотрим на её софт и попробуем что-то зашифровать. Как водится, будет много интересного.

Суть такова


История данного устройства началась в середине семидесятых годов, когда начал разрабатываться алгоритм ГОСТ 28147-89 (он же ‭«Магма-2‭»), по принципу работы напоминающий DES. Создавался он в ходе проекта по разработки криптографических систем защиты информации на ЭВМ Единой системы. Требования, предъявлявшиеся к нему, были крайне высокими: предполагалось, что шифровать им будут информацию высокой степени секретности, причём сам алгоритм секретным был быть не должен.

В 1987 году было создано и устройство шифрования — криптопроцессор ‭«Блюминг-1‭», реализующий данный алгоритм. Примечателен он тем, что стал первым отечественным однокристальным шифратором, давшим начало развития целой области средств защиты информации у нас.



А вот и построенная на базе данного чипа плата «Дебют-3». Существовало три версии: «1» для ЭВМ ДВК, «2» — для Системы малых ЭВМ, «3» — для PC с шиной ISA.





Плата «Криптон-3», дальнейшее развитие платы «Дебют» (ввиду того, что СМ ЭВМ и ДВК были выведены из эксплуатации, «Криптон-1» и «Криптон-2» так и не суждено было появиться). Следом за ней вышла более продвинутая «Криптон-4». Выпускались они зеленоградским предприятием «ANCUD» (что означало «Angstrem custom design»). Несмотря на довольно похожее название, к ранее упоминавшемуся АНКОРТу отношения оно не имеет.

Небольшой прикол
Есть у меня любовь к поиску и документированию ошибок и опечаток в объявлениях, на сайтах и где-то ещё. Чем глупее ошибка и чем серьёзнее место обнаружения — тем веселее. Сайт ANCUD здесь тоже отличился аж тройным неправильным описанием одного и того же слова…



Фирма эта работает и сейчас и продолжает заниматься выпуском средств защиты информации (преимущественно для гостайны).



Снова «Криптон-3», но в несколько другом исполнении. Увы, я общался с товарищем, кому удалось её достать, но запустить её не удалось…

Обзор оборудования


Про эти платы не удалось найти практически никакой информации. Даже при банальном поиске «Криптон-4» обнаруживается мало чего. Так что сейчас немного развеем завесу тайны.



Перво-наперво идёт сама плата «Криптон-4». Рассмотрим её поподробнее. По центру два базовых матричных кристалла Н1515ХМ1, обеспечивающих связь шифропроцессоров с компьютером. Слева от них в опечатанной панельке ПЗУшка, в которой содержится BIOS устройства. Ещё левее два диода в стеклянных корпусах. Это 2Г401 — специализированные германиевые диоды, предназначенные для использования в генераторах шума. Как нетрудно догадаться, здесь на них выполнен аппаратный генератор случайных чисел. Потенциометры на плате, вероятно, служат для его подстройки (хотя, конечно, могу ошибаться, никакой информации на этот счёт я не нашёл). Над БМК находятся два чипа КБ1 — те самые шифропроцессоры. Возле планки нераспаянный разъём DB9 для подключения считывателя смарт-карт. В правом верхнем углу ещё одна ПЗУшка — КР556РТ11. В ней записан индивидуальный номер платы, написанный также на приклеенной к микросхеме бумажке. Номер этот используется для идентификации устройства программами: некоторый софт будет работать исключительно с той платой, для которой разрабатывался.





Дискеты с софтом.





А вот более старые версии софта. Что от чего, мне неведомо, досталось всё одной кучей.



Ещё один дистрибутив софта — LiteSign. В отличие от остальных дискет, эта в опечатанной коробочке (которую до меня уже, разумеется, открывали).



А вот более новая версия платы, уже на PCI. Чипы шифраторов изменили свои корпуса, вместо БМК теперь ПЛИС. Шумовые диоды также, очевидно, никуда не подевались. Разъём 4P4C, предназначенный для подключения ключа iButton.



На обратной стороне этикетка — изделие М-503Г. По сравнению с предыдущей платой, железка не такая уж и древняя.



На этом история данных устройств не заканчивается. Следующим шагом было избавление от керамических чипов шифраторов. Их обязанности были возложены на ПЛИС. Плата же получила название Криптон-8/PCI.



Последняя (если верить сайту ANCUD) версия — Криптон-10/PCI-E.



Параллельно с абонентскими шифраторами выпускаются и средства доверенной загрузки — Криптон-Замок.

Инструкция и софт




Помимо платы и дискет мне достался мануал, который я не поленился отсканировать. Страниц в нём немного, так что я разместил его прямо тут.

Под спойлером много картинок






































Также я оцифровал все имеющиеся у меня дискеты и выложил файлы на old-dos.ru. Помимо этого прочесал архивы сайта ANCUD и все найденные материалы также залил туда.

Первый запуск


Ну что же, время запускать!



В качестве тестового компа будем использовать вот такую плату на процессоре 386SX. Втыкаем в неё всё нужное железо и плату шифрования, и пробуем включать.



После прохождения POST запускается BIOS платы.



Хранилища ключей у неё нет, поэтому они подтягиваются при загрузке с дискет или считывателей смарт-карт, где остаются до отключения питания. Тестовые ключи (узел замены и главный ключ) находятся на комплектной дискете. Нужны они для запуска платы, если ни одного «боевого» ключа ещё не сгенерировано.



Втыкаем дискету с софтом, и ключи успешно подтягиваются. После этого начинается загрузка DOS.

Шифруем и расшифровываем




Теперь запускаем главный софт — crtools. По сути это и есть утилита для шифрования, далёкий предок всяческих «КриптоАРМ» и тому подобного ПО. Здесь достаточно выбрать нужный файл и запустить операцию из меню, после чего он будет зашифрован или расшифрован. Никаких кодов, секретных комбинаций кнопочек и тому подобных манипуляций, всё делается за пару секунд в несколько нажатий клавиш.



Параметры системы.

Генератор ключей




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

ЭЦП и неожиданный облом


Следующей на очереди идёт программа CryptonSign, предназначавшаяся для цифровой подписи.



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

LiteSign




Софт из коробочки тоже оказался непрост.



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

Эмулятор и софт под Windows


Напоследок взглянем на то, какой софт существовал для работы с шифратором в среде Windows. Выпущен он уже куда позднее, нежели тот, что под DOS, также имеет защиту от копирования (на этот раз с помощью аппаратного ключа для LPT-порта) и сейчас доступен только в демо-версии по причине прекращения продаж и отсутствия «кряка». Впрочем, для того, чтобы увидеть его в работе, этого более чем достаточно.
На случай, если платы нет, можно воспользоваться эмулятором (для Windows 9x/NT4.0/2000).



Первым делом ставим необходимый для работы всего софта Crypton API.



Теперь накатываем эмулятор, и всё, можно пробовать запускать ПО.



Помимо софта для шифрования отдельных файлов ANCUD также предоставлял и более специализированный, например, спецархиватор для почты ArcMail.



Но с ним, увы, не задалось: версия под Windows не запускалась, а под DOS — не видела ни эмулятор, ни настоящую плату. Пришлось переместиться на Windows 2000, где софт ожил.



Открываем параметры и устанавливаем путь для хранения ключей.



А вот и наш софт.





Другим ПО для Windows является «Криптон-Подпись», интегрирующийся прямо в контекстное меню.

Криптон для программиста


Помимо использования штатного софта была возможность разрабатывать свой. Для этого существовал Crypton DK — набор библиотек и документации для разработки. Для того, чтобы оснастить свою программу возможностью аппаратного шифрования, достаточно было установить Crypton API и подключить прилагаемые к Crypton DK DLL-ки.

Пример использования каждой из функций Crypton DK
/////////////////////////////////////////////////////////////////
// Sample: testing Crypton API functions
// (c) Ancud 1998
// --------------------------------------------------------------
// The sample shows using all the Crypton API functions
/////////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include "..\..\INC\CryptLib.h"

CRHANDLE hCR;                // Handle to a crypton service
#define TestBufSize 2048     // The size of the buffers for encryption/decryption and random tests
char TestBuf1[TestBufSize];  // Buffers for encryption/decryption and random tests
char TestBuf2[TestBufSize];
char TestBuf3[TestBufSize];
crSYNCHRO crSync;
crKEY     crKey1,crKey2;     // Buffers for keys
crIP      crIP1,crIP2;       // Buffers for imitoprefixes

void                         // Almost obvious function ;)
WriteRes(BOOL res)
{
 if (res)
   printf(" \tOK\n");
 else
   printf(" \tFALSE\n");
}

void                         // Making equal buffers
SetEqualBufs(char* Buf1,char* Buf2,int Size)
{
 char j=35;
 int  i;
 for (i=0; i<Size; i++)
 {
  *(Buf1+i)=j;
  *(Buf2+i)=j;
  j++;
 }
}

void                         // Making different buffers
SetBufs(char* Buf1,char* Buf2,int Size)
{
 char j=32;
 int  i;
 for (i=0; i<Size; i++)
 {
  *(Buf1+i)=j;
  *(Buf2+i)=255-j;
  j++;
 }
}

void
main()
{
 printf("\nTest of Crypton API functions (c) Ancud 1998\n");
 if (crInitCryptonLib())             // Don't forget to call this function
                                     // before using Crypton API functions
 {
  hCR=crInitService();     // Get a handle to the hardware service
  if (hCR)
  {
   BOOL res;

   if(crTestHardware(hCR)){
     printf("Using DK with Crypton Hardware!\n");
   }else
     printf("Using DK with Crypton Emulator!\n");

   //  crTestHardware
   printf("crTestHardware\t"); WriteRes(crTestHardware(hCR));

   //  crGetCryptonNumber
   printf("crGetCryptonNumber\t%i\n",crGetCryptonNumber(hCR));

   //  crRandom
   printf("crRandom\t");
   SetEqualBufs(TestBuf1,TestBuf2,TestBufSize);
   res=crRandom(hCR,TestBufSize,TestBuf1);
   res&=(memcmp(TestBuf1,TestBuf2,TestBufSize)!=0);
   WriteRes(res);

   //  crControlledRandom
   {
    crCTRLRANDOM TestBuf1,TestBuf2;
    printf("crControlledRandom");
    SetEqualBufs(TestBuf1,TestBuf2,CTRLRANDOM_LEN);
    res=crControlledRandom(hCR,TestBuf1);
    res&=(memcmp(TestBuf1,TestBuf2,CTRLRANDOM_LEN)!=0);
    WriteRes(res);
   }

   //  crSetK1
   printf("crSetK1\t\t");
   crRandom(hCR,CRYPTON_KEY_LEN,crKey1);
   WriteRes(crSetK1(hCR,crKey1));

   //  crSetK2
   printf("crSetK2\t\t");
   crRandom(hCR,CRYPTON_KEY_LEN,crKey1);
   WriteRes(crSetK2(hCR,crKey1));

   //  crSetK1onK2
   printf("crSetK1onK2\t");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   res=crSetK1onK2(hCR,crKey1);
   res&=crGetK1onK2(hCR,crKey2);
   res&=(memcmp(crKey1,crKey2,CRYPTON_KEY_LEN)==0);
   WriteRes(res);

   //  crGetK1onK2
   printf("crGetK1onK2\t");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   crSetK1onK2(hCR,crKey1);
   res=crGetK1onK2(hCR,crKey2);
   res&=(memcmp(crKey1,crKey2,CRYPTON_KEY_LEN)==0);
   WriteRes(res);

   //  crGetK2onK1
   printf("crGetK2onK1\t");
   crRandom(hCR,CRYPTON_KEY_LEN,crKey1);
   crSetK1(hCR,crKey1);
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   res=crGetK2onK1(hCR,crKey1);
   res&=crGetK2onK1(hCR,crKey2);
   res&=(memcmp(crKey1,crKey2,CRYPTON_KEY_LEN)==0);
   WriteRes(res);

   //  crSetK2onK3
   printf("crSetK2onK3\t");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   res=crSetK2onK3(hCR,crKey1);
   res&=crGetK2onK3(hCR,crKey2);
   res&=(memcmp(crKey1,crKey2,CRYPTON_KEY_LEN)==0);
   WriteRes(res);

   //  crGetK2onK3
   printf("crGetK2onK3\t");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   crSetK2onK3(hCR,crKey1);
   res=crGetK2onK3(hCR,crKey2);
   res&=(memcmp(crKey1,crKey2,CRYPTON_KEY_LEN)==0);
   WriteRes(res);

   //  crSetK1onK3
   printf("crSetK1onK3\t");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   res=crSetK1onK3(hCR,crKey1);
   res&=crGetK1onK3(hCR,crKey2);
   res&=(memcmp(crKey1,crKey2,CRYPTON_KEY_LEN)==0);
   WriteRes(res);

   //  crGetK1onK3
   printf("crGetK1onK3\t");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   crSetK1onK3(hCR,crKey1);
   res=crGetK1onK3(hCR,crKey2);
   res&=(memcmp(crKey1,crKey2,CRYPTON_KEY_LEN)==0);
   WriteRes(res);

   //  crSetRandomK1onK3
   printf("crSetRandomK1onK3");
   SetEqualBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   res=crGetK1onK3(hCR,crKey1);
   res&=crSetRandomK1onK3(hCR);
   res&=crGetK1onK3(hCR,crKey2);
   res&=(memcmp(crKey1,crKey2,CRYPTON_KEY_LEN)!=0);
   WriteRes(res);

   //  crGetIPforDataonK1
   printf("crGetIPforDataonK1");
   SetBufs(TestBuf1,TestBuf2,TestBufSize);
   SetBufs(crIP1,crIP2,CRYPTON_IP_LEN);
   res=crGetIPforDataonK1(hCR,TestBufSize,TestBuf1,crIP1);
   res&=crGetIPforDataonK1(hCR,TestBufSize,TestBuf1,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)==0);
   res&=crGetIPforDataonK1(hCR,TestBufSize,TestBuf2,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)!=0);
   WriteRes(res);

   //  crGetIPforK1onK2
   printf("crGetIPforK1onK2");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   SetBufs(crIP1,crIP2,CRYPTON_IP_LEN);
   crSetK1(hCR,crKey1);
   res=crGetIPforK1onK2(hCR,crIP1);
   res&=crGetIPforK1onK2(hCR,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)==0);
   crSetK1(hCR,crKey2);
   res&=crGetIPforK1onK2(hCR,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)!=0);
   WriteRes(res);

   //  crGetIPforK2onK3
   printf("crGetIPforK2onK3");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   SetBufs(crIP1,crIP2,CRYPTON_IP_LEN);
   crSetK2(hCR,crKey1);
   res=crGetIPforK2onK3(hCR,crIP1);
   res&=crGetIPforK2onK3(hCR,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)==0);
   crSetK2(hCR,crKey2);
   res&=crGetIPforK2onK3(hCR,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)!=0);
   WriteRes(res);

   //  crGetIPforK2onK1
   printf("crGetIPforK2onK1");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   SetBufs(crIP1,crIP2,CRYPTON_IP_LEN);
   crSetK2(hCR,crKey1);
   res=crGetIPforK2onK1(hCR,crIP1);
   res&=crGetIPforK2onK1(hCR,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)==0);
   crSetK2(hCR,crKey2);
   res&=crGetIPforK2onK1(hCR,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)!=0);
   WriteRes(res);

   //  crGetIPforK1onK3
   printf("crGetIPforK1onK3");
   SetBufs(crKey1,crKey2,CRYPTON_KEY_LEN);
   SetBufs(crIP1,crIP2,CRYPTON_IP_LEN);
   crSetK1(hCR,crKey1);
   res=crGetIPforK1onK3(hCR,crIP1);
   res&=crGetIPforK1onK3(hCR,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)==0);
   crSetK1(hCR,crKey2);
   res&=crGetIPforK1onK3(hCR,crIP2);
   res&=(memcmp(crIP1,crIP2,CRYPTON_IP_LEN)!=0);
   WriteRes(res);

   //  crGammaCodeonK1Ex
   printf("crGammaCodeonK1Ex");
   SetEqualBufs(TestBuf1,TestBuf2,TestBufSize);
   crRandom(hCR,CRYPTON_SYNCHRO_LEN,crSync);
   res=crGammaCodeonK1Ex(hCR,TestBufSize,crSync,TestBuf1,TestBuf2);
   res&=(memcmp(TestBuf1,TestBuf2,TestBufSize)!=0);
   SetBufs(TestBuf1,TestBuf3,TestBufSize);
   res&=crGammaCodeonK1Ex(hCR,TestBufSize,crSync,TestBuf1,TestBuf2);
   res&=crGammaCodeonK1Ex(hCR,TestBufSize,crSync,TestBuf2,TestBuf3);
   res&=(memcmp(TestBuf1,TestBuf3,TestBufSize)==0);
   WriteRes(res);

   //  crGammaRecoveryCodeonK1Ex
   printf("crGammaRecoveryCodeonK1Ex");
   SetEqualBufs(TestBuf1,TestBuf2,TestBufSize);
   crRandom(hCR,CRYPTON_SYNCHRO_LEN,crSync);
   res=crGammaRecoveryCodeonK1Ex(hCR,TestBufSize,crSync,TestBuf1,TestBuf2);
   res&=(memcmp(TestBuf1,TestBuf2,TestBufSize)!=0);
   SetBufs(TestBuf1,TestBuf3,TestBufSize);
   res&=crGammaRecoveryCodeonK1Ex(hCR,TestBufSize,crSync,TestBuf1,TestBuf2);
   res&=crGammaRecoveryDecodeonK1Ex(hCR,TestBufSize,crSync,TestBuf2,TestBuf3);
   res&=(memcmp(TestBuf1,TestBuf3,TestBufSize)==0);
   WriteRes(res);

   crDoneService(hCR);               // We don't need this handle any more
  }
  else
    printf("Error starting the service.\n");
  crDoneCryptonLib();                // We aren't going to use Crypton API any more
 }
 else
   printf("Error initialization of the Crypton library.\n");
 printf("\nPress any key...\n"); _getch();
}


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



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

Что же в итоге?


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

Забавно, что в своё время даже существовали вирусы для ПК с такими платами. На сайте ANCUD упоминалась некая программа, которая якобы ускоряла шифрование файлов, тогда как на деле «Криптон» при её запуске и вовсе не использовался, а файлы защищались куда более слабым алгоритмом.

Такие дела.

Ссылки





Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале



Читайте также: