C# 在.NET中使用PEM编码的RSA私钥

C# 在.NET中使用PEM编码的RSA私钥,c#,.net,cryptography,rsa,private-key,C#,.net,Cryptography,Rsa,Private Key,我有一个私钥,如下所示: -----开始RSA私钥------ 一些私钥数据 -----结束RSA PRIVA 我需要在我的C#项目中使用此键,但我找不到任何示例如何使用此格式的键。感谢所有主要的.NET/C#加密库(如BouncyCastle或SecureBackbox[commercial])都应该支持这种格式,以及加载密钥的操作(加密/解密/签名/验证)。尽管是一篇较老的帖子,我还是想在今年早些时候遇到同样的挑战时,我会粘上自己对这个问题的答案。 我编写了一个用于处理PEM密钥、加密、解密

我有一个私钥,如下所示:

-----开始RSA私钥------ 一些私钥数据 -----结束RSA PRIVA


我需要在我的C#项目中使用此键,但我找不到任何示例如何使用此格式的键。感谢

所有主要的.NET/C#加密库(如BouncyCastle或SecureBackbox[commercial])都应该支持这种格式,以及加载密钥的操作(加密/解密/签名/验证)。

尽管是一篇较老的帖子,我还是想在今年早些时候遇到同样的挑战时,我会粘上自己对这个问题的答案。 我编写了一个用于处理PEM密钥、加密、解密、签名和签名验证的库。 它附带了一个完整的示例解决方案(Load Encrypt Decrypt Save),因此您应该能够立即启动运行

