NET上的RSA和SignedCms;需要多平台方法 [英] RSA and SignedCms on ASP .Net Core; multiplatform approach needed

查看:98
本文介绍了NET上的RSA和SignedCms;需要多平台方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试找到一种可在多平台上运行的APK SF文件的证书签名方法。暂时没有成功;



签名(两者共同)



我正在使用发行人和序列号进行签名:

 私有静态字节[] GetSigned(byte [] sfData,X509Certificate cert ){
X509Certificate2证书=新的X509Certificate2(cert.GetEncoded());
RSA rsaPriv = Certificate.ToRSA(cert.KeyPair.Private为RsaPrivateCrtKeyParameters);
X509Certificate2 certWithKey = RSACertificateExtensions.CopyWithPrivateKey(certificate,rsaPriv);

ContentInfo内容=新的ContentInfo(sfData);
SignedCmssignedCms = new SignedCms(content,true);
CmsSigner签名者=新的CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber,certWithKey);
signedCms.ComputeSignature(签名者);
returnsignedCms.Encode();
}

Windows解决方案

 公共静态RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
{
return CreateRSAProvider(ToRSAParameters(privKey));
}

私有静态RSA CreateRSAProvider(RSAParameters rp)
{
CspParameters csp = new CspParameters
{
KeyContainerName = string.Format( BouncyCastle- {0},Guid.NewGuid()),
标志= CspProviderFlags.UseMachineKeyStore
};

//这是在没有机器可用时回退到用户密钥库的解决方法;
// //否则将无法在Azure和本地工作。
//在ASP .Net内核上,更多的是这种加密方法的错误。
RSACryptoServiceProvider rsaCsp;
try
{
rsaCsp =新的RSACryptoServiceProvider(csp);
} catch(异常例外)
{
csp.Flags = CspProviderFlags.NoFlags;
rsaCsp =新的RSACryptoServiceProvider(csp);
}

rsaCsp.ImportParameters(rp);
return rsaCsp;
}

私有静态RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
{
RSAParameters rp = new RSAParameters();
rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
rp.P = privKey.P.ToByteArrayUnsigned();
rp.Q = privKey.Q.ToByteArrayUnsigned();
rp.D = ConvertRSAParametersField(privKey.Exponent,rp.Modulus.Length);
rp.DP = ConvertRSAParametersField(privKey.DP,rp.P.Length);
rp.DQ = ConvertRSAParametersField(privKey.DQ,rp.Q.Length);
rp.InverseQ = ConvertRSAParametersField(privKey.QInv,rp.Q.Length);
返回rp;
}

Linux解决方案



在此 stackoverflow答案之后,我使用了RSA ;像这样:

 公共静态RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
{
var rp = ToRSAParameters(privKey) ;
返回RSA.Create(rp);
}

