我目前正在开发一个Silverlight应用程序,以便访问X509Store,使用嵌入USB安全令牌中的私钥对数据进行签名。
我从一个以这种方式工作的C#应用程序开始:
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());
}
}
该方法在C#应用程序中运行良好。但是当我尝试将其改编为Silverlight时,X509Store似乎没有实现。
The name “X509Store” does not exist in the namespace System.Security.Cryptography. Are you missing an assembly reference?
我尝试应用.NET Framework DLL但出现以下错误:
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吗?或者有更好的方法来做我想做的事情吗?
提前致谢。
答案 0 :(得分:3)
有两种方法可以做你想做的事:
我的第一个猜测是使用本机Windows库crypt32.dll(通常称为CryptoApi)。毕竟System.Security.dll只是一个托管包装器(使用像ILSpy这样的工具浏览反编译源将向您展示MS如何包装它)。当您在提升信任(属性 - > Silverlight - >需要提升信任)和管理员权限(能够打开证书存储区)中运行时,您可以在带有P / Invoke的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 in Silverlight。 我还没有测试过它。潜在的问题可能是.NET安全端加密深入到mscorlib和System.Security中,转换这些库可能并不那么容易(甚至根本不可能)。