C# RSACryptoServiceProvider(.NET';s RSA)能否使用SHA256而不是SHA1进行加密(非签名)?
加密时,RSACryptServiceProvider(或.NET提供的任何其他RSA加密程序)是否可以使用SHA256而不是SHA1 SHA1似乎是硬编码的,无法更改。例如,RSACryptServiceProvider.SignatureAlgorithm被硬编码为返回“http://www.w3.org/2000/09/xmldsig#rsa-sha1” 如果无法让RSACryptoServiceProvider使用SHA256,有哪些替代方案C# RSACryptoServiceProvider(.NET';s RSA)能否使用SHA256而不是SHA1进行加密(非签名)?,c#,cryptography,rsa,C#,Cryptography,Rsa,加密时,RSACryptServiceProvider(或.NET提供的任何其他RSA加密程序)是否可以使用SHA256而不是SHA1 SHA1似乎是硬编码的,无法更改。例如,RSACryptServiceProvider.SignatureAlgorithm被硬编码为返回“http://www.w3.org/2000/09/xmldsig#rsa-sha1” 如果无法让RSACryptoServiceProvider使用SHA256,有哪些替代方案 更新 下面的代码工作得很好,但我想将OAE
更新 下面的代码工作得很好,但我想将OAEPwithsha1和mgf1填充更改为OAEPwithsha256和mgf1填充。C端需要什么才能使用SHA256而不是SHA1进行加密 加密在C#中完成,使用: 解密在Java中通过以下方式完成:
Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
byte[] cipherText = ...;
byte[] plainText = cipher.doFinal(cipherText);
从任何Windows Server 2003和更高版本操作系统上的.NET 3.5 SP1开始,RSACryptServiceProvider都支持RSA-SHA256进行签名,但不支持加密 从博客帖子:
不过,你应该阅读原始帖子,因为有一些问题需要注意。如果没有办法让RSACryptServiceProvider处理OAEP-with-SHA-256(其他人的答案似乎说明了这一点),那么你仍然可以自己实现该操作。我们讨论的是加密部分,它只使用公钥。公钥是公共的,这意味着您可以导出它(实际上,在您的代码中,您已经有了模数和指数作为字节数组),而且由于这里没有密钥,所以通过一个粗心的实现不会出现关于机密数据泄漏的问题 实施OAEP包括以下内容:
- 遵循第7.1节。这会将要加密的数据转换为长度与RSA模数相同的字节序列。您需要一个SHA-256实现(
)和一个加密质量源alea(System.Security.Cryptography.SHA256Managed
)System.Security.Cryptography.RandomNumberGenerator
- 将结果序列解码为大整数,执行模幂运算(模n,RSA模),并将结果编码为与模长度相同的另一个字节序列。编码规则是大端、无符号位和固定大小(如果这是一个1024位RSA密钥,意味着在这个问题被问答之后,21023
被更新为1.7。为了将来的引用,你可以考虑它,它支持很多密码算法,散列,有弹力城堡的签名可以用于java。点击链接,寻找‘1.7的发行说明’和‘当前特征列表:’。”/p> RSACryptServiceProvider确实使用基于SHA2的签名,但您必须投入一些精力
当您使用证书获取RSACryptoServiceProvider时,底层CryptoAPI提供程序确实很重要。默认情况下,当您使用“makecert”创建证书时,它是“RSA-FULL”,仅支持SHA1哈希签名。您需要支持SHA2的新“RSA-AES”证书 因此,您可以使用一个附加选项创建证书:-sp“Microsoft增强的RSA和AES加密提供程序”(或等效的-sy 24),然后您的代码将如下所示(在.NET 4.0中): 如果您无法更改证书的颁发方式,则有一个半LigiMate解决方案,它基于以下事实:默认情况下,RSACryptServiceProvider是在支持SHA2的情况下创建的。因此,以下代码也可以工作,但有点难看:(此代码的作用是创建一个新的RSACryptServiceProvider,并从证书中获取的密钥导入密钥)
这里的所有其他答案都是关于使用SHA256进行签名,而不是加密。我将实际回答这个问题 任何SHA-2或更高的算法都是用于散列的,不一定是加密/解密的,但这并不意味着你不能使用这些算法生成密钥,然后对它们进行加密/解密。从技术上讲,我要提醒那些反对这个答案的人,这不是“用SHA256加密”,但它确实允许RSA使用使用该算法生成的散列密钥。让您的特定组织决定这是否足以符合NIST/FIPS,如果这是您的原因,就像我在研究此问题时一样 加密(使用RSA或其他非对称加密算法)只需要一个公钥(用于加密)和一个私钥(用于解密)。一旦使用该散列创建密钥,就可以对它们进行加密/解密 我将把我做的一些研究拼凑起来,展示几种方法,你可以使用使用SHA-256散列创建的密钥,然后对其进行加密/解密。你可以通过创建证书或让RSACryptServiceContainer给你一个证书来生成SHA-256密钥 证书方法 在命令行中使用以下行创建证书:
然后将证书导入本地根权限存储并使用以下代码:makecert -r -pe -n "CN=MyCertificate" -a sha256 -b 09/01/2016 -sky exchange C:\Temp\MyCertificate.cer -sv C:\Temp\MyCertificate.pvk pvk2pfx.exe -pvk C:\Temp\MyCertificate.pvk -pi "MyP@ssw0rd" -spc C:\Temp\MyCertificate.cer -pfx C:\Temp\MyCertificate.pfx -po "MyP@ssw0rd"
如果您想使用SHA512,您只需在制作证书时将该参数更改为string input = "test"; string output = string.Empty; X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, "MyCertificate", false); X509Certificate2 certificate = collection[0]; using (RSACryptoServiceProvider cps = (RSACryptoServiceProvider)certificate.PublicKey.Key) { byte[] bytesData = Encoding.UTF8.GetBytes(input); byte[] bytesEncrypted = cps.Encrypt(bytesData, false); output = Convert.ToBase64String(bytesEncrypted); } store.Close();
参考: 使用RSACryptServiceProvider生成密钥SHA512
private static string privateKey = String.Empty; private static void generateKeys() { int dwLen = 2048; RSACryptoServiceProvider csp = new RSACryptoServiceProvider(dwLen); privateKey = csp.ToXmlString(true).Replace("><",">\r\n"); } public static string Encrypt(string data2Encrypt) { try { generateKeys(); RSAx rsax = new RSAx(privateKey, 2048); rsax.RSAxHashAlgorithm = RSAxParameters.RSAxHashAlgorithm.SHA256; byte[] CT = rsax.Encrypt(Encoding.UTF8.GetBytes(data2Encrypt), false, true); // first bool is for using private key (false forces to use public), 2nd is for using OAEP return Convert.ToBase64String(CT); } catch (Exception ex) { // handle exception MessageBox.Show("Error during encryption: " + ex.Message); return String.Empty; } } public static string Decrypt(string data2Decrypt) { try { RSAx rsax = new RSAx(privateKey, 2048); rsax.RSAxHashAlgorithm = RSAxParameters.RSAxHashAlgorithm.SHA256; byte[] PT = rsax.Decrypt(Convert.FromBase64String(data2Decrypt), true, true); // first bool is for using private key, 2nd is for using OAEP return Encoding.UTF8.GetString(PT); } catch (Exception ex) { // handle exception MessageBox.Show("Error during encryption: " + ex.Message); return String.Empty; } }
// @Date : 15th July 2012 // @Author : Arpan Jati (arpan4017@yahoo.com; arpan4017@gmail.com) // @Library : ArpanTECH.RSAx // @CodeProject: http://www.codeproject.com/Articles/421656/RSA-Library-with-Private-Key-Encryption-in-Csharp using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Numerics; using System.Linq; using System.Text; using System.IO; namespace ArpanTECH { /// <summary> /// The main RSAx Class /// </summary> public class RSAx : IDisposable { private RSAxParameters rsaParams; private RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); /// <summary> /// Initialize the RSA class. /// </summary> /// <param name="rsaParams">Preallocated RSAxParameters containing the required keys.</param> public RSAx(RSAxParameters rsaParams) { this.rsaParams = rsaParams; UseCRTForPublicDecryption = true; } /// <summary> /// Initialize the RSA class from a XML KeyInfo string. /// </summary> /// <param name="keyInfo">XML Containing Key Information</param> /// <param name="ModulusSize">Length of RSA Modulus in bits.</param> public RSAx(String keyInfo, int ModulusSize) { this.rsaParams = RSAxUtils.GetRSAxParameters(keyInfo, ModulusSize); UseCRTForPublicDecryption = true; } /// <summary> /// Hash Algorithm to be used for OAEP encoding. /// </summary> public RSAxParameters.RSAxHashAlgorithm RSAxHashAlgorithm { set { rsaParams.HashAlgorithm = value; } } /// <summary> /// If True, and if the parameters are available, uses CRT for private key decryption. (Much Faster) /// </summary> public bool UseCRTForPublicDecryption { get; set; } /// <summary> /// Releases all the resources. /// </summary> public void Dispose() { rsaParams.Dispose(); } #region PRIVATE FUNCTIONS /// <summary> /// Low level RSA Process function for use with private key. /// Should never be used; Because without padding RSA is vulnerable to attacks. Use with caution. /// </summary> /// <param name="PlainText">Data to encrypt. Length must be less than Modulus size in octets.</param> /// <param name="usePrivate">True to use Private key, else Public.</param> /// <returns>Encrypted Data</returns> public byte[] RSAProcess(byte[] PlainText, bool usePrivate) { if (usePrivate && (!rsaParams.Has_PRIVATE_Info)) { throw new CryptographicException("RSA Process: Incomplete Private Key Info"); } if ((usePrivate == false) && (!rsaParams.Has_PUBLIC_Info)) { throw new CryptographicException("RSA Process: Incomplete Public Key Info"); } BigInteger _E; if (usePrivate) _E = rsaParams.D; else _E = rsaParams.E; BigInteger PT = RSAxUtils.OS2IP(PlainText, false); BigInteger M = BigInteger.ModPow(PT, _E, rsaParams.N); if (M.Sign == -1) return RSAxUtils.I2OSP(M + rsaParams.N, rsaParams.OctetsInModulus, false); else return RSAxUtils.I2OSP(M, rsaParams.OctetsInModulus, false); } /// <summary> /// Low level RSA Decryption function for use with private key. Uses CRT and is Much faster. /// Should never be used; Because without padding RSA is vulnerable to attacks. Use with caution. /// </summary> /// <param name="Data">Data to encrypt. Length must be less than Modulus size in octets.</param> /// <returns>Encrypted Data</returns> public byte[] RSADecryptPrivateCRT(byte[] Data) { if (rsaParams.Has_PRIVATE_Info && rsaParams.HasCRTInfo) { BigInteger C = RSAxUtils.OS2IP(Data, false); BigInteger M1 = BigInteger.ModPow(C, rsaParams.DP, rsaParams.P); BigInteger M2 = BigInteger.ModPow(C, rsaParams.DQ, rsaParams.Q); BigInteger H = ((M1 - M2) * rsaParams.InverseQ) % rsaParams.P; BigInteger M = (M2 + (rsaParams.Q * H)); if (M.Sign == -1) return RSAxUtils.I2OSP(M + rsaParams.N, rsaParams.OctetsInModulus, false); else return RSAxUtils.I2OSP(M, rsaParams.OctetsInModulus, false); } else { throw new CryptographicException("RSA Decrypt CRT: Incomplete Key Info"); } } private byte[] RSAProcessEncodePKCS(byte[] Message, bool usePrivate) { if (Message.Length > rsaParams.OctetsInModulus - 11) { throw new ArgumentException("Message too long."); } else { // RFC3447 : Page 24. [RSAES-PKCS1-V1_5-ENCRYPT ((n, e), M)] // EM = 0x00 || 0x02 || PS || 0x00 || Msg List<byte> PCKSv15_Msg = new List<byte>(); PCKSv15_Msg.Add(0x00); PCKSv15_Msg.Add(0x02); int PaddingLength = rsaParams.OctetsInModulus - Message.Length - 3; byte[] PS = new byte[PaddingLength]; rng.GetNonZeroBytes(PS); PCKSv15_Msg.AddRange(PS); PCKSv15_Msg.Add(0x00); PCKSv15_Msg.AddRange(Message); return RSAProcess(PCKSv15_Msg.ToArray() , usePrivate); } } /// <summary> /// Mask Generation Function /// </summary> /// <param name="Z">Initial pseudorandom Seed.</param> /// <param name="l">Length of output required.</param> /// <returns></returns> private byte[] MGF(byte[] Z, int l) { if (l > (Math.Pow(2, 32))) { throw new ArgumentException("Mask too long."); } else { List<byte> result = new List<byte>(); for (int i = 0; i <= l / rsaParams.hLen; i++) { List<byte> data = new List<byte>(); data.AddRange(Z); data.AddRange(RSAxUtils.I2OSP(i, 4, false)); result.AddRange(rsaParams.ComputeHash(data.ToArray())); } if (l <= result.Count) { return result.GetRange(0, l).ToArray(); } else { throw new ArgumentException("Invalid Mask Length."); } } } private byte[] RSAProcessEncodeOAEP(byte[] M, byte[] P, bool usePrivate) { // +----------+---------+-------+ // DB = | lHash | PS | M | // +----------+---------+-------+ // | // +----------+ V // | seed |--> MGF ---> XOR // +----------+ | // | | // +--+ V | // |00| XOR <----- MGF <-----| // +--+ | | // | | | // V V V // +--+----------+----------------------------+ // EM = |00|maskedSeed| maskedDB | // +--+----------+----------------------------+ int mLen = M.Length; if (mLen > rsaParams.OctetsInModulus - 2 * rsaParams.hLen - 2) { throw new ArgumentException("Message too long."); } else { byte[] PS = new byte[rsaParams.OctetsInModulus - mLen - 2 * rsaParams.hLen - 2]; //4. pHash = Hash(P), byte[] pHash = rsaParams.ComputeHash(P); //5. DB = pHash||PS||01||M. List<byte> _DB = new List<byte>(); _DB.AddRange(pHash); _DB.AddRange(PS); _DB.Add(0x01); _DB.AddRange(M); byte[] DB = _DB.ToArray(); //6. Generate a random octet string seed of length hLen. byte[] seed = new byte[rsaParams.hLen]; rng.GetBytes(seed); //7. dbMask = MGF(seed, k - hLen -1). byte[] dbMask = MGF(seed, rsaParams.OctetsInModulus - rsaParams.hLen - 1); //8. maskedDB = DB XOR dbMask byte[] maskedDB = RSAxUtils.XOR(DB, dbMask); //9. seedMask = MGF(maskedDB, hLen) byte[] seedMask = MGF(maskedDB, rsaParams.hLen); //10. maskedSeed = seed XOR seedMask. byte[] maskedSeed = RSAxUtils.XOR(seed, seedMask); //11. EM = 0x00 || maskedSeed || maskedDB. List<byte> result = new List<byte>(); result.Add(0x00); result.AddRange(maskedSeed); result.AddRange(maskedDB); return RSAProcess(result.ToArray(), usePrivate); } } private byte[] Decrypt(byte[] Message, byte [] Parameters, bool usePrivate, bool fOAEP) { byte[] EM = new byte[0]; try { if ((usePrivate == true) && (UseCRTForPublicDecryption) && (rsaParams.HasCRTInfo)) { EM = RSADecryptPrivateCRT(Message); } else { EM = RSAProcess(Message, usePrivate); } } catch (CryptographicException ex) { throw new CryptographicException("Exception while Decryption: " + ex.Message); } catch { throw new Exception("Exception while Decryption: "); } try { if (fOAEP) //DECODE OAEP { if ((EM.Length == rsaParams.OctetsInModulus) && (EM.Length > (2 * rsaParams.hLen + 1))) { byte[] maskedSeed; byte[] maskedDB; byte[] pHash = rsaParams.ComputeHash(Parameters); if (EM[0] == 0) // RFC3447 Format : http://tools.ietf.org/html/rfc3447 { maskedSeed = EM.ToList().GetRange(1, rsaParams.hLen).ToArray(); maskedDB = EM.ToList().GetRange(1 + rsaParams.hLen, EM.Length - rsaParams.hLen - 1).ToArray(); byte[] seedMask = MGF(maskedDB, rsaParams.hLen); byte[] seed = RSAxUtils.XOR(maskedSeed, seedMask); byte[] dbMask = MGF(seed, rsaParams.OctetsInModulus - rsaParams.hLen - 1); byte[] DB = RSAxUtils.XOR(maskedDB, dbMask); if (DB.Length >= (rsaParams.hLen + 1)) { byte[] _pHash = DB.ToList().GetRange(0, rsaParams.hLen).ToArray(); List<byte> PS_M = DB.ToList().GetRange(rsaParams.hLen, DB.Length - rsaParams.hLen); int pos = PS_M.IndexOf(0x01); if (pos >= 0 && (pos < PS_M.Count)) { List<byte> _01_M = PS_M.GetRange(pos, PS_M.Count - pos); byte[] M; if (_01_M.Count > 1) { M = _01_M.GetRange(1, _01_M.Count - 1).ToArray(); } else { M = new byte[0]; } bool success = true; for (int i = 0; i < rsaParams.hLen; i++) { if (_pHash[i] != pHash[i]) { success = false; break; } } if (success) { return M; } else { M = new byte[rsaParams.OctetsInModulus]; //Hash Match Failure. throw new CryptographicException("OAEP Decode Error"); } } else {// #3: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } } else {// #2: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } } else // Standard : ftp://ftp.rsasecurity.com/pub/rsalabs/rsa_algorithm/rsa-oaep_spec.pdf {//OAEP : THIS STADNARD IS NOT IMPLEMENTED throw new CryptographicException("OAEP Decode Error"); } } else {// #1: Invalid Encoded Message Length. throw new CryptographicException("OAEP Decode Error"); } } else // DECODE PKCS v1.5 { if (EM.Length >= 11) { if ((EM[0] == 0x00) && (EM[1] == 0x02)) { int startIndex = 2; List<byte> PS = new List<byte>(); for (int i = startIndex; i < EM.Length; i++) { if (EM[i] != 0) { PS.Add(EM[i]); } else { break; } } if (PS.Count >= 8) { int DecodedDataIndex = startIndex + PS.Count + 1; if (DecodedDataIndex < (EM.Length - 1)) { List<byte> DATA = new List<byte>(); for (int i = DecodedDataIndex; i < EM.Length; i++) { DATA.Add(EM[i]); } return DATA.ToArray(); } else { return new byte[0]; //throw new CryptographicException("PKCS v1.5 Decode Error #4: No Data"); } } else {// #3: Invalid Key / Invalid Random Data Length throw new CryptographicException("PKCS v1.5 Decode Error"); } } else {// #2: Invalid Key / Invalid Identifiers throw new CryptographicException("PKCS v1.5 Decode Error"); } } else {// #1: Invalid Key / PKCS Encoding throw new CryptographicException("PKCS v1.5 Decode Error"); } } } catch (CryptographicException ex) { throw new CryptographicException("Exception while decoding: " + ex.Message); } catch { throw new CryptographicException("Exception while decoding"); } } #endregion #region PUBLIC FUNCTIONS /// <summary> /// Encrypts the given message with RSA, performs OAEP Encoding. /// </summary> /// <param name="Message">Message to Encrypt. Maximum message length is (ModulusLengthInOctets - 2 * HashLengthInOctets - 2)</param> /// <param name="OAEP_Params">Optional OAEP parameters. Normally Empty. But, must match the parameters while decryption.</param> /// <param name="usePrivate">True to use Private key for encryption. False to use Public key.</param> /// <returns>Encrypted message.</returns> public byte[] Encrypt(byte[] Message, byte[] OAEP_Params, bool usePrivate) { return RSAProcessEncodeOAEP(Message, OAEP_Params, usePrivate); } /// <summary> /// Encrypts the given message with RSA. /// </summary> /// <param name="Message">Message to Encrypt. Maximum message length is For OAEP [ModulusLengthInOctets - (2 * HashLengthInOctets) - 2] and for PKCS [ModulusLengthInOctets - 11]</param> /// <param name="usePrivate">True to use Private key for encryption. False to use Public key.</param> /// <param name="fOAEP">True to use OAEP encoding (Recommended), False to use PKCS v1.5 Padding.</param> /// <returns>Encrypted message.</returns> public byte[] Encrypt(byte[] Message, bool usePrivate, bool fOAEP) { if (fOAEP) { return RSAProcessEncodeOAEP(Message, new byte[0], usePrivate); } else { return RSAProcessEncodePKCS(Message, usePrivate); } } /// <summary> /// Encrypts the given message using RSA Public Key. /// </summary> /// <param name="Message">Message to Encrypt. Maximum message length is For OAEP [ModulusLengthInOctets - (2 * HashLengthInOctets) - 2] and for PKCS [ModulusLengthInOctets - 11]</param> /// <param name="fOAEP">True to use OAEP encoding (Recommended), False to use PKCS v1.5 Padding.</param> /// <returns>Encrypted message.</returns> public byte[] Encrypt(byte[] Message, bool fOAEP) { if (fOAEP) { return RSAProcessEncodeOAEP(Message, new byte[0], false); } else { return RSAProcessEncodePKCS(Message, false); } } /// <summary> /// Decrypts the given RSA encrypted message. /// </summary> /// <param name="Message">The encrypted message.</param> /// <param name="usePrivate">True to use Private key for decryption. False to use Public key.</param> /// <param name="fOAEP">True to use OAEP.</param> /// <returns>Encrypted byte array.</returns> public byte[] Decrypt(byte[] Message, bool usePrivate, bool fOAEP) { return Decrypt(Message, new byte[0], usePrivate, fOAEP); } /// <summary> /// Decrypts the given RSA encrypted message. /// </summary> /// <param name="Message">The encrypted message.</param> /// <param name="OAEP_Params">Parameters to the OAEP algorithm (Must match the parameter while Encryption).</param> /// <param name="usePrivate">True to use Private key for decryption. False to use Public key.</param> /// <returns>Decrypted byte array.</returns> public byte[] Decrypt(byte[] Message, byte[] OAEP_Params, bool usePrivate) { return Decrypt(Message, OAEP_Params, usePrivate, true); } /// <summary> /// Decrypts the given RSA encrypted message using Private key. /// </summary> /// <param name="Message">The encrypted message.</param> /// <param name="fOAEP">True to use OAEP.</param> /// <returns>Decrypted byte array.</returns> public byte[] Decrypt(byte[] Message, bool fOAEP) { return Decrypt(Message, new byte[0], true, fOAEP); } #endregion } }
仅供参考:如何更改.p12或.pfx(带私钥的证书)中的CSP。您需要.pfx中私钥的密码才能执行以下步骤 步骤1:将文件转换为开放格式temp.pem
或 openssl pkcs12-in myCert.pfx-out temp.pem-passin pass:myPassword-passout pass:temppwd 步骤2:创建文件myCert2.pfx,其中包含Windows所需的CSP引用openssl pkcs12 -in myCert.p12 -out temp.pem -passin pass:myPassword -passout pass:temppwd
步骤3:删除temp.pem。不再需要它openssl pkcs12 -export -in temp.pem -out myCert2.pfx -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -passin pass:temppwd -passout pass:myPassword
步骤4:验证是否正确完成del temp.pem
这必须显示openssl pkcs12 -info -nodes -in myCert2.pfx -passin pass:myPassword
Microsoft CSP名称:Microsoft
openssl pkcs12 -in myCert.p12 -out temp.pem -passin pass:myPassword -passout pass:temppwd
openssl pkcs12 -export -in temp.pem -out myCert2.pfx -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -passin pass:temppwd -passout pass:myPassword
del temp.pem
openssl pkcs12 -info -nodes -in myCert2.pfx -passin pass:myPassword