在Windows上使用Linux解决方案时,出现以下异常

  [31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81] System.ArgumentException:检测到正在打开的CNG密钥句柄是短暂的,但未指定EphemeralKey打开选项。 
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81]参数名称:keyHandleOpenOptions
[31/​​01/2019 16:26:09信息性] [xUnit .net 00:00:03.81]堆栈跟踪:
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81]位于System.Security.Cryptography.CngKey.Open(SafeNCryptKeyHandle keyHandle,CngKeyHandleOpenOptions keyHandleOpenOptions)
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81]在Internal.Cryptography.Pal.Windows.PkcsPalWindows.GetPrivateKey [T](X509Certificate2证书) ,布尔值无声,布尔值preferredNCrypt)
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81]在Internal.Cryptography.Pal.Windows.PkcsPalWindows.GetPrivateKeyForSigning [T]( X509Certificate2证书,布尔型无声)
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81]在System.Security.Cryptography.Pkcs.CmsSignature.RSAPkcs1CmsSignature.Sign(ReadOnlySpan` 1个dataHash,HashAlgorithmName ha shAlgorithmName,X509Certificate2证书,布尔值无声,Oid& signatureAlgorithm,Byte []& signatureValue)
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81]在System.Security.Cryptography.Pkcs.CmsSignature.Sign(ReadOnlySpan`1 dataHash,HashAlgorithmName hashAlgorithmName, X509Certificate2证书,布尔值无声,Oid& oid,ReadOnlyMemory`1& signatureValue)
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81]在System.Security.Cryptography中。 Pkcs.CmsSigner.Sign(ReadOnlyMemory`1 data,String contentTypeOid,Booleansilent,X509Certificate2Collection& chainCerts)
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81]在系统上.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner签名者,布尔无声)
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81] C:\workspace\ \kleidi\Kleidi\Signing\APK\ApkSigner.cs(176,0):at Kleidi.Signing.APK.ApkSigner.GetRSAData(ZipFile zip,Byte [] sfData,String rsaName,Bundle cert)
[31/​​01/2019 16:26:09信息性] [xUni t.net 00:00:03.81] C:\workspace\kleidi\Kleidi\Signing\APK\ApkSigner.cs(58,0):at Kleidi.Signing.APK.ApkSigner.Sign(Stream srcApkStream ,Stream& dstApkStream,包certBundle,字符串sharedKey,字符串generationId)
[31/​​01/2019 16:26:09信息性] [xUnit.net 00:00:03.81] C:\workspace\kleidi\KleidiTests\ \Signing\APK\ApkSignerTest.cs(23,0):在Kleidi.Signing.APK.ApkSignerTest.Valid_signature_and_certificate_match()

问题是..



任何人都知道一种对两者都有效的方法吗?
还是我应该推断操作系统正在构建我,然后再使用其中一个? (听起来很丑)

解决方案

似乎SignedCms类无法打开通过CopyWithPrivateKey操作的密钥。对于这种情况下发生的任何奇怪的事情,快速而肮脏的解决方法是进行临时PFX导出并重新导入,因此请替换

  X509Certificate2 certWithKey = RSACertificateExtensions.CopyWithPrivateKey(certificate,rsaPriv); 

类似

 使用(X509Certificate2 temp = certificate.CopyWithPrivateKey(rsaPriv))
使用(X509Certificate2 certWithKey = new X509Certificate2(temp.Export(X509ContentType.Pfx))
{
//在以下位置构建CmsSigner并调用ComputeSignature:
}

FWIW:现在是CoreFX错误: https://github.com/dotnet/corefx/issues/35120 。。 p>

I am trying to find a way to do certificate signature of an APK SF file, in a way that works multiplatform. Without success at the minute; exaplanation of what I am doing.

Signing ( common for both )

I am doing a signature with issuer and serial number with:

private static byte[] GetSigned(byte[] sfData, X509Certificate cert){
   X509Certificate2 certificate = new X509Certificate2(cert.GetEncoded());
   RSA rsaPriv = Certificate.ToRSA(cert.KeyPair.Private as RsaPrivateCrtKeyParameters);
   X509Certificate2 certWithKey = RSACertificateExtensions.CopyWithPrivateKey(certificate, rsaPriv);

   ContentInfo content = new ContentInfo(sfData);
   SignedCms signedCms = new SignedCms(content, true);
   CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certWithKey);
   signedCms.ComputeSignature(signer);
   return signedCms.Encode();
}

Windows solution

public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
        {
            return CreateRSAProvider(ToRSAParameters(privKey));
        }

        private static RSA CreateRSAProvider(RSAParameters rp)
        {
            CspParameters csp = new CspParameters
            {
                KeyContainerName = string.Format("BouncyCastle-{0}", Guid.NewGuid()),
                Flags = CspProviderFlags.UseMachineKeyStore
            };

            // This is a workaround to fallback to user keystore while not machine is available;
            // as otherwise it's impossible having something working on Azure and locally.
            // It's more a bug of this cryptography stuff on ASP .Net core..
            RSACryptoServiceProvider rsaCsp;
            try
            {
                rsaCsp = new RSACryptoServiceProvider(csp);
            }catch(Exception ex)
            {
                csp.Flags = CspProviderFlags.NoFlags;
                rsaCsp = new RSACryptoServiceProvider(csp);
            }

            rsaCsp.ImportParameters(rp);
            return rsaCsp;
        }

        private static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
        {
            RSAParameters rp = new RSAParameters();
            rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
            rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
            rp.P = privKey.P.ToByteArrayUnsigned();
            rp.Q = privKey.Q.ToByteArrayUnsigned();
            rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length);
            rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length);
            rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length);
            rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length);
            return rp;
        }

