public static RSACryptoServiceProvider ParseRSAPublicKey(Asn1Sequence RSAPublicKey)
        {
            Byte[][] RSAPublicKeyData;

              RSAParameters RSAParams = new RSAParameters();

              if (RSAPublicKey.SequenceLength != 2)
              {
            throw new ArgumentException("ASN.1 Sequence has wrong number of elements for RSAPublicKey.");
              }

              RSAPublicKeyData = new Byte[RSAPublicKey.SequenceLength][];

              for(int i=0; i<RSAPublicKey.SequenceLength; i++)
              {
            RSAPublicKeyData[i] = RSAPublicKey[i].ContentsToArray();

            // Trim leading zeros if any
            if ( (RSAPublicKeyData[i][0] == 0x00) && (RSAPublicKeyData[i].Length > 1) )
            {
              Byte[] temp = new Byte[RSAPublicKeyData[i].Length - 1];
              Array.Copy(RSAPublicKeyData[i],1,temp,0,RSAPublicKeyData[i].Length - 1);
              RSAPublicKeyData[i] = temp;
            }
              }

              RSAParams.Modulus     = RSAPublicKeyData[0];
              RSAParams.Exponent    = RSAPublicKeyData[1];

              // Import the params into the RSA CSP
              try
              {
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.ImportParameters(RSAParams);
            return RSA;
              }
              catch
              {
            return null;
              }
        }
        private static RSACryptoServiceProvider LoadPEMKey(String fileName)
        {
            StreamReader sr = File.OpenText(fileName);
              String fileStr = sr.ReadToEnd().Trim();
              sr.Close();

              if( fileStr.StartsWith(PEMStartString+PEMPubString) && fileStr.EndsWith(PEMEndString+PEMPubString) )
              {
            // Unencrypted Private Key PEM file
            byte[] keyBlob = null;

            Console.WriteLine("Reading PEM public key from file {0}...", fileName);
            fileStr = TrimPEMData(fileStr);
            try
            {
              // Get binary data from Base64 string
              keyBlob = Convert.FromBase64String (fileStr);

              // Convert binary data to ASN.1 Sequence object and then parse the sequence
              // into RSAPrivateKey Components, then use to create an RSA CSP object.
              Asn1Sequence seq = new Asn1Sequence(keyBlob);

              if (seq.SequenceLength == 2)
              {
            if ( (seq[0].ContentID.TagNumber == Asn1TagNumber.INTEGER) &&
                 (seq[1].ContentID.TagNumber == Asn1TagNumber.INTEGER) )
            {
              return ParseRSAPublicKey(seq);
            }
            else if ( (seq[0].ContentID.TagNumber == Asn1TagNumber.SEQUENCE) &&
                      (seq[1].ContentID.TagNumber == Asn1TagNumber.BITSTRING) )
            {
              Byte[] tempData = seq[1].ContentsToArray();

              // Trim leading zeros in BitString
              if ( (tempData[0] == 0x00) && (tempData.Length > 1) )
              {
                Byte[] tempData2 = new Byte[tempData.Length - 1];
                Array.Copy(tempData,1,tempData2,0,tempData.Length - 1);
                tempData = tempData2;
              }

              // Now see if we can interpret the BITSTRING data as an ASN.1 Sequence
              seq = new Asn1Sequence(tempData);

              if ( (seq.SequenceLength == 2)  &&
                   (seq[0].ContentID.TagNumber == Asn1TagNumber.INTEGER) &&
                   (seq[1].ContentID.TagNumber == Asn1TagNumber.INTEGER) )
              {
                return ParseRSAPublicKey(seq);
              }
              else
              {
                return null;
              }
            }
            else
            {
              return null;
            }
              }
              else
              {
            return null;
              }
            }
            catch(FormatException )
            {
              Console.WriteLine("Error in the PEM data!");
              return null;
            }
              }
              else if( fileStr.StartsWith(PEMStartString+PEMPrivString) && fileStr.EndsWith(PEMEndString+PEMPrivString) )
              {
            // Unencrypted Private Key PEM file
            byte[] keyBlob = null;

            Console.WriteLine("Reading PEM private key from file {0}...", fileName);
            fileStr = TrimPEMData(fileStr);
            try
            {
              // Get binary data from Base64 string
              keyBlob = Convert.FromBase64String (fileStr);

              // Convert binary data to ASN.1 Sequence object and then parse the sequence
              // into RSAPrivateKey Components, then use to create an RSA CSP object.
              return ParseRSAPrivateKey(new Asn1Sequence(keyBlob));
            }
            catch(FormatException )
            {
              Console.WriteLine("Error in the PEM data!");
              return null;
            }
              }
              else if( fileStr.StartsWith(PEMStartString+PEMPKCS8PrivString) && fileStr.EndsWith(PEMEndString+PEMPKCS8PrivString) )
              {
            // Unencrypted PKCS#8 Private Key PEM file
            Console.WriteLine("Reading PKCS#8 PEM private key from file {0}...", fileName);
            return null;
              }
              else if( fileStr.StartsWith(PEMStartString+PEMPKCS8EncPrivString) && fileStr.EndsWith(PEMEndString+PEMPKCS8EncPrivString) )
              {
            // Encrypted PKCS#8 Private Key PEM file
            Console.WriteLine("Reading Encrypted PKCS#8 PEM private key from file {0}...", fileName);
            return null;
              }
              else
            return null;
        }
        /* ASN.1 definitions from PKCS#1 v2.1
          RSAPublicKey ::= SEQUENCE {
          modulus           INTEGER,  -- n
          publicExponent    INTEGER   -- e
          }

          --
          -- Representation of RSA private key with information for the CRT algorithm.
          --
          RSAPrivateKey ::= SEQUENCE {
          version           Version,
          modulus           INTEGER,  -- n
          publicExponent    INTEGER,  -- e
          privateExponent   INTEGER,  -- d
          prime1            INTEGER,  -- p
          prime2            INTEGER,  -- q
          exponent1         INTEGER,  -- d mod (p-1)
          exponent2         INTEGER,  -- d mod (q-1)
          coefficient       INTEGER,  -- (inverse of q) mod p
          otherPrimeInfos   OtherPrimeInfos OPTIONAL
          }

          Version ::= INTEGER { two-prime(0), multi(1) }
          (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})

          OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo

          OtherPrimeInfo ::= SEQUENCE {
          prime             INTEGER,  -- ri
          exponent          INTEGER,  -- di
          coefficient       INTEGER   -- ti
          }
        */
        public static RSACryptoServiceProvider ParseRSAPrivateKey(Asn1Sequence RSAPrivateKey)
        {
            Byte[][] RSAPrivateKeyData;

              RSAParameters RSAParams = new RSAParameters();

              if ( (RSAPrivateKey.SequenceLength != 9) && (RSAPrivateKey.SequenceLength != 10) )
            throw new ArgumentException("ASN.1 Sequence has wrong number of elements for RSAPrivateKey.");

              RSAPrivateKeyData = new Byte[RSAPrivateKey.SequenceLength][];

              for(int i=0; i<RSAPrivateKey.SequenceLength; i++)
              {
            RSAPrivateKeyData[i] = RSAPrivateKey[i].ContentsToArray();

            // Trim leading zeros if any
            if ( (RSAPrivateKeyData[i][0] == 0x00) && (RSAPrivateKeyData[i].Length > 1) )
            {
              Byte[] temp = new Byte[RSAPrivateKeyData[i].Length - 1];
              Array.Copy(RSAPrivateKeyData[i],1,temp,0,RSAPrivateKeyData[i].Length - 1);
              RSAPrivateKeyData[i] = temp;
            }
              }

              // Verify version is v2.1
              //Console.WriteLine(RSAPrivateKeyData[0][0]);
              //Console.WriteLine(RSAPrivateKeyData[0][1]);
              //if( (RSAPrivateKeyData[0][0] != 0x02) || (RSAPrivateKeyData[0][1] != 0x01) )
              //  throw new ArgumentException("ASN.1 RSAPrivateKey Sequence has wrong version number.");

              // rsaData[0] is version field
              RSAParams.Modulus     = RSAPrivateKeyData[1];
              RSAParams.Exponent    = RSAPrivateKeyData[2];
              RSAParams.D           = RSAPrivateKeyData[3];
              RSAParams.P           = RSAPrivateKeyData[4];
              RSAParams.Q           = RSAPrivateKeyData[5];
              RSAParams.DP          = RSAPrivateKeyData[6];
              RSAParams.DQ          = RSAPrivateKeyData[7];
              RSAParams.InverseQ    = RSAPrivateKeyData[8];

              // Import the params into the RSA CSP
              try
              {
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.ImportParameters(RSAParams);
            return RSA;
              }
              catch
              {
            return null;
              }
        }