Re: pkcs11, получить публичный ключ
Давайте проще, без купюр
index.html
<!DOCTYPE html>
<html lang="ru">
<head>
<title>Тест рутокен</title>
<script type="text/javascript" src="app.js"></script>
</head>
<object id="pluginRutokenWEB" type="application/x-rutoken" width="0" height="0"><param name="onload" value="pluginit" /></object>
<body>
</body>
</html>
app.js
window.onload = function () {
// Загрузка плагина
plugin = document.getElementById("pluginRutokenWEB");
// Проверка плагина на валидность
if (plugin && plugin.valid) {
// Показать версию плагина
document.body.innerHTML += "<br>Установлен плагин Рутокен WEB версии " + plugin.get_version();
// Проверка наличия токена в системе
if (plugin.rtwIsTokenPresentAndOK()) {
// теперь пробуем стандартную процедуру аутентификации rutoken
// сначала пошлем запрос на аутентификацию:
sendjson({ requesttype: 'authentificationrequest', id: plugin.rtwGetDeviceID() },
function (e) {
var r = JSON.parse(e.currentTarget.response);
sendjson({
requesttype: 'authentificationdata',
signedhash: plugin.rtwSign('178', r.random),
publickey: plugin.rtwGetPublicKey('178')
},
function (e) { if (this.status === 200) { document.body.innerHTML += "<br> received: " + this.responseText; } }
);
}
);
} else { window.alert("Рутокен WEB не подключен"); } return;
} else { window.alert("Установите плагин Рутокен WEB"); }
};
function sendjson(jsondata,callback) {
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:6266/load.ashx', true); // у вас тут видимо будет другой порт
xhr.onload = callback;
xhr.send(JSON.stringify(jsondata));
}
load.ashx.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Rutoken;
using Net.Pkcs11Interop.Common;
using Net.Pkcs11Interop.HighLevelAPI;
using RutokenPkcs11Interop;
using RutokenPkcs11Interop.Common;
namespace rutokenweb
{
public class Load : IHttpHandler
{
// Шаблон для поиска закрытого ключа для цифровой подписи
static readonly List<ObjectAttribute> PrivateKeyAttributes = new List<ObjectAttribute>
{
// ID пары
new ObjectAttribute(CKA.CKA_ID, "178"),
// Класс - закрытый ключ
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY)
};
// Шаблон для поиска открытого ключа для проверки цифровой подписи
static readonly List<ObjectAttribute> PublicKeyAttributes = new List<ObjectAttribute>
{
// ID пары
new ObjectAttribute(CKA.CKA_ID,"178"),
// // Класс - открытый ключ
new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PUBLIC_KEY)
};
// словарь для представления пришедшего json запроса
public static Dictionary<String, String> ext = new Dictionary<String, String>();
public static string userhash = "";
public void ProcessRequest(HttpContext context)
{
HttpResponse response = context.Response;
// переводим запрос в строку
string ss = GetAsString(context);
// полученную json строку превращаем в словарь C#
JsonToDic(ss);
switch(ext["requesttype"])
{
case "authentificationrequest":
userhash = RutokenWeb.GetRandomHash();
response.Write("{\"random\":\"" + userhash + "\"}");
break;
case "authentificationdata":
bool Auth = RutokenWeb.CheckSignature(ext["signedhash"], userhash, ext["publickey"]);
if (Auth) { response.Write("<br>Auth OK"); }
else { response.Write("<br>Auth none"); }
using (var pkcs11 = new Pkcs11(Settings.RutokenEcpDllDefaultPath, Settings.OsLockingDefault))
{
Console.WriteLine("Checking tokens available");
Slot slot = Helpers.GetUsableSlot(pkcs11);
List<CKM> mechanisms = slot.GetMechanismList();
bool isGostR3410Supported = mechanisms.Contains((CKM)Extended_CKM.CKM_GOSTR3410);
bool isGostR3411Supported = mechanisms.Contains((CKM)Extended_CKM.CKM_GOSTR3411);
using (Session session = slot.OpenSession(false))
{
session.Login(CKU.CKU_USER, "12345678");
List<ObjectHandle> privateKeys = session.FindAllObjects(PrivateKeyAttributes);
List<ObjectHandle> publicKeys = session.FindAllObjects(PublicKeyAttributes);
byte[] hash = StringToByteArray(userhash);
// Инициализация операции подписи данных по алгоритму ГОСТ Р 34.10-2001
var signMechanism = new Mechanism((uint)Extended_CKM.CKM_GOSTR3410);
// Подписать данные
byte[] signature = session.Sign(signMechanism, privateKeys[0], hash);
// собственная проверка
session.Verify(signMechanism, publicKeys[0], hash, signature, out bool isSignatureValid);
// преобразуем подписанный хэш в строку
string sig1 = ByteArrayToString(signature);
// конвертим строку
string sig = Hash32Convert(sig1);
// читаем открытый ключ
var x = session.GetAttributeValue(publicKeys[0], new List<CKA> { CKA.CKA_VALUE });
// в строку
var y = ByteArrayToString( x[0].GetValueAsByteArray());
// конвертим строку
var z = Key64Convert(y);
bool signed = RutokenWeb.CheckSignature(sig, userhash, z);
}
}
break;
default: break;
}
ext.Clear();
}
public string GetAsString(HttpContext cnt)
{
string o = "";
System.IO.Stream s = cnt.Request.GetBufferedInputStream();
while (true) { int c = s.ReadByte(); if (c < 0) break; else o += ((char)c); }
return o;
}
public void JsonToDic(string j)
{
Regex r = new Regex("\"([^\"]+)\":\"([^\"]+)\"", RegexOptions.Singleline);
Match m = r.Match(j);
while (m.Success) { ext.Add(m.Groups[1].ToString(), m.Groups[2].ToString()); m = m.NextMatch(); }
}
public string ByteArrayToString(byte[] a)
{
StringBuilder o = new StringBuilder(a.Length * 2);
for (int i = 0; i < a.Length; i++) o.Append(a[i].ToString("x2"));
return o.ToString();
}
public byte[] StringToByteArray(string s)
{
string ss = s.ToUpper();
byte[] o = new byte[s.Length / 2];
for (int i = 0; i < s.Length / 2; i++) o[i] = (byte)int.Parse(s.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
return o;
}
public string Key64Convert(string PKCSKey)
{
string JSKey = "";
for (var i = 31; i >= 0; i--) { JSKey += PKCSKey[2 * i]; JSKey += PKCSKey[2 * i + 1]; }
for (var i = 63; i >= 32; i--) { JSKey += PKCSKey[2 * i]; JSKey += PKCSKey[2 * i + 1]; }
return JSKey;
}
public string BigToLittle(string s)
{
string o = "";
for (var i = 0; i < s.Length/8; i++) {
o += s[8 * i + 6]; o += s[8 * i + 7]; o += s[8 * i + 4]; o += s[8 * i + 5];
o += s[8 * i + 2]; o += s[8 * i + 3]; o += s[8 * i]; o += s[8 * i + 1];
}
return o;
}
public string Hash32Convert(string s)
{
string o = "";
for (var i = (s.Length)/2-1; i >= 0; i--) { o += s[2 * i]; o += s[2 * i + 1]; }
return o;
}
public bool IsReusable
{
get
{
return false;
}
}
}
public static class Helpers
{
public static Slot GetUsableSlot(Pkcs11 pkcs11)
{
// Получить список слотов c подключенными токенами
List<Slot> slots = pkcs11.GetSlotList(true);
// Проверить, что слоты найдены
if (slots == null)
throw new NullReferenceException("No available slots");
// Проверить, что число слотов больше 0
if (slots.Count <= 0)
throw new InvalidOperationException("No available slots");
// Получить первый доступный слот
Slot slot = slots[0];
return slot;
}
public static void PrintByteArray(byte[] array)
{
var hexString = new StringBuilder();
var width = 16;
int byteCounter = 1;
foreach (var item in array)
{
hexString.AppendFormat(" 0x{0:x2}", item);
if (byteCounter == width)
{
hexString.AppendLine();
byteCounter = 0;
}
byteCounter++;
}
Console.WriteLine(hexString);
}
}
}