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; } }