请注意:以下代码用于导出 私钥 。如果您要导出 公共
密钥,请参考我在此处给出的答案。
PEM格式只是转换为base64
的密钥(按PKCS#1)的ASN.1
DER编码。鉴于表示密钥所需的字段数量有限,创建快捷的DER编码器以输出适当的格式然后进行base64编码非常简单。因此,下面的代码并不是特别优雅,但是可以做到:
private static void ExportPrivateKey(RSACryptoServiceProvider csp, TextWriter outputStream){ if (csp.PublicOnly) throw new ArgumentException("CSP does not contain a private key", "csp"); var parameters = csp.ExportParameters(true); using (var stream = new MemoryStream()) { var writer = new BinaryWriter(stream); writer.Write((byte)0x30); // SEQUENCE using (var innerStream = new MemoryStream()) { var innerWriter = new BinaryWriter(innerStream); EnpreIntegerBigEndian(innerWriter, new byte[] { 0x00 }); // Version EnpreIntegerBigEndian(innerWriter, parameters.Modulus); EnpreIntegerBigEndian(innerWriter, parameters.Exponent); EnpreIntegerBigEndian(innerWriter, parameters.D); EnpreIntegerBigEndian(innerWriter, parameters.P); EnpreIntegerBigEndian(innerWriter, parameters.Q); EnpreIntegerBigEndian(innerWriter, parameters.DP); EnpreIntegerBigEndian(innerWriter, parameters.DQ); EnpreIntegerBigEndian(innerWriter, parameters.InverseQ); var length = (int)innerStream.Length; EnpreLength(writer, length); writer.Write(innerStream.GetBuffer(), 0, length); } var base64 = Convert.Tobase64String(stream.GetBuffer(), 0, (int)stream.Length).ToCharArray(); outputStream.WriteLine("-----BEGIN RSA PRIVATE KEY-----"); // Output as base64 with lines chopped at 64 characters for (var i = 0; i < base64.Length; i += 64) { outputStream.WriteLine(base64, i, Math.Min(64, base64.Length - i)); } outputStream.WriteLine("-----END RSA PRIVATE KEY-----"); }}private static void EnpreLength(BinaryWriter stream, int length){ if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be non-negative"); if (length < 0x80) { // Short form stream.Write((byte)length); } else { // Long form var temp = length; var bytesRequired = 0; while (temp > 0) { temp >>= 8; bytesRequired++; } stream.Write((byte)(bytesRequired | 0x80)); for (var i = bytesRequired - 1; i >= 0; i--) { stream.Write((byte)(length >> (8 * i) & 0xff)); } }}private static void EnpreIntegerBigEndian(BinaryWriter stream, byte[] value, bool forceUnsigned = true){ stream.Write((byte)0x02); // INTEGER var prefixZeros = 0; for (var i = 0; i < value.Length; i++) { if (value[i] != 0) break; prefixZeros++; } if (value.Length - prefixZeros == 0) { EnpreLength(stream, 1); stream.Write((byte)0); } else { if (forceUnsigned && value[prefixZeros] > 0x7f) { // Add a prefix zero to force unsigned if the MSB is 1 EnpreLength(stream, value.Length - prefixZeros + 1); stream.Write((byte)0); } else { EnpreLength(stream, value.Length - prefixZeros); } for (var i = prefixZeros; i < value.Length; i++) { stream.Write(value[i]); } }}


