Не так давно я рассказывал про построенный на базе «гражданского» девайса портативный шифратор «Электроника МК-85С». Самое время поведать миру о ещё одном, не менее значимом, но чуть менее известном девайсе — отечественном криптопроцессоре «Блюминг-1», а также об алгоритме, который который он реализовывал.
Итак, в сегодняшней статье рассмотрим ещё одного представителя российской шифровальной техники — построенную на данном чипе плату шифрования «Криптон». Узнаем, как работает эта штука и где она применялась. Заодно посмотрим на её софт и попробуем что-то зашифровать. Как водится, будет много интересного.
❯ Суть такова
История данного устройства началась в середине семидесятых годов, когда начал разрабатываться алгоритм ГОСТ 28147-89 (он же «Магма-2»), по принципу работы напоминающий DES. Создавался он в ходе проекта по разработки криптографических систем защиты информации на ЭВМ Единой системы. Требования, предъявлявшиеся к нему, были крайне высокими: предполагалось, что шифровать им будут информацию высокой степени секретности, причём сам алгоритм секретным был быть не должен.
В 1987 году было создано и устройство шифрования — криптопроцессор «Блюминг-1», реализующий данный алгоритм. Примечателен он тем, что стал первым отечественным однокристальным шифратором, давшим начало развития целой области средств защиты информации у нас.
А вот и построенная на базе данного чипа плата «Дебют-3». Существовало три версии: «1» для ЭВМ ДВК, «2» — для Системы малых ЭВМ, «3» — для PC с шиной ISA.
Фирма эта работает и сейчас и продолжает заниматься выпуском средств защиты информации (преимущественно для гостайны).
Снова «Криптон-3», но в несколько другом исполнении. Увы, я общался с товарищем, кому удалось её достать, но запустить её не удалось…
❯ Обзор оборудования
Про эти платы не удалось найти практически никакой информации. Даже при банальном поиске «Криптон-4» обнаруживается мало чего. Так что сейчас немного развеем завесу тайны.
Дискеты с софтом.
А вот более старые версии софта. Что от чего, мне неведомо, досталось всё одной кучей.
Ещё один дистрибутив софта — 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-ки.
/////////////////////////////////////////////////////////////////
// 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 "....INCCryptLib.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(" tOKn");
else
printf(" tFALSEn");
}
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 1998n");
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("crTestHardwaret"); WriteRes(crTestHardware(hCR));
// crGetCryptonNumber
printf("crGetCryptonNumbert%in",crGetCryptonNumber(hCR));
// crRandom
printf("crRandomt");
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("crSetK1tt");
crRandom(hCR,CRYPTON_KEY_LEN,crKey1);
WriteRes(crSetK1(hCR,crKey1));
// crSetK2
printf("crSetK2tt");
crRandom(hCR,CRYPTON_KEY_LEN,crKey1);
WriteRes(crSetK2(hCR,crKey1));
// crSetK1onK2
printf("crSetK1onK2t");
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("crGetK1onK2t");
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("crGetK2onK1t");
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("crSetK2onK3t");
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("crGetK2onK3t");
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("crSetK1onK3t");
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("crGetK1onK3t");
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 упоминалась некая программа, которая якобы ускоряла шифрование файлов, тогда как на деле «Криптон» при её запуске и вовсе не использовался, а файлы защищались куда более слабым алгоритмом.
Такие дела.
❯ Ссылки
- Тема на «Полигоне»
- Юбилей АНКАДа
- Сам АНКАД
- Ещё немного скриншотов и описание работы
- Весь
софт, какой смог найти - История создания первых отечественных шифропроцессоров «Блюминг» и аппаратных шифраторов на их основе
Читайте также:
Автор: MaFrance351