干杯, 克里斯托弗

  • 步骤1获取“一些私钥数据”内容。删除------开始RSA私钥------和------结束RSA私钥------删除所有行符号(“\n”)
  • 第二步。解析RSA的密钥
  • private RSACryptoServiceProvider CreateSProviderFromPrivateKey(字符串privateKey)
    {
    var privateKeyBits=System.Convert.FromBase64String(privateKey);
    var RSA=new RSACryptoServiceProvider();
    var rsaparms=新的rsaparmeters();
    使用(BinaryReader binr=new BinaryReader(new MemoryStream(privateKeyBits)))
    {
    字节bt=0;
    ushort-twobytes=0;
    twobytes=binr.ReadUInt16();
    如果(两个字节==0x8130)
    binr.ReadByte();
    else if(两个字节==0x8230)
    binr.ReadInt16();
    其他的
    抛出新异常(“意外值read binr.ReadUInt16()”;
    twobytes=binr.ReadUInt16();
    如果(两个字节!=0x0102)
    抛出新异常(“意外版本”);
    bt=binr.ReadByte();
    如果(bt!=0x00)
    抛出新异常(“意外值read binr.ReadByte()”;
    rsaparms.module=binr.ReadBytes(getintegerize(binr));
    rsaparms.Exponent=binr.ReadBytes(getintegerize(binr));
    rsaparms.D=binr.ReadBytes(getintegerize(binr));
    rsaparms.P=binr.ReadBytes(getintegerize(binr));
    rsaparms.Q=binr.ReadBytes(getintegerize(binr));
    rsaparms.DP=binr.ReadBytes(getintegerize(binr));
    rsaparms.DQ=binr.ReadBytes(getintegerize(binr));
    rsaparms.InverseQ=binr.ReadBytes(getintegerize(binr));
    }
    RSA.输入参数(rsaparms);
    返回RSA;
    }
    私有整数GetIntegerSize(BinaryReader binr)
    {
    字节bt=0;
    字节lowbyte=0x00;
    字节高字节=0x00;
    整数计数=0;
    bt=binr.ReadByte();
    如果(bt!=0x02)
    返回0;
    bt=binr.ReadByte();
    如果(bt==0x81)
    count=binr.ReadByte();
    其他的
    如果(bt==0x82)
    {
    highbyte=binr.ReadByte();
    lowbyte=binr.ReadByte();
    byte[]modint={lowbyte,highbyte,0x00,0x00};
    count=位转换器.ToInt32(modint,0);
    }
    其他的
    {
    计数=bt;
    }
    while(binr.ReadByte()==0x00)
    {
    计数-=1;
    }
    binr.BaseStream.Seek(-1,SeekOrigin.Current);
    返回计数;
    }
    
    下面我写的关于数字签名的文章给出了一个c#的解决方案(不需要额外的库)。代码显示了如何将PEM格式的RSA私钥转换为.NET RSACryptoServiceProvider类使用的XML格式

    使用Atlando Crypto Currency Geo Service,注册后您的身份将存储在浏览器中。在每次请求时,我们都会使用您的私钥通过此身份签署并加密与我们的合同。本文解释了它的工作原理

    下面的代码通过比较原始版本和签名版本,在C#(RSACryptServiceProvider类)中实现了身份验证过程。模数来自PEM格式的RSA公钥(指数AQAB)

    私有静态bool验证(字符串原始、字符串签名、字符串模数)
    {
    SHA256Managed sha=新的SHA256Managed();
    byte[]bytes=Encoding.UTF8.GetBytes(原始);
    byte[]hash=sha.ComputeHash(字节);
    sha.Clear();
    byte[]signed=新字节[signature.Length/2];
    对于(int i=0;i  private static bool Verify(string original, string signature, string modulus)
      {
        SHA256Managed sha = new SHA256Managed();
    
        byte[] bytes = Encoding.UTF8.GetBytes(original);
        byte[] hash = sha.ComputeHash(bytes);
    
        sha.Clear();
    
        byte[] signed = new byte[signature.Length/2];
    
        for (int i = 0; i < signature.Length; i += 2)
        {
          signed[i/2] = Convert.ToByte(Convert.ToInt32(signature.Substring(i, 2), 16));
        }
    
        string key = "<RSAKeyValue><Modulus>" + modulus + "</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
    
        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        {
          rsa.FromXmlString(key);
    
          RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(rsa);
    
          RSADeformatter.SetHashAlgorithm("SHA256");
    
          return RSADeformatter.VerifySignature(hash, signed);
        }
      }
    
    
      public static string Modulus(string pem)
      {
        byte[] x509der = Convert.FromBase64String(pem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", ""));
    
        byte[] seqOID = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
    
        MemoryStream ms = new MemoryStream(x509der);
        BinaryReader reader = new BinaryReader(ms);
    
        if (reader.ReadByte() == 0x30) ReadASNLength(reader); //skip the size
        else return null;
    
        int identifierSize = 0; //total length of Object Identifier section
    
        if (reader.ReadByte() == 0x30) identifierSize = ReadASNLength(reader);
        else return null;
    
        if (reader.ReadByte() == 0x06) //is the next element an object identifier?
        {
          int oidLength = ReadASNLength(reader);
          byte[] oidBytes = new byte[oidLength];
          reader.Read(oidBytes, 0, oidBytes.Length);
    
          if (oidBytes.SequenceEqual(seqOID) == false) return null; //is the object identifier rsaEncryption PKCS#1?
    
          int remainingBytes = identifierSize - 2 - oidBytes.Length;
          reader.ReadBytes(remainingBytes);
        }
    
        if (reader.ReadByte() == 0x03) //is the next element a bit string?
        {
          ReadASNLength(reader); //skip the size
          reader.ReadByte(); //skip unused bits indicator
          if (reader.ReadByte() == 0x30)
          {
            ReadASNLength(reader); //skip the size
            if (reader.ReadByte() == 0x02) //is it an integer?
            {
              int modulusSize = ReadASNLength(reader);
              byte[] modulus = new byte[modulusSize];
              reader.Read(modulus, 0, modulus.Length);
              if (modulus[0] == 0x00) //strip off the first byte if it's 0
              {
                byte[] tempModulus = new byte[modulus.Length - 1];
                Array.Copy(modulus, 1, tempModulus, 0, modulus.Length - 1);
                modulus = tempModulus;
              }
    
              if (reader.ReadByte() == 0x02) //is it an integer?
              {
                int exponentSize = ReadASNLength(reader);
                byte[] exponent = new byte[exponentSize];
                reader.Read(exponent, 0, exponent.Length);
    
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                RSAParameters RSAKeyInfo = new RSAParameters();
                RSAKeyInfo.Modulus = modulus;
                RSAKeyInfo.Exponent = exponent;
                rsa.ImportParameters(RSAKeyInfo);
                return rsa.ToXmlString(false).Replace("<RSAKeyValue><Modulus>", "").Replace("</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>", "");
              }
            }
          }
        }
    
        return null;
      }
    
    
      public static int ReadASNLength(BinaryReader reader)
      {//Note: this method only reads lengths up to 4 bytes long as this is satisfactory for the majority of situations.
        int length = reader.ReadByte();
        if ((length & 0x00000080) == 0x00000080) //is the length greater than 1 byte
        {
          int count = length & 0x0000000f;
          byte[] lengthBytes = new byte[4];
          reader.Read(lengthBytes, 4 - count, count);
          Array.Reverse(lengthBytes); //
          length = BitConverter.ToInt32(lengthBytes, 0);
        }
        return length;
      }
    
        public string GenerateJWTToken(string rsaPrivateKey)
        {
            var rsaParams = GetRsaParameters(rsaPrivateKey);
            var encoder = GetRS256JWTEncoder(rsaParams);
    
            // create the payload according to your need
            var payload = new Dictionary<string, object>
            {
                { "iss", ""},
                { "sub", "" },
                // and other key-values 
            };
    
            var token = encoder.Encode(payload, new byte[0]);
    
            return token;
        }
    
        private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
        {
            var csp = new RSACryptoServiceProvider();
            csp.ImportParameters(rsaParams);
    
            var algorithm = new RS256Algorithm(csp, csp);
            var serializer = new JsonNetSerializer();
            var urlEncoder = new JwtBase64UrlEncoder();
            var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
    
            return encoder;
        }
    
        private static RSAParameters GetRsaParameters(string rsaPrivateKey)
        {
            var byteArray = Encoding.ASCII.GetBytes(rsaPrivateKey);
            using (var ms = new MemoryStream(byteArray))
            {
                using (var sr = new StreamReader(ms))
                {
                    // use Bouncy Castle to convert the private key to RSA parameters
                    var pemReader = new PemReader(sr);
                    var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
                    return DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
                }
            }
        }