В настоящее время я разрабатываю приложение Silverlight для доступа к X509Store для подписывания данных с помощью закрытого ключа, встроенного в токен безопасности USB.
Я начал с приложения С#, которое работает следующим образом:
public byte[] SignData(byte[] HashTosign, string Cert_To_Use_b64)
{
byte[] Signature = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
store.Close();
try {
foreach (X509Certificate2 Certificate in collection) {
if (ToBase64(Certificate.RawData) == Cert_To_Use_b64) {
RSACryptoServiceProvider Rsa = new RSACryptoServiceProvider();
Rsa = (RSACryptoServiceProvider)Certificate.PrivateKey;
try {
RSACryptoServiceProvider aesRsa = new RSACryptoServiceProvider();
string strPk = Certificate.PrivateKey.ToXmlString(true);
aesRsa.FromXmlString(strPk);
Signature = aesRsa.SignHash(HashTosign, CryptoConfig.MapNameToOID("SHA256"));
} catch (Exception ex) {
Throw new exception("FAILURE : " + ex.Message());
}
lgSignature = Signature.Length;
return 0;
}
}
} catch (CryptographicException ex) {
Throw new exception("FAILURE : " + ex.Message());
} catch (Exception ex) {
Throw new exception("FAILURE : " + ex.Message());
}
}
Этот метод отлично работает в приложении С#. Но когда я пытаюсь адаптировать его к Silverlight, X509Store, похоже, не реализован.
The name "X509Store" does not exist in the namespace System.Security.Cryptography. Are you missing an assembly reference?
Я попытался применить DLL.NET Framework, но получил следующую ошибку:
It is not possible to add a reference to System.Security.dll because it was not created with the Silverlight runtime. Silverlight projects only work with Silverlight assemblies.
Можно ли воссоздать сборку System.Security.dll для Silverlight? Или есть лучшее средство для выполнения того, что я хочу сделать?
Заранее спасибо.
Существует два возможных способа сделать то, что вы хотите:
Мой кулак предполагал использовать собственную библиотеку Windows crypt32.dll (обычно называемую CryptoApi). Ведь System.Security.dll - это всего лишь управляемая оболочка (просмотр декомпилированного источника с помощью инструмента, такого как ILSpy, покажет вам, как MS его обертывает). Вы можете использовать его в Silverlight с P/Invoke при запуске с повышенным доверием (Properties → Silverlight → Требовать повышенное доверие) и правами администратора (чтобы открыть хранилище сертификатов). Однако есть несколько недостатков:
Ссылка на документацию:
Таким образом мне удалось получить дескриптор (указатель IntPtr) для сертификата, зарегистрированного на моей смарт-карте:
using System;
using System.Runtime.InteropServices;
namespace SilverlightX509Store
{
public static class CapiNative
{
public const string MY = "MY";
public const uint PKCS_7_ASN_ENCODING = 0x00010000;
public const uint X509_ASN_ENCODING = 0x00000001;
public const uint CERT_FIND_SUBJECT_STR = 0x00080007;
public const int ACCESS_DENIED = 5;
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertOpenSystemStore(
IntPtr hCryptProv,
string storename);
[DllImport("crypt32.dll", SetLastError = true)]
public static extern IntPtr CertFindCertificateInStore(
IntPtr hCertStore,
uint dwCertEncodingType,
uint dwFindFlags,
uint dwFindType,
[In, MarshalAs(UnmanagedType.LPWStr)]String pszFindString,
IntPtr pPrevCertCntxt);
}
public class CapiWrapper
{
public IntPtr FindCert(string subject)
{
IntPtr storeHandle = CapiNative.CertOpenSystemStore(
IntPtr.Zero,
CapiNative.MY);
if (Marshal.GetLastWin32Error() == CapiNative.ACCESS_DENIED)
{
return IntPtr.Zero;
}
IntPtr certHandle = CapiNative.CertFindCertificateInStore(
storeHandle,
CapiNative.PKCS_7_ASN_ENCODING | CapiNative.X509_ASN_ENCODING,
0,
CapiNative.CERT_FIND_SUBJECT_STR,
"subject to find",
IntPtr.Zero);
return certHandle;
}
}
}
Кажется, есть способ конвертировать.NET-библиотеку в SL. См. Статью Reusing.NET Assemblies в Silverlight. Я еще не тестировал его. Потенциальная проблема может заключаться в том, что шифрование конечной защиты.NET встроено глубоко в mscorlib и System.Security, и может быть не так просто преобразовать эти библиотеки (или даже вообще невозможно).