Linux solution

Following this stackoverflow answer, I've used RSA; like:

public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
        {
            var rp = ToRSAParameters(privKey);
            return RSA.Create(rp);
        }

While using Linux solution on Windows, I got the following exception

[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]       System.ArgumentException : The CNG key handle being opened was detected to be ephemeral, but the EphemeralKey open option was not specified.
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]       Parameter name: keyHandleOpenOptions
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]       Stack Trace:
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]            at System.Security.Cryptography.CngKey.Open(SafeNCryptKeyHandle keyHandle, CngKeyHandleOpenOptions keyHandleOpenOptions)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]            at Internal.Cryptography.Pal.Windows.PkcsPalWindows.GetPrivateKey[T](X509Certificate2 certificate, Boolean silent, Boolean preferNCrypt)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]            at Internal.Cryptography.Pal.Windows.PkcsPalWindows.GetPrivateKeyForSigning[T](X509Certificate2 certificate, Boolean silent)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]            at System.Security.Cryptography.Pkcs.CmsSignature.RSAPkcs1CmsSignature.Sign(ReadOnlySpan`1 dataHash, HashAlgorithmName hashAlgorithmName, X509Certificate2 certificate, Boolean silent, Oid& signatureAlgorithm, Byte[]& signatureValue)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]            at System.Security.Cryptography.Pkcs.CmsSignature.Sign(ReadOnlySpan`1 dataHash, HashAlgorithmName hashAlgorithmName, X509Certificate2 certificate, Boolean silent, Oid& oid, ReadOnlyMemory`1& signatureValue)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]            at System.Security.Cryptography.Pkcs.CmsSigner.Sign(ReadOnlyMemory`1 data, String contentTypeOid, Boolean silent, X509Certificate2Collection& chainCerts)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]            at System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner signer, Boolean silent)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]         C:\workspace\kleidi\Kleidi\Signing\APK\ApkSigner.cs(176,0): at Kleidi.Signing.APK.ApkSigner.GetRSAData(ZipFile zip, Byte[] sfData, String rsaName, Bundle cert)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]         C:\workspace\kleidi\Kleidi\Signing\APK\ApkSigner.cs(58,0): at Kleidi.Signing.APK.ApkSigner.Sign(Stream srcApkStream, Stream& dstApkStream, Bundle certBundle, String sharedKey, String generationId)
[31/01/2019 16:26:09 Informational] [xUnit.net 00:00:03.81]         C:\workspace\kleidi\KleidiTests\Signing\APK\ApkSignerTest.cs(23,0): at Kleidi.Signing.APK.ApkSignerTest.Valid_signature_and_certificate_match()

Question is..

Anyone knows a way that works for both? or should I infere the operative system is building me and then use one or other ? (sounds ugly)

解决方案

It looks like the SignedCms class is having trouble opening the key that was manipulated via CopyWithPrivateKey. The quick-and-dirty workaround for anything weird happening in that situation is to make a temporary PFX export and reimport it, so replace

X509Certificate2 certWithKey = RSACertificateExtensions.CopyWithPrivateKey(certificate, rsaPriv);

with something like

using (X509Certificate2 temp = certificate.CopyWithPrivateKey(rsaPriv))
using (X509Certificate2 certWithKey = new X509Certificate2(temp.Export(X509ContentType.Pfx))
{
    // Build CmsSigner and call ComputeSignature here.
}

FWIW: This is now a CoreFX bug: https://github.com/dotnet/corefx/issues/35120.

这篇关于NET上的RSA和SignedCms;需要多平台方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